Search
Loading...
Skip to content

Integrate IMG.LY Premium Assets

Host IMG.LY premium templates on your infrastructure and integrate them directly into CE.SDK’s asset library.

IMG.LY Premium Assets integration

10 mins
estimated time
Download
StackBlitz
GitHub

IMG.LY offers premium templates through downloadable asset archives. These templates can be hosted on your own infrastructure and seamlessly integrated into CE.SDK’s asset library, making them available to users alongside other asset sources. Contact IMG.LY sales to purchase premium template packages.

This guide covers environment setup, fetching and parsing the content manifest, creating local asset sources with archive loading support, replacing URL placeholders, configuring category labels, and displaying templates as a prominent dock entry in the asset library.

Prerequisites#

Before integrating premium assets, ensure you have:

  • IMG.LY premium asset archive (contact sales to purchase)
  • Self-hosted server or CDN for asset files
  • Working CE.SDK instance
  • Understanding of URL structure and path resolution
  • Environment variable support (Vite, webpack, or equivalent bundler)

The premium asset package contains a structured archive with template metadata, thumbnails, and design files ready for hosting.

Premium Asset Package Structure#

The archive contains a content.json manifest and template directories. Each template directory includes three essential files: asset.json containing metadata, thumbnail.jpg for preview images, and design.zip with the complete template and assets.

{
"version": "1.0",
"id": "imgly-premium-templates",
"assets": [
{
"id": "social-media-story-1",
"label": { "en": "Modern Social Media Story" },
"meta": {
"uri": "{{base_url}}/social-media-story-1/design.zip",
"thumbUri": "{{base_url}}/social-media-story-1/thumbnail.jpg"
},
"payload": {
"sourceSet": [
{ "uri": "{{base_url}}/social-media-story-1/thumbnail.jpg" }
]
}
}
]
}

The {{base_url}} placeholders allow flexible hosting by replacing them with your actual server URL at runtime.

Hosting Premium Assets#

Upload extracted asset folders to your server with all three files accessible via URL. CE.SDK combines the base URL with template paths to fetch resources.

Environment Configuration#

Configure the base URL using environment variables to keep your hosting location secure and easily configurable across environments.

Create a .env file in your project root:

Terminal window
VITE_PREMIUM_TEMPLATES_BASE_URL=https://your-cdn.example.com/premium-templates

For reference and team setup, create a .env.example file:

Terminal window
VITE_PREMIUM_TEMPLATES_BASE_URL=https://your-cdn.example.com/premium-templates
# CE.SDK License Key (Optional)
# VITE_CESDK_LICENSE=YOUR_LICENSE_KEY_HERE

Add .env to your .gitignore to prevent exposing sensitive URLs:

Terminal window
# Environment files
.env
.env.local
.env.*.local

Loading Configuration#

Load the base URL from environment variables with validation:

// Configure the base URL where premium assets are hosted
// This points to IMG.LY's premium templates CDN
const baseURL = import.meta.env.VITE_CESDK_PREMIUM_TEMPLATES_URL;
if (!baseURL) {
throw new Error(
'VITE_CESDK_PREMIUM_TEMPLATES_URL environment variable is required'
);
}

The base URL points to the root directory where template folders are hosted. This URL can be a CDN, your own server, or any accessible HTTP location. Using environment variables keeps your hosting location confidential and allows different configurations for development, staging, and production environments.

Configuring Asset Sources#

We configure CE.SDK to load premium templates by fetching the content.json manifest and creating a local asset source.

Fetching the Manifest#

First, we fetch and parse the content.json file that lists all available templates.

// Fetch the content.json manifest file
// This file lists all available templates and their metadata
const contentJSONUrl = `${baseURL}/dist/templates/content.json`;
const response = await fetch(contentJSONUrl);
if (!response.ok) {
throw new Error(`Failed to fetch content.json: ${response.statusText}`);
}
const content: ContentJSON = await response.json();

The manifest contains the source ID and an array of asset definitions with metadata for each template.

Extracting Source Data#

We extract the source ID and assets array from the parsed manifest.

// Extract the source ID and assets array from the manifest
const { assets, id: sourceId } = content;

The source ID determines which asset library panel displays the templates. The assets array contains all template definitions.

Creating a Local Source#

We create a local asset source with a custom apply handler for loading template archives.

// Create a local asset source for the premium templates with custom apply handler
// Templates are archive files that need special loading
engine.asset.addLocalSource(sourceId, [], async (asset) => {
// Load the template from the archive URL
await engine.scene.loadFromArchiveURL(asset.meta.uri);
// Return the scene ID after loading
return engine.scene.get()!;
});

Premium templates are distributed as .zip archives, so we provide a custom applyAsset callback that uses loadFromArchiveURL() instead of the standard asset application logic. This callback:

  1. Loads the template archive from the asset’s URI
  2. Replaces the current scene with the template content
  3. Returns the scene ID for tracking

Local sources are ideal for finite asset collections that don’t require custom query logic. The engine manages search and pagination automatically.

Processing and Adding Assets#

We process each asset to replace {{base_url}} placeholders with the actual hosting URL, then add them to the source.

// Process each asset and add it to the source
assets.forEach((asset) => {
// Replace {{base_url}} placeholders in asset metadata
// Note: We append '/dist' to match the CDN structure
const replacementURL = `${baseURL}/dist`;
if (asset.meta) {
Object.entries(asset.meta).forEach(([key, value]: [any, any]) => {
const stringValue: string = value.toString();
if (stringValue.includes('{{base_url}}')) {
const updated = stringValue.replace('{{base_url}}', replacementURL);
if (asset.meta) {
asset.meta[key] = updated;
}
}
});
}
// Replace {{base_url}} in payload sourceSet for responsive images
// cSpell:ignore sourceset
if (asset.payload?.sourceSet) {
asset.payload.sourceSet.forEach((sourceSet) => {
sourceSet.uri = sourceSet.uri.replace('{{base_url}}', replacementURL);
});
}
// Add the processed asset to the local source
engine.asset.addAssetToSource(sourceId, asset);
});

For each asset, we replace placeholders in two locations: the meta object and the payload.sourceSet array.

Replacing Meta Placeholders#

We iterate through the meta object to replace any {{base_url}} placeholders.

// Replace {{base_url}} placeholders in asset metadata
// Note: We append '/dist' to match the CDN structure
const replacementURL = `${baseURL}/dist`;
if (asset.meta) {
Object.entries(asset.meta).forEach(([key, value]: [any, any]) => {
const stringValue: string = value.toString();
if (stringValue.includes('{{base_url}}')) {
const updated = stringValue.replace('{{base_url}}', replacementURL);
if (asset.meta) {
asset.meta[key] = updated;
}
}
});
}

This ensures the template URI and thumbnail URI point to the correct server location.

Replacing SourceSet Placeholders#

We also replace placeholders in the payload.sourceSet array for responsive image variants.

// Replace {{base_url}} in payload sourceSet for responsive images
// cSpell:ignore sourceset
if (asset.payload?.sourceSet) {
asset.payload.sourceSet.forEach((sourceSet) => {
sourceSet.uri = sourceSet.uri.replace('{{base_url}}', replacementURL);
});
}

The source set array contains multiple image sizes for optimal loading performance.

Adding to Source#

After processing, we add the asset to the local source.

// Add the processed asset to the local source
engine.asset.addAssetToSource(sourceId, asset);

The engine stores the asset and makes it available for search queries and display.

Displaying Templates in Asset Library#

Templates automatically appear in the asset library after being added to the source. To make them easily accessible, we configure category labels and a dedicated dock entry.

Configuring Category Labels#

Premium templates are organized into categories. We configure i18n translations for user-friendly category labels:

// Set translations for category labels
cesdk.i18n.setTranslations({
en: {
'libraries.ly.img.template.premium.ly.img.template.premium1.label':
'Templates',
'libraries.ly.img.template.premium.ly.img.template.premium1.e-commerce.label':
'E-Commerce',
'libraries.ly.img.template.premium.ly.img.template.premium1.event.label':
'Event',
'libraries.ly.img.template.premium.ly.img.template.premium1.personal.label':
'Personal',
'libraries.ly.img.template.premium.ly.img.template.premium1.professional.label':
'Professional',
'libraries.ly.img.template.premium.ly.img.template.premium1.socials.label':
'Socials'
}
});

These translations map the internal category identifiers from content.json (like e-commerce, event, personal) to readable labels that appear in the asset library interface. The translation keys follow the pattern: libraries.{sourceId}.{categoryId}.label.

Configuring the Dock Entry#

We add a custom dock entry as the first button in the asset library dock, followed by a separator for visual grouping.

// Configure the asset library dock entry for premium templates
cesdk.ui.addAssetLibraryEntry({
id: 'ly.img.template.premium',
sourceIds: [sourceId],
previewLength: 3,
gridColumns: 3,
gridItemHeight: 'auto'
});
// Add premium templates as the first button in the dock with a separator
cesdk.ui.setDockOrder([
{
id: 'ly.img.assetLibrary.dock',
key: 'premium-templates',
label: 'Premium Templates',
entries: ['ly.img.template.premium']
},
{ id: 'ly.img.separator' },
...cesdk.ui.getDockOrder()
]);

This configuration:

  • Places “Premium Templates” as the first dock button
  • Adds a visual separator after it
  • Preserves all existing dock entries using the spread operator
  • Shows 3 preview templates in a 3-column grid
  • Uses the default template icon instead of custom emoji

The sourceIds array specifies which asset source to display (matching the source ID from content.json). The entries array contains the asset library entry IDs to display in this dock panel.

Testing the Integration#

Verify templates appear in the asset library and load correctly with all assets. Query the asset source programmatically to check availability:

const result = await engine.asset.findAssets('imgly-premium-templates', {
page: 0,
perPage: 10,
});
console.log(`Found ${result.total} templates`);

Applying Templates Programmatically#

To demonstrate the integration working immediately upon load, apply a template programmatically after the asset source is configured:

// Query and apply the second template to demonstrate the integration
const result = await engine.asset.findAssets(sourceId, {
page: 0,
perPage: 2
});
if (result.assets.length > 1) {
// Apply the second template - this triggers the custom applyAsset callback
await engine.asset.apply(sourceId, result.assets[1]);
}

This queries the asset source for templates and applies the second one (index 1) to the canvas. This provides immediate visual feedback that the integration is working correctly. Users can then click other templates in the asset library to explore the full collection.

Optimization#

Implement CDN caching for design.zip files and thumbnails to improve load times. Configure appropriate cache headers on your server to reduce bandwidth and latency.

For authenticated access, implement server access controls to restrict premium content to authorized users only. Use signed URLs or token-based authentication to protect template files.

Environment variables provide additional security benefits by keeping hosting locations out of source control. Configure different base URLs for development, staging, and production environments without code changes. This allows you to test with staging assets locally while production uses the actual CDN.

Troubleshooting#

Environment variable not defined: If you see “VITE_PREMIUM_TEMPLATES_BASE_URL environment variable is required”, ensure your .env file exists and contains the base URL. Restart your development server after creating or modifying the .env file.

Base URL configuration errors: Verify the base URL matches your hosting location exactly, including protocol (http/https) and trailing slashes. Check that the environment variable is loaded correctly using console.log(import.meta.env.VITE_PREMIUM_TEMPLATES_BASE_URL).

Templates not applying or showing serialization errors: Premium templates are .zip archives that require a custom applyAsset callback using loadFromArchiveURL(). Verify your asset source creation includes this callback instead of relying on default asset application behavior.

Missing or incorrect file paths (404 errors): Check that template folders and files are uploaded correctly and accessible at the expected URLs. Verify the /dist path is included if your CDN uses that structure.

CORS issues when loading from different domains: Configure CORS headers on your server to allow CE.SDK to fetch resources from your domain.

Template files not loading or appearing blank: Ensure design.zip files are valid CE.SDK archives and contain all required assets.

Thumbnail images not displaying: Verify thumbnail file paths are correct and images are accessible via HTTP.

Content manifest parsing errors: Validate content.json structure matches the expected format with required fields like id, version, and assets array.

Category labels not appearing: Ensure i18n translations are configured before adding the asset library entry. Translation keys must match the pattern libraries.{sourceId}.{categoryId}.label.

API Reference#

MethodCategoryPurpose
engine.asset.addLocalSource()AssetCreate a local asset source with custom apply callback
engine.asset.addAssetToSource()AssetAdd individual template assets to the source
engine.scene.loadFromArchiveURL()SceneLoad template from .zip archive URL
engine.asset.findAssets()AssetQuery assets from a source for programmatic application
cesdk.i18n.setTranslations()UIConfigure category labels and localized strings
cesdk.ui.addAssetLibraryEntry()UIAdd custom asset library panel configuration
cesdk.ui.setDockOrder()UIConfigure dock button order and custom entries
cesdk.ui.getDockOrder()UIGet current dock configuration for preservation

Next Steps#