CMP DAM in CMS
Integrate Optimizely Digital Asset Management (DAM) with Optimizely Content Management System (CMS) 12 for seamless access to digital assets.
The Optimizely Digital Asset Management (DAM) and Optimizely Content Management System (CMS) 12 integration lets editors select, manage, and render assets from DAM directly within the CMS user interface (UI).
The integration provides the following capabilities:
- Select images, videos, and files from DAM using the library picker UI.
- Retrieve and cache asset metadata (alt text, dimensions, descriptions).
- Track asset usage in published content.
- Render assets with proper metadata using built-in HTML helpers.
- Query assets with Optimizely Graph for improved performance.
ImportantUse the Graph integration for metadata retrieval in production environments. The CMP REST API has rate limiting that can result in
429(too many requests) errors under heavy load. The Graph integration provides better performance and scalability and eliminates rate-limiting issues. See Metadata retrieval methods for details.
Prerequisites
Minimum version requirements
EPiServer.Cms.Core12.22.1 or laterEPiServer.Cms.UI12.32.0 or laterEPiServer.Cms.WelcomeIntegration.UI2.2.0 or later
CMP requirements
- Active Content Marketing Platform (CMP) account with application credentials (Client ID and Client Secret).
- You can only configure one CMP instance per CMS instance.
Image processing requirements
For proper image format support, especially for modern formats like WebP and AVIF:
- Use
EPiServer.ImageLibrary.ImageSharpversion 2.0.5 or later. - Obtain an ImageSharp license (required for version 2.x).
- Upgrade to version 2.x for significantly better support for various image formats.
NoteIf images from DAM appear broken in the CMS content selector or preview, upgrading to ImageSharp 2.x typically resolves the issue.
Before troubleshooting any issues, verify you are running the latest versions of these packages.
Install the NuGet packages
Install the required NuGet packages:
# Required packages
dotnet add package EPiServer.CMS.WelcomeIntegration.UI
dotnet add package EPiServer.Cms.WelcomeIntegration.Core
dotnet add package Optimizely.Cmp.Client
# Recommended for production deployments
dotnet add package EPiServer.Cms.WelcomeIntegration.Graph
NoteInstall the Graph integration package in all production environments to avoid REST API rate limiting and improve performance.
Architecture overview
The integration consists of three main components:
- Library picker UI – Lets editors browse and select DAM assets.
- Metadata retrieval – Pulls asset metadata (alt text, dimensions, and so on) using the CMP REST API or Graph.
- Asset usage tracking – Reports to CMP where assets are used in published content.
Metadata retrieval methods
Use the Graph integration for all production deployments. While the integration supports both retrieval methods, the CMP REST API has performance limitations and rate limiting that make it unsuitable for high-traffic scenarios.
Option 1: CMP REST API (not recommended for production)
- Direct API calls to CMP.
- Subject to rate limiting that can return
429(too many requests) status codes under heavy use. - Slower performance under heavy load.
- Use only for development or low-traffic scenarios.
Option 2: Optimizely Graph (recommended)
- Queries indexed asset data.
- No rate-limiting issues.
- Better performance and scalability.
- Handles high-volume requests without throttling.
- Requires additional configuration. See Enable Graph integration for details.
When metadata is retrieved
Asset metadata syncs on two occasions:
- Content publishing – When publishing CMS content that references CMP assets.
- Scheduled maintenance – Through the Optimizely DAM Maintenance scheduled job.
Configure the integration
-
Enable the library picker UI – Add the following to your
Startup.cs:public void ConfigureServices(IServiceCollection services) { // Enable CMP DAM library picker services.AddDAMUi(options => options.Enabled = true); // ... other service configuration } -
Configure CMP API integration – Create an application in CMP to obtain your Client ID and Client Secret, then configure authentication.
ImportantEnsure you are configuring credentials for the same CMP instance that editors will use. Mixing CMP instances causes metadata sync failures.
- Option 1 – Configure in
Startup.cs.services.AddOptimizelyCmpClient(options => { options.ClientId = "YOUR_CLIENT_ID"; options.ClientSecret = "YOUR_CLIENT_SECRET"; }); - Option 2 – Configure in
appsettings.json(recommended for secrets management).Then in{ "Optimizely": { "Cmp": { "ClientId": "YOUR_CLIENT_ID", "ClientSecret": "YOUR_CLIENT_SECRET" } } }Startup.cs:services.AddOptimizelyCmpClient();
- Option 1 – Configure in
-
Enable Graph integration (recommended) – Configure Graph integration for all production deployments. The CMP REST API implements rate limiting that returns
429(too many requests) status codes under heavy load, which becomes problematic in high-traffic environments or when multiple concurrent requests are made to CMP. Graph integration eliminates these issues, handles high-volume requests without rate limiting, and scales effectively for production workloads.This is additional configuration on top of the CMP API setup in step 2.
First, ensure your Optimizely Graph gateway is configured. See Optimizely Graph documentation for details.
-
Option 1 – Configure in
Startup.cs.services.Configure<CMPGraphOptions>(options => options.SingleKey = "YOUR_CMP_GRAPH_SECRET"); services.AddDAMGraphIntegration(); -
Option 2 – Configure in
appsettings.json.{ "Optimizely": { "CmpGraph": { "SingleKey": "YOUR_CMP_GRAPH_SECRET" } } }Then in
Startup.cs:services.AddDAMGraphIntegration();
NoteGraph integration was introduced in version 1.4.0. Upgrade to this version or later to enable Graph-based metadata retrieval.
-
Advanced configuration (optional)
Customize DAM UI behavior in appsettings.json:
{
"EPiServer": {
"Cms": {
"DAMUi": {
"Enabled": true,
"IconClass": "dijitNoIcon",
"AvailableTypes": "episerver.core.imagedata",
"StoreName": "episervercmsdamcontentcreation",
"Endpoint": "https://cmp.optimizely.com",
"Path": "/cloud/library-picker",
"StartingFolders": {
"Global": "/path/to/default/folder",
"ByAssetType": {
"image": "/images",
"video": "/videos"
}
}
}
}
}
}The following parameters are available:
| Parameter | Description | Default |
|---|---|---|
Enabled | Enables or disables DAM integration | true |
IconClass | CSS class for UI icon | dijitNoIcon |
AvailableTypes | Restricts integration to specific content types | episerver.core.imagedata |
Endpoint | CMP environment URL | https://cmp.optimizely.com |
StartingFolders | Default folders in library picker | None |
Use assets in content
Supported property types
You can use CMP assets in the following property types:
ContentReference(single asset)ContentReferencelist (multiple assets)ContentAreaUrlorUrlToImage(URL-based properties)LinkItem(link properties)
When replacing an existing DAM asset, the library picker opens pre-selected on the current asset, regardless of the underlying property type. This deep linking works for ContentReference-based and URL-based properties.
The following example shows a content type that uses CMP assets:
public class ArticlePage : PageData
{
[Display(Name = "Hero Image")]
public virtual ContentReference HeroImage { get; set; }
[Display(Name = "Gallery")]
public virtual IList<ContentReference> ImageGallery { get; set; }
[Display(Name = "Main Content")]
public virtual ContentArea MainContent { get; set; }
[Display(Name = "Background Image")]
public virtual Url BackgroundImage { get; set; }
}Asset types
CMP provides three asset categories:
- Images – JPG, PNG, WebP, GIF, and so on.
- Videos – MP4, MOV, and so on.
- Raw files – PDFs, Word documents, Excel spreadsheets, PowerPoint presentations, ZIP archives, and so on.
Render assets
The integration provides built-in helpers to render assets with proper metadata. Use these helpers instead of manually constructing URLs.
The rendering helpers reuse cached metadata from the CMS database when available, reducing outbound calls to CMP Graph. This improves performance when rendering multiple assets on a single page.
Option 1: HTML helper (Razor)
The HTML helper provides multiple overloads for flexibility.
The following example shows basic usage with a ContentReference property:
@model PageViewModel<ArticlePage>
@using EPiServer.Cms.WelcomeIntegration.UI.Helpers
@await Html.RenderTagWithMetadata(m => m.CurrentPage.HeroImage)To add HTML attributes to the rendered tag:
@await Html.RenderTagWithMetadata(
m => m.CurrentPage.HeroImage,
new Dictionary<string, string>
{
{ "class", "hero-image" },
{ "loading", "eager" },
{ "fetchpriority", "high" }
}
)To use the asset GUID directly (for example, from custom properties):
@await Html.RenderTagWithMetadata(m => m.CurrentPage.AssetGuid)Option 2: Tag helper (Razor)
The tag helper provides a declarative approach with support for custom attributes.
The following example shows basic usage:
@model PageViewModel<ArticlePage>
@addTagHelper *, EPiServer.Cms.WelcomeIntegration.UI
<dam-asset content-reference="@Model.CurrentPage.HeroImage" />To add custom attributes using the attr- prefix:
<dam-asset
content-reference="@Model.CurrentPage.HeroImage"
attr-class="hero-image responsive"
attr-loading="eager"
attr-fetchpriority="high"
attr-data-analytics="hero-banner" />This renders as:
<img src="..."
class="hero-image responsive"
loading="eager"
fetchpriority="high"
data-analytics="hero-banner"
alt="..."
title="..." />Option 3: URL helper extensions
For more control over rendering, use the URL helper extensions:
@using EPiServer.Cms.WelcomeIntegration.UI.Helpers
<!-- Get asset URL -->
<img src="@Url.DamAssetUrl(Model.CurrentPage.HeroImage)" alt="Hero" />
<!-- Get specific rendition URL -->
<img src="@Url.DamAssetUrl(Model.CurrentPage.HeroImage, "thumbnail")" alt="Thumbnail" />Option 4: ContentArea with view components
When assets are added to a ContentArea, the integration uses view components to render them with full metadata:
@Html.PropertyFor(m => m.CurrentPage.MainContent)The following view components handle rendering:
DAMImageAssetViewComponent– Renders image assets.DAMVideoAssetViewComponent– Renders video assets.
No additional configuration is required; the view components are registered automatically.
Default rendering behavior
Images
Images render with the following default attributes:
loading="lazy"– Defers loading until the image is near the viewport.decoding="async"– Lets the browser decode the image asynchronously.fetchpriority="low"– Indicates the image has lower priority for bandwidth allocation.widthandheight– Set from metadata to prevent layout shift (CLS optimization).alt– Set from CMP metadata.title– Set from CMP metadata.
The following example shows the rendered HTML output:
<img src="https://images2.cmp.optimizely.com/..."
alt="A very cute little ghost"
title="ghost.png"
width="1130"
height="1147"
loading="lazy"
decoding="async"
fetchpriority="low" />Override these defaults using the tag helper's attr- attributes or the HTML helper's dictionary parameter.
Videos
Videos render with an HTML5 <video> element:
<video controls>
<source src="https://images2.cmp.optimizely.com/..." type="video/mp4" />
Your browser does not support HTML5 video.
</video>The integration sets the following video attributes:
- Adds
controlsfor playback controls. - Includes fallback text for browsers without HTML5 video support.
- Sets the appropriate
typeattribute based on MIME type.
Documents and files (raw files)
All document and file types render as download links with target="_blank". This includes any asset with an application/* MIME type (PDF, Office documents, ZIP archives, and so on), text/* MIME type (CSV, plain text, and so on), or any other non-image, non-video MIME type.
The following example shows the rendered HTML output:
<a href="https://images2.cmp.optimizely.com/..."
target="_blank"
title="Annual Report 2025"
alt="Annual Report 2025">Annual Report 2025</a>Work with renditions
CMP assets can have multiple renditions, which are pre-processed versions optimized for different use cases (thumbnails, banners, mobile sizes, and so on).
Renditions
Renditions are alternative versions of an asset created in CMP with different dimensions, quality settings, or formats. Common examples:
- Thumbnail – Small preview (for example, 150x150).
- Banner – Wide format for hero images (for example, 1920x600).
- Mobile – Optimized for mobile devices (for example, 640x480).
Access renditions
To retrieve a rendition URL using the URL helper:
<!-- Use specific rendition -->
<img src="@Url.DamAssetUrl(Model.CurrentPage.Image, "thumbnail")" alt="Thumbnail" />
<!-- Fallback: if "banner" does not exist, returns the default asset URL -->
<img src="@Url.DamAssetUrl(Model.CurrentPage.Image, "banner")" alt="Banner" />Rendition matching follows these rules:
- Case-insensitive, for example, "Thumbnail," "THUMBNAIL," and "thumbnail" all match.
- If the requested rendition does not exist, the default asset URL is returned.
- When a rendition is selected, the returned URL, width, and height reflect the rendition's values, not the original asset's.
- Check application logs for warnings about missing renditions.
Access renditions programmatically
Use IDAMAssetIdentityResolver to query available renditions:
var identity = _resolver.Get(assetRef);
var renditions = identity?.Metadata?.DAMAssetInfo?.Renditions;
if (renditions != null)
{
foreach (var rendition in renditions)
{
// rendition.Name - for example, "thumbnail"
// rendition.Url - Direct URL to the rendition
// rendition.Width - Rendition width in pixels
// rendition.Height - Rendition height in pixels
}
}Troubleshoot renditions
If you request a rendition that does not exist, the following warning displays in application logs:
Rendition 'thumbnail' for asset with ContentReference '2_dam' is not found in DAM metadata, falling back to default asset URL.
The URL helper falls back to the default asset URL, so the page continues to work without errors, and there is no user-facing impact.
To resolve missing rendition warnings:
- Verify the rendition exists in CMP for the specific asset.
- Check the rendition name spelling (case-insensitive but must match exactly).
- Run the Optimizely DAM Maintenance scheduled job to refresh metadata.
- Rerun the job to update stale metadata if you recently added the rendition in CMP.
Access asset metadata programmatically
For custom rendering scenarios, use IDAMAssetIdentityResolver:
using EPiServer.Cms.WelcomeIntegration.Core;
public class CustomImageRenderer
{
private readonly IDAMAssetIdentityResolver _resolver;
public CustomImageRenderer(IDAMAssetIdentityResolver resolver)
{
_resolver = resolver;
}
public string RenderImage(ContentReference assetRef)
{
var identity = _resolver.Get(assetRef);
if (identity?.Metadata?.DAMAssetInfo == null)
return string.Empty;
var info = identity.Metadata.DAMAssetInfo;
return $@"<img
src=""{info.Url}""
alt=""{info.AltText}""
width=""{info.Width}""
height=""{info.Height}""
title=""{info.Title}"" />";
}
}DAMAssetInfo structure
DAMAssetInfo structureThe DAMAssetInfo object contains comprehensive metadata:
{
"Title": "ghost.png",
"Url": "https://images2.cmp.optimizely.com/...",
"Width": "1130",
"Height": "1147",
"Description": "Image description",
"AltText": "A very cute little ghost",
"MimeType": "image/png",
"Renditions": [
{
"Name": "thumbnail",
"Url": "https://images2.cmp.optimizely.com/...",
"Width": "150",
"Height": "150"
},
{
"Name": "banner",
"Url": "https://images2.cmp.optimizely.com/...",
"Width": "1920",
"Height": "600"
}
],
"FocalPoint": {
"X": 500,
"Y": 300
}
}The following properties are available on the DAMAssetInfo object:
| Property | Type | Description |
|---|---|---|
Title | string? | Asset title from CMP |
Url | string | Direct URL to the asset (may be SEO-friendly) |
Width | string? | Image width in pixels |
Height | string? | Image height in pixels |
Description | string? | Asset description from CMP |
AltText | string? | Alternative text for accessibility |
MimeType | string? | MIME type (for example, "image/png", "video/mp4") |
Renditions | IEnumerable<DamAssetRendition>? | Available renditions |
FocalPoint | DamAssetFocalPoint? | Smart crop focal point (X, Y coordinates) |
Focal point
The FocalPoint property indicates the point of interest in an image, which is useful for smart cropping:
var identity = _resolver.Get(assetRef);
var focalPoint = identity?.Metadata?.DAMAssetInfo?.FocalPoint;
if (focalPoint != null)
{
var x = focalPoint.X; // X coordinate (pixels from left)
var y = focalPoint.Y; // Y coordinate (pixels from top)
// Use focal point for custom cropping or positioning
}Use the focal point for the following scenarios:
- Responsive image cropping that preserves the main subject.
- CSS
object-positioncalculations. - Custom image processing pipelines.
Metadata limitations
CMS 12 supports the following metadata from CMP:
- Title
- Alt text
- Description
- Dimensions (Width, Height)
- URL (including SEO-friendly URLs)
- Renditions
- Focal point
The following CMP metadata fields are not available in CMS 12:
- Fields – Custom metadata fields defined in CMP.
- Tags – Asset tagging and categorization.
- Custom properties – Any CMP-specific custom properties.
Workarounds for extended metadata
If you need access to fields, tags, or other advanced CMP metadata, use one of the following approaches:
- Query CMP Graph directly –
// Use Optimizely Graph to query CMP data directly var query = @"query { Asset(where: { _metadata: { key: { eq: ""YOUR_ASSET_ID"" } } }) { fields tags } }"; - Retrieve with the CMP REST API – Use the CMP client to fetch full asset metadata and store relevant extended metadata in CMS content properties.
- Duplicate in CMS – Store critical metadata fields directly on your CMS content types and maintain sync manually or with custom scheduled jobs.
Scheduled jobs
The integration provides two scheduled jobs that run automatically:
- Optimizely DAM maintenance job
- Optimizely DAM asset tracking job
Optimizely DAM maintenance job
- Purpose – Syncs asset metadata from CMP to CMS.
- Schedule – Configurable (default: daily).
The job performs the following actions:
- Updates alt text, dimensions, and other metadata for all referenced assets.
- Syncs SEO-friendly URLs if enabled in CMP.
- Processes assets that failed during previous runs.
Troubleshoot the DAM maintenance job
- Missing or outdated alt text – If assets render without alt text or with outdated metadata:
- Verify content is published – Metadata only updates on publish, not on save.
- Run the job manually – Go to Admin > Scheduled Jobs and run Optimizely DAM Maintenance.
- Check application logs – Check application logs for errors during job execution.
- Verify the rendering method – Ensure you are using
@Html.RenderTagWithMetadataor<dam-asset>instead of manually constructing URLs withIUrlResolver.
- SEO URLs not updating – If CMP has SEO-friendly URLs enabled, but CMS still uses hashed URLs:
- Run the Optimizely DAM Maintenance job manually.
- Verify the Graph integration is configured correctly (if using).
- Check logs for sync errors.
- Ensure the scheduled job completed successfully.
- Partial job failures – If the job completes with partial success (for example, 999 of 1000 items processed):
- Check application logs – Check application logs during the job execution timeframe.
- Look for handled exceptions – Some errors are logged but do not fail the entire job.
- Verify specific asset failures – Verify the following:
- The asset still exists in CMP.
- The asset is accessible with configured credentials.
- The asset is from the correct CMP instance.
Optimizely DAM asset tracking job
- Purpose – Reports asset usage to CMP Asset Lineage API.
- Schedule – Configurable (default: daily).
The job performs the following actions:
Updated 3 days ago
