<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Robert Svallin</title><link href="http://world.optimizely.com" /><updated>2026-04-12T08:48:22.0000000Z</updated><id>https://world.optimizely.com/blogs/robert-svallin/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>CMS 12 - Optimizely DAM Integration 2.2.0</title><link href="https://world.optimizely.com/blogs/robert-svallin/dates/2026/4/cms-12---optimizely-dam-integration-2.2.0" /><id>&lt;div&gt;
&lt;h2&gt;What&#39;s New in Optimizely DAM Integration 2.2.0&lt;/h2&gt;
Version 2.2.0 of the Optimizely DAM (CMP) integration for CMS 12 is a pretty big release. Many of the improvements here come directly from customer feedback and real-world production observations. The result is a more reliable, faster, and more consistent integration across the board.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;This release was developed in parallel with CMS 13, and will most likely be the last version to introduce new features for the CMS 12 integration. CMS 13 adopts the SaaS integration model, which works in a fundamentally different way. Going forward, our focus is on the CMS 13 integration. CMS 12 will continue to receive critical fixes, but new feature work will target CMS 13.&lt;/div&gt;
&lt;div&gt;
&lt;h3&gt;A Note on REST API vs Graph Integration&lt;/h3&gt;
While this release includes improvements to both the REST API and Graph integration paths, Optimizely strongly encourages developers to move to the Graph integration if you haven&#39;t already. The REST API integration has inherent performance limitations and implements rate limiting that can result in 429 (Too Many Requests) status codes under heavy use. This becomes particularly problematic in high-traffic production environments where multiple concurrent requests to CMP can trigger throttling.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;The Graph integration provides a better alternative. It handles high-volume requests without rate limiting issues, offers better query performance, and scales more effectively for production workloads. While this version continues to address issues in the REST API integration for those still using it, the recommended path forward is to migrate to Graph integration.&lt;/div&gt;
&lt;h3&gt;Performance: Cached Metadata During Rendering&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;All rendering helpers now reuse cached metadata from the database. This includes the DAMAssetTagHelper (&amp;lt;dam-asset&amp;gt; tag), HtmlHelpers.RenderTagWithMetadata(), and the new IUrlHelper.DamAssetUrl() extension method. The integration only makes API calls when cached metadata is incomplete, specifically when the URL or MIME type is missing. In typical use cases, metadata is populated during content publishing or by the scheduled maintenance job, which means render-time API calls are eliminated entirely.&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;For a page with 10 DAM assets, the previous implementation would make 10 separate Graph API calls on each render, adding 500-2000ms of latency depending on network conditions and API load. The cached approach retrieves the same data from the database in under 10ms total. For production sites with high traffic, this typically reduces API calls by 95% or more on steady-state pages.This is probably the change you&#39;ll notice most. Previously, the TagHelper and HtmlHelper components made live API calls to CMP Graph every time a page was rendered, even though the metadata was already cached in the CMS database. On high-traffic sites with many assets, this behavior led to SNAT port exhaustion and unnecessary load on the Graph API.&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;New URL Helper Extension&lt;/h3&gt;
&lt;div&gt;Version 2.2.0 introduces IUrlHelper.DamAssetUrl() for direct URL generation from cached metadata:&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;@using EPiServer.Cms.WelcomeIntegration.UI.Helpers

&amp;lt;!-- Basic asset URL --&amp;gt;
&amp;lt;img src=&quot;@Url.DamAssetUrl(Model.CurrentPage.HeroImage)&quot; alt=&quot;Hero&quot; /&amp;gt;

&amp;lt;!-- Specific rendition URL --&amp;gt;
&amp;lt;img src=&quot;@Url.DamAssetUrl(Model.CurrentPage.HeroImage, &quot;thumbnail&quot;)&quot; alt=&quot;Thumbnail&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;div&gt;The method follows this priority chain:&lt;/div&gt;
&lt;ol&gt;
&lt;li&gt;Rendition URL (if rendition name provided and exists in cached metadata)&lt;/li&gt;
&lt;li&gt;Main asset URL (from cached metadata)&lt;/li&gt;
&lt;li&gt;IUrlResolver fallback (if metadata unavailable)&lt;/li&gt;
&lt;li&gt;Empty string (if ContentReference is null/empty)&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;DAM Deep Linking for All Property Types&lt;/h3&gt;
When replacing an existing DAM asset on a content page, the DAM picker opens with the current asset pre-selected, making it easy to browse related assets or pick a different version. In previous releases, this deep linking only worked for properties backed by a `ContentReference`. Properties that store a URL instead, such as `UrlToImage` or `LinkItem`, would open the picker without any context about the current selection.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;The integration now resolves URL-based values server-side before opening the picker. When an editor clicks &quot;replace&quot; on a property that stores a URL, the integration resolves the URL back to a content reference and looks up the corresponding DAM asset. The picker then opens with that asset pre-selected. A small improvement, but one that removes a real friction point for editors working with different property types.&lt;br /&gt;
&lt;h3&gt;Metadata Consistency Across REST API and Graph&lt;/h3&gt;
The integration now provides consistent metadata regardless of whether you retrieve asset information through the CMP REST API or Optimizely Graph. Previously, the data available in the CMS database varied depending on the retrieval method, which created inconsistencies in how assets were stored and rendered.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;The normalization work ensures that three key metadata properties are now consistently populated from both sources. The &lt;strong&gt;Description&lt;/strong&gt; field, which was previously only available when using the REST API, is now properly retrieved from Graph as well. &lt;strong&gt;Renditions&lt;/strong&gt;, alternative asset versions like thumbnails, banners, and other predefined sizes, are now correctly fetched and stored regardless of the data source. Additionally, the &lt;strong&gt;FocalPoint&lt;/strong&gt;&amp;nbsp;property has been restored. This smart crop coordinate data (X, Y values) was available in the 1.x versions of the integration but had been missing in 2.x releases.&lt;br /&gt;
&lt;div&gt;For REST API users, rendition fetching requires explicit configuration. Configure `GetRenditions` to enable rendition data, and optionally GetRenditionsWidthAndHeight to include dimension information:&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddCMPRestApi(options =&amp;gt;
{
    options.GetRenditions = true;
    options.GetRenditionsWidthAndHeight = true;
});&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;&lt;br /&gt;Graph queries are unaffected by these settings and include renditions by default. See the Upgrading section below for additional configuration details.&lt;br /&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;With Description, Renditions, and FocalPoint now included, the metadata story is complete. The integration covers the full set of properties that will be synchronized from CMP, and no additional metadata fields are planned for future releases.&lt;/div&gt;
&lt;br /&gt;
&lt;h3&gt;Document and Video Fixes&lt;/h3&gt;
&lt;strong&gt;Video and document metadata in Graph&lt;/strong&gt;. The Graph integration now handles all asset types uniformly. In previous versions, retrieving metadata for videos or documents through Graph would result in a null DAMAssetInfo, while the same request through the REST API would return proper metadata including title, MIME type, and URL. This discrepancy has been resolved, and the Graph integration now correctly retrieves and populates metadata for images, videos, and documents alike.&lt;br /&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;Document rendering&lt;/strong&gt;. The rendering helpers previously only recognized a hardcoded list of nine application/* MIME types (PDF, Office formats, ZIP) as downloadable documents. Assets with other application/* types fell through to a default case that rendered a &amp;lt;div&amp;gt; with the asset title but no link, making the output non-functional. Text-based documents like CSV or plain text files produced no output at all. This release fixes document rendering so that all document types produce working download links. Text-based documents (text/*) are now explicitly handled, the hardcoded allowlist for application/* types has been removed so all application formats are treated consistently, and the default fallback for any unrecognized MIME type now renders a download link as well.&lt;/div&gt;
&lt;br /&gt;
&lt;h3&gt;Rendition Retrieval Fixes&lt;/h3&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;p&gt;Fixed a bug where Renditions was null when calling IDAMAssetMetadataService.GetAssetMetadata(Guid id) or when stored&amp;nbsp;metadata had no Type value. The metadata service previously only fetched renditions when assetType was explicitly&amp;nbsp;DAMAssetType.Image, but several code paths passed null for this parameter.&lt;/p&gt;
&lt;p&gt;The service now fetches renditions regardless of the assetType value.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;Asset Tracking Improvements&lt;/h3&gt;
&lt;div&gt;The asset tracking system has been improved to correctly handle removals from rich text fields. When you removed a DAM asset from an `XhtmlString` field and published the page, the tracking metadata would remain in the database, making it appear that the asset was still in use. The tracking system now properly updates when assets are removed from `XhtmlString` fields, ensuring the `Trackings` field is correctly nullified when assets are no longer referenced.&lt;/div&gt;
&lt;h3&gt;Upgrading to 2.2.0&lt;/h3&gt;
&lt;div&gt;Upgrading to version 2.2.0 is straightforward. Update the NuGet packages to version 2.2.0:&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code&gt;dotnet add package EPiServer.CMS.WelcomeIntegration.UI --version 2.2.0
dotnet add package EPiServer.Cms.WelcomeIntegration.Core --version 2.2.0
dotnet add package EPiServer.Cms.WelcomeIntegration.Graph --version 2.2.0&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;div&gt;If you&#39;re still using the REST API endpoint, consider this a good time to migrate to the Graph integration. The REST API path carries inherent performance limitations including rate limiting that can cause 429 errors under load, and future development efforts will prioritize the Graph integration. The &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/docs/cmp-dam-in-cms&quot;&gt;official documentation &lt;/a&gt;covers the migration path.&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;For REST API users who are not yet ready to migrate and want to retrieve renditions, you&#39;ll need to add configuration:&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;{
  &quot;CMPRestApi&quot;: {
    &quot;GetRenditions&quot;: true,
    &quot;GetRenditionsWidthAndHeight&quot;: true
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;br /&gt;
&lt;div&gt;After upgrading, run the &quot;Optimizely DAM Maintenance&quot; scheduled job to backfill missing metadata for existing assets. The job will populate Description, Renditions, and FocalPoint data for assets that were created before the upgrade.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
Version 2.2.0 closes a lot of gaps that we have received feedback on over time. If you run into issues after&amp;nbsp;upgrading, or if something doesn&#39;t behave the way you&#39;d expect, file an issue through Optimizely Support. That&amp;nbsp;feedback is what shaped most of this release, and it will shape what comes next for CMS 13.&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;</id><updated>2026-04-12T08:48:22.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>CMS 13 Preview 4 — Upgrading from Preview 3</title><link href="https://world.optimizely.com/blogs/robert-svallin/dates/2026/3/cms-13-preview-4--upgrading-from-preview-3/" /><id>&lt;p&gt;This is the third post in a series where I use the Alloy template as a reference to walk through each CMS 13 preview. The &lt;a href=&quot;/link/401767d8a5e8446db6e213b139618c2d.aspx&quot;&gt;first post&lt;/a&gt; covered upgrading from CMS 12 to Preview 2, and the &lt;a href=&quot;/link/440e06e8b64e4e80aa1b65dc833d9ec2.aspx&quot;&gt;second&lt;/a&gt; looked at the key changes in Preview 3. If you&#39;re following along, pick up where we left off.&lt;/p&gt;
&lt;p&gt;Preview 4 is out. The package bump is easy enough, but there&#39;s an API change around how you resolve the start page that&#39;ll ripple through your code. Here&#39;s what to change and what&#39;s worth knowing about.&lt;/p&gt;
&lt;h2&gt;Step 1: Update Packages&lt;/h2&gt;
&lt;p&gt;Bump your package references from preview3 to preview4:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;PackageReference Include=&quot;EPiServer.CMS&quot; Version=&quot;13.0.0-preview4&quot; /&amp;gt;
&amp;lt;PackageReference Include=&quot;EPiServer.CMS.UI.AspNetIdentity&quot; Version=&quot;13.0.0-preview4&quot; /&amp;gt;
&amp;lt;PackageReference Include=&quot;Optimizely.Graph.Cms&quot; Version=&quot;13.0.0-preview4&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;div&gt;
&lt;h3&gt;Known Issue: Database Schema Upgrade from Older CMS 12 Versions&lt;/h3&gt;
If you&#39;re upgrading directly from an older CMS 12 version (e.g. 12.34.1 or earlier) to a CMS 13 preview and not from preview3 (which this article assumes), the database schema migration may fail with an error like:&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;Column names in each table must be unique. Column name &#39;Failed&#39; in table &#39;dbo.tblNotificationMessage&#39; is specified more than once.&lt;/code&gt;&lt;/pre&gt;
This happens because certain columns were added in later CMS 12 releases, and the CMS 13 migration scripts don&#39;t check whether they already exist before trying to add them.&lt;br /&gt;
&lt;div&gt;Workaround: First upgrade to the latest CMS 12 version so that your database schema is fully up to date, then upgrade from there to the CMS 13 preview. This ensures all intermediate schema changes are applied before the CMS 13 migration runs.&lt;/div&gt;
&lt;/div&gt;
&lt;h2&gt;Step 2: Resolving the Start Page&lt;/h2&gt;
&lt;p&gt;In Preview 3, Alloy template resolved the start page by casting to Website and accessing RoutingEntryPoint. In Preview 4, the simplest approach is to use ContentReference.StartPage directly &amp;mdash; no need to go through IApplicationResolver in most cases.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Before (Preview 3)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var website = _applicationResolver.GetByContext() as Website;
var startPageContentLink = website?.RoutingEntryPoint;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;After (Preview 4)&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var startPageContentLink = ContentReference.StartPage;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the Alloy template this simplified things across several files by using ContentReference.StartPage&amp;nbsp;&lt;br /&gt;- &lt;strong&gt;PageViewContextFactory.cs&lt;/strong&gt; &amp;mdash; CreateLayoutModel&amp;nbsp;&lt;br /&gt;-&amp;nbsp;&lt;strong&gt;ContentLocator.cs&lt;/strong&gt; &amp;mdash; GetContactPages&amp;nbsp;&lt;br /&gt;- &lt;strong&gt;PreviewController.cs&lt;/strong&gt; &amp;mdash; the Index action&lt;br /&gt;- &lt;strong&gt;StartPageController.cs&lt;/strong&gt; &amp;mdash; the Index action&lt;br /&gt;-&amp;nbsp;&lt;strong&gt;Breadcrumbs.cshtml&lt;/strong&gt; and &lt;strong&gt;Header.cshtml&lt;/strong&gt;&amp;nbsp;&amp;mdash; same change&lt;/p&gt;
&lt;p&gt;If you do need more control, IRoutableApplication with its EntryPoint property is still available as an alternative.&lt;/p&gt;
&lt;p&gt;The SiteDefinition migration keeps getting refined. Issues with default application provisioning and hostname resolution between preview and view modes from earlier previews have been sorted out.&lt;/p&gt;
&lt;h2&gt;Step 3: DAM Integration (optional)&lt;/h2&gt;
&lt;p&gt;Preview 4 adds a new package for Optimizely DAM integration. Its important to call out that even though DAM is a fundamental piece of CMS 13 it is possible to run without it. CMS still can store assets in te traditional sense.&lt;/p&gt;
&lt;p&gt;Similar to CMS 12 the DAM configuration is handled using options directly requiring an application to be created in CMP from which the credentials can be retrieved for configuration in CMS. You&#39;ll also need the SSO ID which can be found under &lt;strong&gt;Settings \ Organization \ General&lt;/strong&gt; in CMP.&lt;/p&gt;
&lt;p&gt;The DAM integration no longer talks to the CMP REST API directly. Instead it&#39;s built on External Sources, which means DAM assets need to be indexed into the Optimizely Graph instance connected to your CMS. So before wiring up the code below, make sure you have Optimizely Graph set up, then contact Optimizely Support to connect DAM to your Graph instance. The onboarding steps &amp;mdash; selecting your DAM instance, activating asset types &amp;mdash; follow the same process as CMS SaaS and are documented in the &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/docs/onboard-dam-to-cms-saas&quot;&gt;Onboard DAM to CMS guide&lt;/a&gt;. Updated documentation specific to CMS 13 will be available at release. Once that&#39;s done, Content Manager can be used to discover and pick DAM assets directly from the editing UI.&lt;/p&gt;
&lt;p&gt;Add the package:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;PackageReference Include=&quot;EPiServer.Cms.DamIntegration.UI&quot; Version=&quot;13.0.0-preview4&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Register the DAM UI in Startup.cs:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddDamUI();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the DAM HTML helpers namespace to Views/_ViewImports.cshtml:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;@using EPiServer.Cms.DamIntegration.UI.Helpers&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This gives you access to helpers like RenderTagWithMetadata(...) for rendering DAM assets. Note that the epi-property tag helper you&#39;re already using comes from EPiServer.Cms.AspNetCore.TagHelpers, which should already be registered in your _ViewImports.cshtml via @addTagHelper.&lt;/p&gt;
&lt;p&gt;Then configure your CMP credentials (note that these have defaults, included here for transparency) in appsettings.json:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;&quot;Optimizely&quot;: {
  &quot;Cms&quot;: {
    &quot;DamUI&quot;: {
      &quot;Endpoint&quot;: &quot;https://cmp.optimizely.com&quot;,
      &quot;SsoId&quot;: &quot;&amp;lt;your-sso-id&amp;gt;&quot;,
      &quot;NavigationUrl&quot;: &quot;https://cmp.optimizely.com/cloud/library&quot;
    }
  },
  &quot;Cmp&quot;: {
    &quot;Client&quot;: {
      &quot;TokenUrl&quot;: &quot;https://accounts.cmp.optimizely.com/o/oauth2/v1/token&quot;,
      &quot;ApiUrl&quot;: &quot;https://api.cmp.optimizely.com/v3/&quot;,
      &quot;ClientId&quot;: &quot;&amp;lt;your-client-id&amp;gt;&quot;,
      &quot;ClientSecret&quot;: &quot;&amp;lt;your-client-secret&amp;gt;&quot;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The DAM picker now also supports multi-select, which is a nice improvement for editors working with lots of media.&lt;/p&gt;
&lt;h3&gt;Migrating from CMS 12 DAM Integration&lt;/h3&gt;
&lt;p&gt;For the GA release of CMS 13, a standalone migration package will be available that converts the CMS 12-style DAM integration to the new one. This package&amp;nbsp;will handle the migration of existing DAM asset references so that they work with the new EPiServer.Cms.DamIntegration.UI package.&lt;/p&gt;
&lt;p&gt;The first version of the migration package will support:&lt;br /&gt;&amp;nbsp; - ContentReference properties&lt;br /&gt;&amp;nbsp; - IList&amp;lt;ContentReference&amp;gt; properties&lt;/p&gt;
&lt;p&gt;Support for additional property types will be added in future releases.&lt;/p&gt;
&lt;h3&gt;Using DAM Assets in Your Content&lt;/h3&gt;
&lt;p&gt;To use DAM assets on a page, add a ContentReference property with the UIHint.Image hint:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using EPiServer.Web;
using System.ComponentModel.DataAnnotations;

public class DamExamplePage : StandardPage
{
    [Display(GroupName = Globals.GroupNames.Content)]
    [UIHint(UIHint.Image)]
    public virtual ContentReference Image { get; set; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In the view, render it with the epi-property tag helper &amp;mdash; same pattern as any other CMS property:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;img epi-property=&quot;@Model.CurrentPage.Image&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Step 4: Audiences (optional)&lt;/h2&gt;
&lt;p&gt;Audiences are a separate package in CMS 13. If you were using services.AddVisitorGroups() in Preview 3, you&#39;ll need to add the new NuGet package and update your service registration.&lt;/p&gt;
&lt;p&gt;Add the package:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;PackageReference Include=&quot;EPiServer.Cms.UI.VisitorGroups&quot; Version=&quot;13.0.0-preview4&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then update your Startup.cs &amp;mdash; the old AddVisitorGroups() call is replaced with two separate registrations:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using EPiServer.Cms.UI.VisitorGroups;
services.AddVisitorGroupsMvc().AddVisitorGroupsUI();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A few audience-related bugs have also been fixed: the policy-not-found error is gone, Geographic Location criteria works, and context menu positioning for personalized groups has been corrected.&lt;/p&gt;
&lt;h2&gt;What Else Is New in Preview 4&lt;/h2&gt;
&lt;p&gt;A few things worth knowing about beyond the upgrade steps:&lt;/p&gt;
&lt;h3&gt;Graph .NET SDK&lt;/h3&gt;
&lt;p&gt;There&#39;s a new .NET SDK for Optimizely Graph with a fluent API covering facets, caching, auth, tracking, and object-to-Graph field mapping. Extensibility points have also been added to ContentGraph.CMS so you can hook into the indexing pipeline.&lt;/p&gt;
&lt;h3&gt;Improved Migration from SiteDefinition&lt;/h3&gt;
&lt;p&gt;The migration from SiteDefinition to the Application Model has been improved. Creating in-process websites via the settings UI works again, and typed content types now show up correctly when picking the start page for an application.&lt;/p&gt;
&lt;p&gt;For the full list of changes, check the official release notes.&lt;/p&gt;</id><updated>2026-03-20T12:08:15.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>CMS 13 Preview 3: Key changes</title><link href="https://world.optimizely.com/blogs/robert-svallin/dates/2026/2/cms-13-preview-3-key-changes/" /><id>&lt;p&gt;If you&#39;ve been following along with the CMS 13 preview, you&#39;ve likely worked through the initial upgrade path covered in my previous post. Preview 3 brings us another step closer to a production-ready release. Based on feedback on Preview 2 we have made changes so that &lt;strong&gt;Content Manager and Optimizely Graph are no longer enabled by default. &lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;It is however important to understand that: while these features are opt-in from a technical perspective, Optimizely Graph is effectively required if you want to unlock the full potential of CMS 13. &lt;span class=&quot;fabric-background-color-mark&quot;&gt;In practice, we expect most customers to adopt Graph as part of their CMS 13 journey, since many of the platform&amp;rsquo;s most meaningful innovations depend on it. Let&amp;rsquo;s unpack what that means.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;What&#39;s New in Preview 3?&lt;/h2&gt;
&lt;p&gt;Preview 3 includes the usual improvements and bug fixes, but I wont highlight them here but instead refer to the official &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13-Pre-Release/docs/release-notes-for-cms-13-pre-release-preview-3&quot;&gt;release notes&lt;/a&gt;. What is worth discussing is the change in having Optimizely Graph and Content Manager enabled through opt in.&lt;/p&gt;
&lt;h2&gt;Why Optimizely Graph Matters&lt;/h2&gt;
&lt;p&gt;Several of CMS 13&#39;s new features are built on top of Optimizely Graph. Let&amp;acute;s look at some of the bigger examples:&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li&gt;
&lt;p&gt;Content Manager: The new editorial experience relies on Graph for content discoverability.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;External Content: Integrating content from external sources outside of CMS requires Graph&#39;s indexing capabilities&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Content Binding: The approach to rendering external content leverages Graph&#39;s structured queries&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;span class=&quot;fabric-background-color-mark&quot;&gt;RAG for Opal: Graph allows Opal to &amp;ldquo;see&amp;rdquo; and &amp;ldquo;understand&amp;rdquo; your content. Allowing Opal to query all content, understand tone of voice, and more.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In other words, if you&#39;re planning to use any of the new CMS 13 features that differentiate it from CMS 12, you need Optimizely Graph - they wont work without it. At Optimizely, we view Optimizely Graph as a &lt;strong&gt;mandatory&lt;/strong&gt; and foundational component for using CMS 13 to its full potential. Running CMS 13 without Optimizely Graph will be very close to running CMS 12 compiled for .NET 10 with a smaller subset of new features. Over time, Optimizely Graph will increase in usage in CMS 13 and beyond since it is at the very center of functionality that we build.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;fabric-background-color-mark&quot;&gt;For organizations that truly cannot adopt Graph, it&amp;rsquo;s worth carefully evaluating the value of moving to CMS 13 in the near term, since several of the headline innovations will not be available without it.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Is Optimizely Graph required?&lt;/h2&gt;
&lt;p&gt;Let&#39;s be pragmatic about this. You can run CMS 13 without Graph in some scenarios, for example:&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li&gt;
&lt;p&gt;You&#39;re maintaining a CMS 12 codebase with minimal changes during migration&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You&#39;re in the early phases of migration and haven&#39;t yet enabled the new features&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class=&quot;fabric-background-color-mark&quot;&gt;One example is customers with strict on-prem or data residency requirements where introducing a cloud service is not feasible. That said, many customers who run CMS &amp;ldquo;on-prem&amp;rdquo; Today are already operating in hybrid models (self-hosted in cloud environments, partner-hosted infrastructure, etc.), and in those cases Graph is often still a viable option.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If you&#39;re upgrading to CMS 13 for its new capabilities, then its likely that you will be adopting Graph. The question probably isn&#39;t &quot;if&quot; but rather &quot;when&quot; in your migration timeline.&lt;/p&gt;
&lt;h2&gt;Enabling Content Manager and Optimizely Graph&lt;/h2&gt;
&lt;p&gt;Since you&#39;ll almost certainly need these features, or at least want to try them out, here&#39;s the straightforward opt-in process:&lt;/p&gt;
&lt;p&gt;Step 1: Add the NuGet Packages&lt;br /&gt;Reference the appropriate packages in your project:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;dotnet add package EPiServer.Cms.UI.ContentManager
dotnet add package Optimizely.Graph.Cms&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Step 2: Update Your Startup Configuration&lt;br /&gt;In your Startup.cs (or wherever you&#39;re configuring services in your Alloy-based project), add the following calls to your service registration:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
{
  // ... your existing service configuration
  services.AddContentGraph();
  services.AddContentManager();
  // ... rest of your configuration
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Notice the order matters here: AddContentGraph() should come before AddContentManager() since Content Manager depends on Graph&#39;s infrastructure.&lt;/p&gt;
&lt;h2&gt;My perspective on Graph Adoption&lt;/h2&gt;
&lt;p&gt;Here&#39;s what I am thinking with this change on Opt In approach: Graph isn&#39;t a nice-to-have feature add-on&amp;mdash;it&#39;s a corner stone for content delivery in the Optimizely ecosystem.&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li&gt;
&lt;p&gt;Content Manager gives editors a performant content discovery experience powered by Graph queries&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;External Content lets you unify disparate content sources through Graph&#39;s indexing&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Content Binding enables developers to work with strongly-typed content models backed by Graph&#39;s schema&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These aren&#39;t isolated features; they are puzzle pieces that tell a joint story. And Graph is the connective tissue that bind them together.&lt;/p&gt;
&lt;p&gt;If you&#39;re building greenfield projects or undertaking significant modernization efforts, I think that you should embrace Graph from day one. Trying to retrofit it later when you want to adopt Content Manager or External Content will be more painful than including it from the start.&lt;/p&gt;
&lt;h2&gt;So, Alloy Template&lt;/h2&gt;
&lt;p&gt;If you&#39;re working with the Alloy template as a learning tool or project foundation, you&#39;ll want to enable both features to get the full editorial experience. The Alloy template shows Content Manager&#39;s capabilities, and Graph powers both its search functionality and the new content delivery patterns.&lt;/p&gt;
&lt;p&gt;This is actually a good learning environment to understand how Graph integrates with the platform before you build your production architecture.&lt;/p&gt;
&lt;p&gt;As always, remember that Preview 3 is not production-ready. Use it for evaluation, experimentation, and preparation&amp;mdash;but keep your production sites on CMS 12 until the official CMS 13 release.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;</id><updated>2026-02-19T13:44:31.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>From 12 to 13 preview: A Developer&#39;s Guide to testing an Optimizely CMS 13 Alloy Site</title><link href="https://world.optimizely.com/blogs/robert-svallin/dates/2026/1/from-12-to-13-a-developers-guide-to-upgrading-an-optimizely-cms-alloy-site/" /><id>&lt;p&gt;The release of Optimizely CMS 13 marks a significant step forward, embracing a more composable and headless-first architecture. While this unlocks powerful new capabilities, it also introduces important changes to the underlying framework.&lt;/p&gt;
&lt;p&gt;This guide provides a hands-on walkthrough for upgrading a standard CMS 12 Alloy starter site to the CMS 13 preview. We&#39;ll cover dependency updates, code migrations for obsolete APIs, and the new application configuration model.&lt;/p&gt;
&lt;h2&gt;Step 1: Create a Baseline CMS 12 Site&lt;/h2&gt;
&lt;p&gt;First, let&#39;s establish a starting point. Create a fresh CMS 12 Alloy site using the Optimizely templates. This ensures we have a clean, working installation before we begin the upgrade.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;# Create a new Alloy project
dotnet new epi-alloy-mvc -n alloy13preview

# Build and run the site
dotnet build
dotnet run&lt;/code&gt;&lt;/pre&gt;
&lt;div class=&quot;fabric-editor-breakout-mark fabric-editor-block-mark css-p8f2xz&quot;&gt;
&lt;div class=&quot;code-block css-ggxefa&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;Once the site is running, register a new user account so you can log in. Verify that the site is fully functional. When you&#39;re ready, shut down the application.&lt;/p&gt;
&lt;h2&gt;Step 2: Update Project Dependencies&lt;/h2&gt;
&lt;p&gt;With our baseline established, the next step is to update the project file and NuGet packages.&lt;/p&gt;
&lt;ol class=&quot;ak-ol&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Update the Target Framework&lt;/strong&gt;: Open the .csproj file and change the target framework to&lt;/p&gt;
&lt;div class=&quot;code-block css-ggxefa&quot;&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;&amp;lt;PropertyGroup&amp;gt;
  &amp;lt;TargetFramework&amp;gt;net10.0&amp;lt;/TargetFramework&amp;gt;
&amp;lt;/PropertyGroup&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Update NuGet Packages&lt;/strong&gt;: Update all EpiServer.* package versions to 13.0.0-preview2.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Add AspNetIdentity&lt;/strong&gt;: CMS 13 decouples the UI&#39;s identity management. Add a new package reference for EPiServer.CMS.UI.AspNetIdentity.&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;code-block css-ggxefa&quot;&gt;
&lt;div class=&quot;css-9n57oc&quot;&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;PackageReference Include=&quot;EPiServer.CMS.UI.AspNetIdentity&quot; Version=&quot;13.0.0-preview2&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Step 3: Code Migration and Mitigating Obsolete APIs&lt;/h2&gt;
&lt;p&gt;CMS 13 refactors several core APIs. The compiler will now report a series of warnings and errors related to obsolete members. Let&#39;s work through them.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;A Friendly Pro-Tip:&lt;/strong&gt; As you begin the migration, make it a habit to check the compiler warnings in your IDE or build output. These warnings are your roadmap to finding every instance of a deprecated or obsolete API in your specific project. While this guide covers the common changes for the Alloy template, your codebase may have other areas needing attention.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h3&gt;Use ContentReference and ContentLink&lt;/h3&gt;
&lt;p&gt;The PageReference and PageData.PageLink types are now obsolete. This change reflects a broader shift to treat all content more generically. The fix is a straightforward replacement across your solution:&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li&gt;
&lt;p&gt;Replace PageReference with ContentReference.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Replace .PageLink with .ContentLink.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Replace SiteDefinition with the New Application Model&lt;/h3&gt;
&lt;p&gt;The concept of SiteDefinition is replaced by a more flexible &lt;strong&gt;Application Model&lt;/strong&gt;. An application connects a starting point in the content tree with a specific rendering mode (e.g., &quot;In-Process&quot; or &quot;Headless&quot;) and hostnames.&lt;/p&gt;
&lt;p&gt;To resolve this, you&#39;ll need to inject IApplicationResolver into your controllers and services to get the context of the current application (IApplication).&lt;/p&gt;
&lt;p&gt;Here is an example of how to refactor the StartPageController:&lt;/p&gt;
&lt;div class=&quot;fabric-editor-breakout-mark fabric-editor-block-mark css-p8f2xz&quot;&gt;
&lt;div class=&quot;code-block css-ggxefa&quot;&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using alloy13preview.Models.Pages;
using alloy13preview.Models.ViewModels;
using EPiServer.Web;
using EPiServer.Web.Mvc;
using Microsoft.AspNetCore.Mvc;
using EPiServer.Applications;
using EPiServer.Shell.Security;
using EPiServer.Web.Routing;

namespace alloy13preview.Controllers;

public class StartPageController : PageControllerBase&amp;lt;StartPage&amp;gt;
{
  private readonly IApplicationResolver _applicationResolver;
  
  public StartPageController(IApplicationResolver applicationResolver)
  {
    _applicationResolver = applicationResolver;
  }

  public async Task&amp;lt;IActionResult&amp;gt; Index(StartPage currentPage, CancellationToken cancellationToken)
  {
    var model = PageViewModel.Create(currentPage);
    var application = await _applicationResolver.GetByContextAsync(cancellationToken);

    var website = application as Website;
    
    if (website is not null &amp;amp;&amp;amp; website.RoutingEntryPoint.CompareToIgnoreWorkID(currentPage.ContentLink))
    {
      // Connect the view models logotype property to the start page&#39;s to make it editable
      var editHints = ViewData.GetEditHints&amp;lt;PageViewModel&amp;lt;StartPage&amp;gt;, StartPage&amp;gt;();
      editHints.AddConnection(m =&amp;gt; m.Layout.Logotype, p =&amp;gt; p.SiteLogotype);
      editHints.AddConnection(m =&amp;gt; m.Layout.ProductPages, p =&amp;gt; p.ProductPageLinks);
      editHints.AddConnection(m =&amp;gt; m.Layout.CompanyInformationPages, p =&amp;gt; p.CompanyInformationPageLinks);
      editHints.AddConnection(m =&amp;gt; m.Layout.NewsPages, p =&amp;gt; p.NewsPageLinks);
      editHints.AddConnection(m =&amp;gt; m.Layout.CustomerZonePages, p =&amp;gt; p.CustomerZonePageLinks);
    }

    return View(model);
  }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You will need to apply a similar pattern to other places in the code that reference SiteDefinition.Current. For SiteDefinition.Current.RootPage, you can replace it with ContentReference.RootPage.&lt;/p&gt;
&lt;h3&gt;Modernize Dependency Injection&lt;/h3&gt;
&lt;p&gt;Service location using InitializationEngined.Locate is obsolete. Instead, use constructor injection to get an IServiceProvider instance.&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Before&lt;/strong&gt;: context.Locate.Advanced.GetInstance&amp;lt;T&amp;gt;()&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;After&lt;/strong&gt;: Inject IServiceProvider&amp;nbsp;and call serviceProvider.GetRequiredService&amp;lt;T&amp;gt;()&amp;nbsp;In an IInitializationModule, you can access it via context.Services.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Other Small API Changes&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li&gt;IContentTypeRepository&amp;lt;T&amp;gt;: The generic argument is no longer needed. Change IContentTypeRepository&amp;lt;PageType&amp;gt;()&amp;nbsp;to IContentTypeRepository()&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;PageController.PageContext.Page This property is now of type IContent. Update your code to reflect this change.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step 4: Configuration Updates&lt;/h2&gt;
&lt;p&gt;Next, we need to make a few adjustments in Startup.cs and appSetting.json&lt;/p&gt;
&lt;ol class=&quot;ak-ol&quot;&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enable Database Compatibility Update&lt;/strong&gt;: In Startup.cs,&amp;nbsp;add the following to allow the database compatibility level to be updated automatically.&lt;/p&gt;
&lt;div class=&quot;code-block css-ggxefa&quot;&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.Configure&amp;lt;DataAccessOptions&amp;gt;(options =&amp;gt;
{
    options.UpdateDatabaseCompatibilityLevel = true;
});&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Configure Content Graph&lt;/strong&gt;: Content Graph is enabled by default in the preview of CMS 13 and cant be disabled. This will likely change in subsequent releases. You must add your credentials to appSettings.json.&lt;/p&gt;
&lt;div class=&quot;code-block css-ggxefa&quot;&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;&quot;Optimizely&quot;: {
  &quot;ContentGraph&quot;: {
    &quot;GatewayAddress&quot;: &quot;https://staging.cg.optimizely.com&quot;,
    &quot;AllowSendingLog&quot;: &quot;true&quot;,
    &quot;SingleKey&quot;: &quot;INSERT SINGLEKEY HERE&quot;,
    &quot;AppKey&quot;: &quot;INSERT APPKEY HERE&quot;,
    &quot;Secret&quot;: &quot;INSERT SECRET HERE&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install Visitor Groups&lt;/strong&gt;: Due to a known issue in the preview, the menu system will not render correctly unless Visitor Groups are installed. Add this to Startup.cs&lt;/p&gt;
&lt;div class=&quot;code-block css-ggxefa&quot;&gt;
&lt;div class=&quot;css-9n57oc&quot;&gt;
&lt;div class=&quot;css-4osl21&quot;&gt;
&lt;div&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddVisitorGroups();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Step 5: Fixing the Post-Upgrade 404&lt;/h2&gt;
&lt;p&gt;After making all the changes, run the application:&lt;/p&gt;
&lt;div class=&quot;fabric-editor-breakout-mark fabric-editor-block-mark css-p8f2xz&quot;&gt;
&lt;div class=&quot;code-block css-ggxefa&quot;&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;dotnet run&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;You will notice the site returns a &lt;strong&gt;404 Not Found&lt;/strong&gt; error. This is expected. The migrated database still has the old SiteDefinition configuration, which doesn&#39;t align with the new Application Model.&lt;/p&gt;
&lt;p&gt;Follow these steps to fix it:&lt;/p&gt;
&lt;ol class=&quot;ak-ol&quot;&gt;
&lt;li&gt;
&lt;p&gt;Navigate to the CMS admin interface: &lt;code class=&quot;_ca0qyh40 _u5f3m5ip _n3tdyh40 _19bvm5ip _2rkofajl _11c819w5 _1reo1wug _18m91wug _1dqoglyw _1e0c1nu9 _bfhk187e _16d9qvcn _syazi7uo _vwz41kw7 _1i4q1hna _o5721jtm&quot;&gt;https://localhost:5000/Optimizely/CMS&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go to &lt;strong&gt;Settings&lt;/strong&gt; &amp;gt; &lt;strong&gt;Applications&lt;/strong&gt;. If the page fails to render, clear your browser cache and reload. You will see a default &quot;Headless&quot; application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Edit the application and click &lt;strong&gt;Delete Application&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Click &lt;strong&gt;Create New Application&lt;/strong&gt;.&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li&gt;
&lt;p&gt;Set the &lt;strong&gt;Type&lt;/strong&gt; to &lt;strong&gt;In Process&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Select your original Alloy start page as the &lt;strong&gt;Application start page&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Give it a name.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Edit the new &quot;In Process&quot; application you just created.&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li&gt;
&lt;p&gt;In the &lt;strong&gt;Hosts&lt;/strong&gt; section, add a new host with the name localhost:5000&amp;nbsp;and set it as the default.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Your Alloy site should now render correctly on the frontend, and preview in Edit mode will be functional.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Congratulations! You have successfully upgraded your Alloy site to CMS 13. This process highlights the key architectural shifts in the new version, particularly the move to a composable Application Model and modernized APIs. You are now ready to explore the new features and possibilities of Optimizely CMS 13.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Important Note&lt;/strong&gt;: The steps outlined in this guide are intended for developers to explore the CMS 13 preview with the Alloy template. This is an incomplete preview, and these instructions are not recommended for use with an actual development project and certainly not a live production site. We will share more as we get closer to the release date of CMS 13.&lt;/p&gt;</id><updated>2026-01-23T14:21:45.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>CMP DAM asset sync to Optimizely Graph self service</title><link href="https://world.optimizely.com/blogs/robert-svallin/dates/2025/2/cmp-dam-asset-graph-self-service/" /><id>&lt;p&gt;The CMP DAM integration in CMS introduced support for querying Optimizly Graph (EPiServer.Cms.WelcomeIntegration.Graph 2.0.0) for metadata such as alternative texts. Up until now interaction with Optimizely has been needed when adding this integration from CMP to Optmizely Graph but that is no longer the case. CMP now contains a self service feature where Optimizely Graph can be added and initial synchronization of assets started. This makes it easier to get started and reap the performance benefits of moving from REST API integration with CMP to the more performant Optimizely Graph integration.&lt;/p&gt;
&lt;p&gt;In CMP simply header over to &lt;strong&gt;Settings \ Organization \ Misc&lt;/strong&gt;, scroll to the bottom of the view and hit the &lt;strong&gt;Enable &amp;amp; Sync&lt;/strong&gt;&amp;nbsp;button that you will find there. Once the sync has completed you will find a URL to the Optimizely Graph UI which contains the &lt;strong&gt;SingleKey&lt;/strong&gt; needed to configure CMS.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/ff2c84cbf623455ba306902f5ed5b262.aspx?1739443330051&quot; alt=&quot;Enabling and syncing DAM assets to Optimizely Graph&quot; width=&quot;195&quot; height=&quot;94&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The URL will look something like below.&lt;/p&gt;
&lt;p&gt;&lt;a title=&quot;Optimizely Graph UI with single key&quot; href=&quot;https://cg.optimizely.com/app/graphiql?auth=SINGLE_KEY&quot;&gt;https://cg.optimizely.com/app/graphiql?auth=SINGLE_KEY&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;If you havent already read about our integration with CMP, either with REST API, or with Optimizely Graph, then please head over to &lt;a href=&quot;https://docs.developers.optimizely.com/platform-optimizely/docs/cmp-dam-cms&quot;&gt;CMP DAM in CMS&lt;/a&gt; to find details on how to get started.&lt;/p&gt;</id><updated>2025-02-13T10:48:51.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>DAM integration new major version, performance improvements and Library Picker folder selection</title><link href="https://world.optimizely.com/blogs/robert-svallin/dates/2024/11/dam-integration-new-major-version-performance-improvements-and-library-picker-folder-selection/" /><id>&lt;p&gt;As you might already have seen we have decided to delist the EPiServer.CMS.WelcomeIntegration version 1.4.0 where we introduced Graph support. Unfortunately a return type was changed that we didn&amp;rsquo;t catch which means that it became a breaking change. We have decided to delist 1.4.0 and release the performance improvements we have been working on as a new major. We apologize for any inconvenience this has caused and suggest that you either downgrade to 1.3.9 and rely on the CMP API instead of Graph, or upgrade to 2.0.0 instead. We recommend to upgrade to 2.0.0 for the best performance.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Performance&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The integration between CMS and CMP uses a combination of the CMP Library Picker, in which the editor selects the asset to reference and, either the CMP&amp;acute;s REST API, or indexed assets in Graph. The API or Graph is used to pull metadata regarding the assets such as sizing or alt texts. The integration with REST API has been around for quite some time and the Graph integration was released in the previous version, 1.4.0, and we described how to configure it in &lt;a href=&quot;/link/652f47770cce478882e5e0481d69b6c8.aspx&quot;&gt;this blog post by Bartosz Sekula&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We are now releasing a change in how metadata is cached in the CMS for assets referenced from CMP DAM. Moving forward from version 2.0.0 the cache will move to the database and stored permanently. This removes the need for any page request that contain CMP DAM assets to perform outbound network requests to retrieve that metadata when cache has expired.&lt;/p&gt;
&lt;p&gt;The metadata will be fetched for Image assets from CMP when a content that contains references to those images is &lt;strong&gt;published&lt;/strong&gt;. So metadata will be available once the page starts to receive traffic. Please note that fetching the metadata is handled in the background to not block the editor from interacting with the UI. If the images are already referenced by other pages or block then the already existing metadata will be used.&lt;/p&gt;
&lt;p&gt;Should for some reason the metadata not have been populated then the image will still render but with the public URL which was stored the first time the asset was referenced, instead of the latest URL provided by CMP through the metadata.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Renditions&lt;/strong&gt; of &lt;strong&gt;Images&lt;/strong&gt; is a bit different and a topic to which we will return. Currently the renditions for an image asset will render without alt-text. As already stated, we are working on resolving that. The HtmlHelper and TagHelper as well as DamImageAssetViewComponent will still render the correct rendition.&lt;/p&gt;
&lt;p&gt;Example of using HtmlHelper&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;@model PageViewModel&amp;lt;StandardPage&amp;gt;
@using EPiServer.Cms.WelcomeIntegration.UI.Helpers

@await Html.RenderTagWithMetadata(p =&amp;gt; p.CurrentPage.Image)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Example of using TagHelper&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;@model PageViewModel&amp;lt;StandardPage&amp;gt;
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers

&amp;lt;dam-asset content-reference=&quot;@Model.CurrentPage.Image&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Maintaining asset metadata&lt;/h3&gt;
&lt;p&gt;Since the metadata for Images now have moved to the database, how does it get updated? A new scheduled job has been created which will, on schedule, pull metadata from CMP DAM for all assets and update in CMS. This job can be executed manually should the need arise to sync metadata between CMP and CMS.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/7771fed1d3e54efbb6c8f8b4142cecc8.aspx?1732854990499&quot; alt=&quot;The scheduled job for maintaining CMP DAM asset metadata in CMS&quot; width=&quot;834&quot; height=&quot;471&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Metrics from testing scenarios indicate big performance improvements when serving content with DAM assets to visitors.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Asset Library folder selection&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;CMP has the possibility to organize content in folder structures and it is now possible configure either globally or by type which folder to open in the &lt;strong&gt;CMP Library Picker&lt;/strong&gt;. Configuration is done at startup or appSettings as usual.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;.AddDAMUi(o =&amp;gt; {
    o.Enabled = true;
    o.GlobalRootFolderGuid = &quot;a7fd6357c13d49829715f38fe8114c40&quot;;
    o.RootFolderForTypes = new Dictionary&amp;lt;string, IEnumerable&amp;lt;Type&amp;gt;&amp;gt;
    {
        { &quot;57523add60d04e328d7fc1e02c05ed40&quot;, new Type[] { typeof(DAMImageAsset) } },
        { &quot;7bce1de28e66411590ac32896eff2ce1&quot;, new Type[] { typeof(DAMVideoAsset) } },
        { &quot;72b89ab1b83041acaab861a035db7e7b&quot;, new Type[] { typeof(DAMAsset) } }
    };
});&lt;/code&gt;&lt;/pre&gt;</id><updated>2024-11-29T04:37:35.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>EPiServer.CMS UI 12.17.0 delisted from Nuget feed</title><link href="https://world.optimizely.com/blogs/robert-svallin/dates/2023/3/episerver-cms-ui-12-17-0-delisted-from-nuget-feed/" /><id>&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;The 12.17.0 version of the UI packages have been delisted from our Nuget feed and is no longer available. We are working on providing a patch, 12.17.1 to correct an issue that affects string properties that use &lt;span class=&quot;classLib&quot;&gt;SelectMany&lt;/span&gt; attribute and a &lt;span class=&quot;classLib&quot;&gt;ISelectionFactory&lt;/span&gt; to handle the available options.&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;The root issue is that the representation of the selected values is now stored in a different way in the database and that needs to be considered a breaking change. We moved from a comma separated list in favor of a Json array. I.e. from &quot;value1,value2,value3&quot; to &quot;[\&quot;value1\&quot;,\&quot;value2\&quot;,\&quot;value3\&quot;] in an effort to try and broaden the capabilities. The change only applies to properties that have been updated and saved to the database since the 12.17.0 upgrade was done on the installation.&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;An installation can be checked if it has been affected by the issue, by running a query against the database to see if the properties store a JSON array or comma separated strings. Please note that only installations using 12.17.0 and that uses properties that are using SelectMany attribute is potentially affected.&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;An example would be that 12.17.0 would store&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11pt; padding-left: 40px;&quot; lang=&quot;sv&quot;&gt;&lt;span class=&quot;classLib&quot;&gt;[&quot;1&quot;,&quot;2&quot;,&quot;3&quot;]&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;Instead of the previously used&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11pt; padding-left: 40px;&quot; lang=&quot;sv&quot;&gt;&lt;span class=&quot;classLib&quot;&gt;1,2,3&lt;/span&gt;&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li style=&quot;font-family: Calibri; font-size: 11pt;&quot; lang=&quot;sv&quot;&gt;&lt;a href=&quot;/epiui/CMS/Content/support/Bug-list,,149001/bug/CMS-26903?epieditmode=False&amp;amp;epsremainingpath=bug/CMS-26903&quot; title=&quot;CMS-26903&quot;&gt;CMS-26903&lt;/a&gt;&lt;br /&gt;When addressing the issue &lt;a href=&quot;/epiui/CMS/Content/support/Bug-list,,149001/bug/CMS-23405?epieditmode=False&amp;amp;epsremainingpath=bug/CMS-23405&quot; title=&quot;CMS-23405&quot;&gt;CMS-23405&lt;/a&gt; &lt;span lang=&quot;sv&quot; style=&quot;font-family: Calibri; font-size: 11.0pt;&quot;&gt;a breaking change was introduced in how the values for string properties using&amp;nbsp;&lt;/span&gt;&lt;span lang=&quot;en-SE&quot; style=&quot;font-weight: bold; font-family: -apple-system; font-size: 10.5pt; color: #272b32; background: white;&quot;&gt;SelectManyAttribute&lt;/span&gt;&lt;span lang=&quot;sv&quot; style=&quot;font-family: Calibri; font-size: 11.0pt;&quot;&gt;&amp;nbsp;and&amp;nbsp;&lt;/span&gt;&lt;span lang=&quot;en-SE&quot; style=&quot;font-weight: bold; font-family: -apple-system; font-size: 10.5pt; color: #272b32; background: white;&quot;&gt;ISelectionFactory&lt;/span&gt;&lt;span lang=&quot;sv&quot; style=&quot;font-family: Calibri; font-size: 11.0pt;&quot;&gt;&amp;nbsp;are stored in the database. A change was made to serialize the selected options as JSON instead of comma separated strings.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;We offer our apologies that this occured and we are sorry that this has affected our customers. For installations that are in the process of migrating to 12.17.0 we ask that you verify if you are affected. Wait for the 12.17.1 version that will arrive shortly and then verify that data is stored correctly.&lt;/p&gt;
&lt;p style=&quot;margin: 0in; font-family: Calibri; font-size: 11.0pt;&quot; lang=&quot;sv&quot;&gt;This blog post will be updated as we move forward with this issue. Thank you for your patience.&lt;/p&gt;</id><updated>2023-03-01T05:30:45.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Improving And Unifying The UI</title><link href="https://world.optimizely.com/blogs/robert-svallin/dates/2022/6/ui-refresh/" /><id>&lt;p&gt;&lt;span&gt;We aim to unify and make a seamless user experience across all Optimizely products. This change will make our products more predictable, easy to use, and accessible. T&lt;/span&gt;herefor the CMS in Content Cloud has, over the last few versions (starting with 12.3.0), received multiple updates to the UI.&amp;nbsp; This work is still ongoing, and in the coming weeks/months we expect to release even more updates. However, we wanted to pause and talk a bit about what we have done recently.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s start with a direct comparison of how the UI has changed during this period. The screenshots below clearly outline the differences.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/e22dea18564b4579a02de912701e2f89.aspx&quot; width=&quot;2844&quot; alt=&quot;A comparison of form edit between 12.7.0 (left) and 12.2.0 (right).&quot; style=&quot;border-style: solid;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;em&gt;Image: A comparison of form edit between 12.7.0 (left) and 12.2.0 (right).&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The UI now uses icons from Font Awesome Pro 6, which is a font-based icon library which in turn means that there are fewer resources to download and the icons scale better since they are vector-based. Icons are no longer solid instead, they are outlined, more sharp, crisp, and modern looking. All products from Optimizely use the same set of icons.&lt;/p&gt;
&lt;p&gt;The new icons use the same CSS classes as the old ones did, so for example the home icon still uses the .epi-iconObjectStart CSS class. However, the new icons use a licensed version of Font Awesome 6 Pro, and this limits how the icons can be used. Third-party add-ons and extensions need to use either a free version of Font Awesome 6/equivalent or purchase their license. The new icons have the following sizes, small (16 x 20), medium (24 x 30), and large (32 x 40).&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Spacing has also been reworked to introduce more padding to create an improved visual clarity, balancing the layout and making it easier to overview. By introducing more white space into the layout important elements draw the user&amp;rsquo;s attention, allowing the user to focus on call-to-action items and making everything easier to read. In general, alignment has been given an overhaul as well.&lt;/p&gt;
&lt;p&gt;Primary buttons have moved to the right-most side in a button group and the secondary button no longer has a border unless it receives focus or the user hovers on it. This further makes the primary button easier for the eye to catch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/6f5baee0cc0c464799cea3b323ff351f.aspx&quot; width=&quot;800&quot; alt=&quot;Button placement and disabled state in 12.7.0 (left) and 12.2.0 (right)&quot; height=&quot;808&quot; style=&quot;border-style: solid;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;em&gt;Image: Button placement and disabled state in 12.7.0 (left) and 12.2.0 (right)&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Disabled buttons are not transparent anymore. Instead, they have a specific look to them to make sure that they stand out as inactive. For example, a disabled primary button was previously a muted blue that became brighter when enabled. Now the disabled version is instead grey and becomes blue once enabled.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Content Selectors have been reworked to support the user in selecting content without using drag and drop. This was made possible by allowing all content selectors to have a drop-down menu that allows the user to select as well as create content. Drag-n-drop is still present in the UI and the borders of drop zones have been adjusted so that they are coherent and visible.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/b7383116577b428e9e0db0cded611f6c.aspx&quot; width=&quot;1024&quot; alt=&quot;Creating and selecting content in 12.7.0 (left) and 12.2.0 (right)&quot; height=&quot;254&quot; style=&quot;border-style: solid;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;em&gt;Image: Creating and selecting content in 12.7.0 (left) and 12.2.0 (right).&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Multi-targeting .NET 6 and .NET 5&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;As of EPiServer.CMS.UI 12.4.0 our nugets multi-target both .NET 6.0 and .NET 5.0. EPiServer.CMS.TinyMCE 3.2.0 also supports both as well as EPiServer.Telemetry.UI 2.1.0.&lt;/p&gt;
&lt;p&gt;This was a small selection of the many updates that have been made in the UI and as you upgrade you will discover many more. In the coming versions the team will work on more updates, and we are looking forward to your feedback.&lt;/p&gt;
&lt;h2&gt;&lt;b&gt;New support for tiff files&lt;/b&gt;&lt;/h2&gt;
&lt;p&gt;The CMS UI supports tiff files and adds Tiff to &lt;span class=&quot;classLib&quot;&gt;SupportedEditExtensions&lt;/span&gt; list. Currently, tiff is quite an old image extension and It is supported by a few browsers (for example, safari, IE11).&lt;/p&gt;
&lt;h3&gt;What is in the box?&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;On Chrome/other browsers users can:
&lt;ul&gt;
&lt;li&gt;Upload a .tiff image&lt;/li&gt;
&lt;li&gt;Open in Image Editor to edit a .tiff image&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;On Safari/IE11 browser users can:
&lt;ul&gt;
&lt;li&gt;Upload a .tiff image&lt;/li&gt;
&lt;li&gt;DnD a .tiff image into Image property (content reference/content reference list/link item collection/URL to (doc,image, page), XhtmlString, Content Area)&lt;/li&gt;
&lt;li&gt;Open a .tiff image on OPE or All properties mode&lt;/li&gt;
&lt;li&gt;Open in Image Editor to edit a .tiff image&lt;/li&gt;
&lt;li&gt;View a .tiff image on View mode&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Known issues&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Thumbnails in Media gadget have a hard-coded content-type (image/png) in CMS Core, and they are not going to change it. That explains why tiff or ico files don&#39;t show thumbnails.&lt;/li&gt;
&lt;li&gt;We only support *.tiff extension. *.tif is not supported&lt;/li&gt;
&lt;/ul&gt;</id><updated>2022-06-16T14:17:55.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>