Skip to main content

Manage Assets

In this example, we will show you how to use the CreativeEditor SDK's CreativeEngine to manage assets through the asset API.

To begin working with assets first you need at least one asset source. As the name might imply asset sources provide the engine with assets. These assets then show up in the editor's asset library. But they can also be independently searched and used to create design blocks. Asset sources can be added dynamically using the asset API as we will show in this guide.

Explore a full code sample of the integration on CodeSandbox or view the code on GitHub.


This example uses the headless CreativeEngine. See the Setup article for a detailed guide. To get started right away, you can also access the block API within a running CE.SDK instance via cesdk.engine.block. Check out the APIs Overview to see that illustrated in more detail.

Defining a Custom Asset Source#

Asset sources need at least an id and a findAssets function. You may notice asset source functions are all async. This way you can use web requests or other long-running operations inside them and return results asynchronously.

Let's go over these properties one by one:

All functions of the asset API refer to an asset source by its unique id. That's why it has to be mandatory. Trying to add an asset source with an already registered id will fail.

  • findAssets(sourceId: string, query: AssetQueryData): Promise<AssetsQueryResult> should return paginated asset results for the given queryData. The asset results have a set of mandatory and optional properties. For a listing with an explanation for each property please refer to the Integrate a Custom Asset Source guide. The properties of the queryData and the pagination mechanism are also explained in this guide.
  • applyAsset?: (asset: AssetResult) => Promise<void> is an optional function to define the behavior of what to do when an asset gets applied to the scene. You can use the engine's APIs to do whatever you want with the given asset result. In this case, we always create an image block and add it to the first page we find.

If you don't provide this function the engine's default behavior is to create a block based on the asset result's meta.blockType property, add the block to the active page, and sensibly position and size it.

  • applyAssetToBlock?: (asset: AssetResult, block: number) => Promise<void> is an optional function to define the behavior of what to do when an asset gets applied to an existing block. You can use the engine's APIs to do whatever you want with the given asset result. Here we just trigger the default engine behavior.

If you don't provide this function the engine's default behavior is to update the block's source uri based on the asset result's meta.blockType property. For blocks with a corresponding property meta.previewUri is also taken into account.

Registering a New Asset Source#

  • addSource(source: AssetSource): void now allows registering our custom asset source with the engine.
  • findAllSources(): string[] lists all available sources including our newly registered asset source 'foobar'.
  • removeSource(id: string): void allows removing our source. We do this at the very end. But it is not necessary.

Finding and Applying Assets#

  • findAssets(sourceId: string, query: AssetQueryData): Promise<AssetsQueryResult> can be used after registering our custom source to obtain a search result. We want an asset from the first page (indexing starts at 0) and at most 100 asset results for that query.
  • async apply(sourceId: string, assetResult: AssetResult): Promise<void> Finally, we can apply the first asset result from our query result to the scene using apply. The custom applyAsset function of our asset source will run to do this job.
import CreativeEngine from '';
const config = {
baseURL: ''
CreativeEngine.init(config).then(async (engine) => {
const scene = engine.scene.create();
const page = engine.block.create('page');
engine.block.appendChild(scene, page);
const customSource = {
id: 'foobar',
async findAssets(queryData) {
return Promise.resolve({
assets: [
id: 'logo',
meta: {
uri: '',
thumbUri: '',
blockType: '//ly.img.ubq/image',
width: 320,
height: 116
context: {
sourceId: 'foobar'
total: 1,
nextPage: undefined
async applyAsset(assetResult) {
const image = engine.block.create('image');
engine.block.setString(image, 'image/imageFileURI', assetResult.meta.uri);
engine.block.setWidth(image, assetResult.meta.width);
engine.block.setHeight(image, assetResult.meta.height);
const firstPage = engine.block.findByType('page')[0];
engine.block.appendChild(firstPage, image);
engine.block.setWidth(firstPage, assetResult.meta.width);
engine.block.setHeight(firstPage, assetResult.meta.height);
engine.scene.zoomToBlock(firstPage, 0, 0, 0, 0);
async applyAssetToBlock(assetResult, block) {
engine.asset.defaultApplyAssetToBlock(assetResult, block);
const result = await engine.asset.findAssets(, {page: 0, perPage: 100});
const asset = result.assets[0];
await engine.asset.apply(, asset);