<?xml version="1.0" encoding="utf-8"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><language>en</language><title>Blogs</title> <link>https://world.optimizely.com/blogs/</link><description></description><ttl>60</ttl><generator>Optimizely World</generator><item> <title>Integrating a Third-Party DAM into Optimizely CMS 12: A Case Study</title>            <link>https://techhub.iodigital.com/articles/optimizely-cms-third-party-dam-integration</link>            <description>There is no handbook for wiring an external DAM into Optimizely CMS 12. This case study walks through the research, dead ends, and breakthroughs — decompiling the CMP package, extending ContentReferenceEditor, proxy content items, and a custom Assets pane tab — using Wedia as the concrete example.</description>            <guid>https://techhub.iodigital.com/articles/optimizely-cms-third-party-dam-integration</guid>            <pubDate>Tue, 07 Jul 2026 00:00:00 GMT</pubDate>           <category>Blog post</category></item><item> <title>Ringing a Physical Sales Bell from Optimizely Commerce</title>            <link>https://world.optimizely.com/blogs/kennyg/dates/2026/7/ringing-a-physical-sales-bell-from-optimizely-commerce/</link>            <description>&lt;p&gt;This one started as a weekend project that got a little out of hand.&lt;/p&gt;
&lt;p&gt;I built an &amp;ldquo;On Air&amp;rdquo; sign for my office &amp;mdash; one of those LED signs streamers use &amp;mdash; that turns itself on whenever I&amp;rsquo;m in a Teams call or a Zoom meeting, so my family knows not to walk in. It&amp;rsquo;s driven by a cheap TP-Link Kasa smart plug and a bit of PowerShell that watches for a call and flips the plug. Nothing fancy. But once you can turn a plug on and off from code, your brain starts looking for other things that&amp;nbsp;&lt;em&gt;should&lt;/em&gt;&amp;nbsp;turn it on. And if you spend your days in Optimizely Commerce like we do, the answer shows up pretty fast:&amp;nbsp;&lt;strong&gt;every time an order is placed, ring a bell.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Old shops had a bell on the door. Trading floors had an actual bell. There&amp;rsquo;s something motivating about a real, physical signal when money comes in &amp;mdash; the whole team hears it. Modern commerce replaced that with a toast notification nobody looks at. So let&amp;rsquo;s put the bell back, using nothing but an order event and fifteen dollars of hardware.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; everything below is a standalone sample. It depends only on public Optimizely and Microsoft NuGet packages &amp;mdash; nothing from our codebase &amp;mdash; so you can drop the files straight into your own Commerce solution. I built, compiled, and ran it against EPiServer.Commerce.Core 14.45. The same order-event API carries forward to Commerce 15, so it should work there unchanged, but I&#39;ve only tested on 14.&amp;nbsp;&amp;mdash; &lt;strong&gt;IOrderEvents.SavedOrder&lt;/strong&gt;&amp;nbsp;and&amp;nbsp;&lt;strong&gt;OrderEventArgs.OrderGroup&lt;/strong&gt;&amp;nbsp;(an&amp;nbsp;&lt;strong&gt;IPurchaseOrder&lt;/strong&gt;) are the same on both.&lt;/p&gt;
&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;There are three moving parts:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Talk to the plug&lt;/strong&gt;&amp;nbsp;from C#.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;A &amp;ldquo;sales bell&amp;rdquo; that blinks the plug&lt;/strong&gt;&amp;nbsp;&amp;mdash; on a background worker, so it never touches checkout.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;An order-event listener&lt;/strong&gt;&amp;nbsp;that rings the bell when an order is placed.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;A quick word on part 1, because it&amp;rsquo;s the part that surprised me. These plugs used to speak a trivial local protocol over TCP, but newer firmware locked that down, and the usual libraries couldn&amp;rsquo;t authenticate against my account at all &amp;mdash; the handshake just kept failing. The Kasa phone app works fine, though, because it goes through&amp;nbsp;&lt;strong&gt;TP-Link&amp;rsquo;s cloud&lt;/strong&gt;&amp;nbsp;(&lt;strong&gt;wap.tplinkcloud.com&lt;/strong&gt;). So that&amp;rsquo;s what we do too: log in, find the device by its alias, and relay the old&amp;nbsp;&lt;strong&gt;set_relay_state&lt;/strong&gt;&amp;nbsp;command through the cloud&amp;rsquo;s&amp;nbsp;&lt;strong&gt;passthrough&amp;nbsp;&lt;/strong&gt;method. The tradeoff is it needs internet and adds a second or two of latency &amp;mdash; which is exactly why the bell runs in the background and never in the request.&lt;/p&gt;
&lt;h2&gt;Implementation&lt;/h2&gt;
&lt;h3&gt;Talking to the plug&lt;/h3&gt;
&lt;p&gt;The plug client is a straight C# port of the PowerShell from the original project. It logs in once, caches the token and the device&amp;rsquo;s server URL, and re-logs in if a call fails. The one non-obvious bit: TP-Link wants the actual device command as a JSON&amp;nbsp;&lt;em&gt;string&lt;/em&gt;&amp;nbsp;nested inside the request.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public async Task SetAsync(bool on, CancellationToken ct = default)
{
    if (!_opts.Enabled) return;

    // TP-Link expects the legacy device command as a JSON *string* inside requestData.
    var command = $&quot;{{\&quot;system\&quot;:{{\&quot;set_relay_state\&quot;:{{\&quot;state\&quot;:{(on ? 1 : 0)}}}}}}}&quot;;

    for (var attempt = 1; attempt &amp;lt;= 2; attempt++)
    {
        try
        {
            if (_token is null) await ConnectAsync(ct);

            var body = new
            {
                method = &quot;passthrough&quot;,
                @params = new { deviceId = _deviceId, requestData = command }
            };

            var result = await PostAsync($&quot;{_appServerUrl}?token={_token}&quot;, body, ct);
            if (result.GetProperty(&quot;error_code&quot;).GetInt32() != 0)
                throw new InvalidOperationException($&quot;cloud error: {result.GetRawText()}&quot;);

            return;
        }
        catch (Exception ex)
        {
            _log.LogWarning(ex, &quot;Kasa cloud attempt {Attempt} failed&quot;, attempt);
            _token = null; // force a fresh login next time
        }
    }

    _log.LogError(&quot;Kasa plug state not updated after retry&quot;);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;ConnectAsync&lt;/strong&gt;&amp;nbsp;does the&amp;nbsp;&lt;strong&gt;login&amp;nbsp;&lt;/strong&gt;and&amp;nbsp;&lt;strong&gt;getDeviceList&amp;nbsp;&lt;/strong&gt;calls and stashes the&amp;nbsp;&lt;strong&gt;deviceId&amp;nbsp;&lt;/strong&gt;and&amp;nbsp;&lt;strong&gt;appServerUrl&lt;/strong&gt;. It&amp;rsquo;s in the full sample; nothing exciting.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Heads-up if you drop this into an existing Commerce solution:&lt;/strong&gt;&amp;nbsp;many Optimizely sites transitively reference&amp;nbsp;&lt;strong&gt;System.Net.Http.Formatting&lt;/strong&gt;&amp;nbsp;(via&amp;nbsp;&lt;strong&gt;Microsoft.AspNet.WebApi.Client&lt;/strong&gt;), which ships its&amp;nbsp;&lt;em&gt;own&lt;/em&gt;&amp;nbsp;PostAsJsonAsync&amp;nbsp;extension. When it&amp;rsquo;s in scope, the bare&amp;nbsp;&lt;strong&gt;_http.PostAsJsonAsync(url, body, ct)&lt;/strong&gt;&amp;nbsp;becomes ambiguous and won&amp;rsquo;t compile. Fully-qualify the BCL one:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using var response = await System.Net.Http.Json.HttpClientJsonExtensions
    .PostAsJsonAsync(_http, url, body, ct);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A clean standalone project won&amp;rsquo;t hit this &amp;mdash; it only bites when the WebApi.Client extension is also referenced.&lt;/p&gt;
&lt;h3&gt;Keeping it off the checkout path&lt;/h3&gt;
&lt;p&gt;Two rules for anything you bolt onto checkout: it can&amp;rsquo;t slow the order down, and it&amp;nbsp;&lt;em&gt;definitely&lt;/em&gt;&amp;nbsp;can&amp;rsquo;t fail the order. A dead smart plug should never throw an exception up into&amp;nbsp;&lt;strong&gt;SaveAsPurchaseOrder&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;So the bell is completely decoupled. Ringing it just drops a token into a bounded channel &amp;mdash; a fire-and-forget, non-blocking write &amp;mdash; and a background service does the slow part (turn on, wait, turn off) somewhere else entirely.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public sealed class SalesBell : ISalesBell
{
    private readonly ChannelWriter&amp;lt;byte&amp;gt; _writer;
    public SalesBell(Channel&amp;lt;byte&amp;gt; channel) =&amp;gt; _writer = channel.Writer;

    // Non-blocking, never throws. If the queue is full, we just drop the ring.
    public void Ring() =&amp;gt; _writer.TryWrite(0);
}

public sealed class SalesBellWorker : BackgroundService
{
    protected override async Task ExecuteAsync(CancellationToken stoppingToken)
    {
        await foreach (var _ in _reader.ReadAllAsync(stoppingToken))
        {
            try
            {
                using var scope = _scopes.CreateScope();
                var plug = scope.ServiceProvider.GetRequiredService&amp;lt;IKasaPlug&amp;gt;();

                await plug.SetAsync(true, stoppingToken);
                await Task.Delay(TimeSpan.FromSeconds(3), stoppingToken);
                await plug.SetAsync(false, stoppingToken);
            }
            catch (Exception ex) { _log.LogWarning(ex, &quot;Sales bell blink failed&quot;); }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Because the channel is bounded and set to drop when full, a Black-Friday rush can&amp;rsquo;t queue up 4,000 blinks and fall an hour behind &amp;mdash; the light just flickers and drops the overflow. Good enough for a novelty light.&lt;/p&gt;
&lt;h3&gt;Listening for orders&lt;/h3&gt;
&lt;p&gt;Optimizely&amp;rsquo;s order pipeline exposes&amp;nbsp;&lt;strong&gt;IOrderEvents&lt;/strong&gt;&amp;nbsp;(in&amp;nbsp;&lt;strong&gt;EPiServer.Commerce.Order&lt;/strong&gt;). You resolve it from DI and subscribe to&amp;nbsp;&lt;strong&gt;SavedOrder&lt;/strong&gt;. Easy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Gotcha:&lt;/strong&gt;&amp;nbsp;&lt;strong&gt;SavedOrder&amp;nbsp;&lt;/strong&gt;fires on&amp;nbsp;&lt;strong&gt;every&lt;/strong&gt;&amp;nbsp;save of&amp;nbsp;&lt;strong&gt;any&lt;/strong&gt;&amp;nbsp;order group. That includes carts, and it fires again every time an existing order&amp;rsquo;s status changes later. So we guard twice &amp;mdash; only ring for an actual purchase order, and only the first time we&amp;rsquo;ve seen that order.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;private void OnSavedOrder(object? sender, OrderEventArgs e)
{
    // Carts are order groups too &amp;mdash; only ring for a completed purchase order.
    if (e.OrderGroup is not IPurchaseOrder po) return;

    // SavedOrder fires on every later save; only ring on first sight.
    var id = po.OrderLink.OrderGroupId;
    if (Seen.TryGetValue(id, out _)) return;
    Seen.Set(id, true, TimeSpan.FromHours(1));

    _log.LogInformation(&quot;Order {OrderNumber} placed &amp;mdash; ringing the sales bell&quot;, po.OrderNumber);
    _bell.Ring();
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Wiring it up&lt;/h3&gt;
&lt;p&gt;An&amp;nbsp;&lt;strong&gt;IConfigurableModule&lt;/strong&gt;&amp;nbsp;registers everything and subscribes the listener once the site is up. The&amp;nbsp;&lt;strong&gt;ModuleDependency&amp;nbsp;&lt;/strong&gt;on Commerce&amp;rsquo;s initialization module guarantees&amp;nbsp;&lt;strong&gt;IOrderEvents&amp;nbsp;&lt;/strong&gt;is available by the time we ask for it.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[InitializableModule]
[ModuleDependency(typeof(EPiServer.Commerce.Initialization.InitializationModule))]
public sealed class SalesBellModule : IConfigurableModule
{
    public void ConfigureContainer(ServiceConfigurationContext context)
    {
        var services = context.Services;

        services.AddOptions&amp;lt;KasaOptions&amp;gt;()
                .Configure&amp;lt;IConfiguration&amp;gt;((o, cfg) =&amp;gt; cfg.GetSection(&quot;SalesBell&quot;).Bind(o));

        services.AddHttpClient&amp;lt;IKasaPlug, KasaCloudPlug&amp;gt;();

        services.AddSingleton(_ =&amp;gt; Channel.CreateBounded&amp;lt;byte&amp;gt;(
            new BoundedChannelOptions(100) { FullMode = BoundedChannelFullMode.DropWrite }));

        services.AddSingleton&amp;lt;ISalesBell, SalesBell&amp;gt;();
        services.AddHostedService&amp;lt;SalesBellWorker&amp;gt;();
        services.AddSingleton&amp;lt;SalesBellOrderListener&amp;gt;();
    }

    public void Initialize(InitializationEngine context)
        =&amp;gt; context.Locate.Advanced.GetInstance&amp;lt;SalesBellOrderListener&amp;gt;().Subscribe();

    public void Uninitialize(InitializationEngine context)
        =&amp;gt; context.Locate.Advanced.GetInstance&amp;lt;SalesBellOrderListener&amp;gt;().Unsubscribe();
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;One easy-to-miss detail: only&amp;nbsp;&lt;strong&gt;ConfigureContainer&lt;/strong&gt;&amp;nbsp;gets an&amp;nbsp;&lt;strong&gt;IServiceCollection&lt;/strong&gt;.&amp;nbsp;&lt;strong&gt;Initialize&amp;nbsp;&lt;/strong&gt;and&amp;nbsp;&lt;strong&gt;Uninitialize&amp;nbsp;&lt;/strong&gt;receive an&amp;nbsp;&lt;strong&gt;InitializationEngine&lt;/strong&gt;, which has no&amp;nbsp;&lt;strong&gt;.Services&lt;/strong&gt;&amp;nbsp;property &amp;mdash; you resolve through&amp;nbsp;&lt;strong&gt;context.Locate.Advanced.GetInstance&amp;lt;T&amp;gt;()&lt;/strong&gt;&amp;nbsp;instead.&lt;/p&gt;
&lt;p&gt;Config lives in a&amp;nbsp;&lt;strong&gt;SalesBell&amp;nbsp;&lt;/strong&gt;section &amp;mdash; but put the password in Key Vault or DXP configuration, not&amp;nbsp;&lt;strong&gt;appsettings.json&lt;/strong&gt;&amp;nbsp;in source control:&lt;/p&gt;
&lt;pre class=&quot;language-json&quot;&gt;&lt;code&gt;{
  &quot;SalesBell&quot;: {
    &quot;Username&quot;: &quot;you@example.com&quot;,
    &quot;Password&quot;: &quot;keep-me-in-key-vault&quot;,
    &quot;DeviceAlias&quot;: &quot;On Air Lamp&quot;,
    &quot;Enabled&quot;: true
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;That&amp;nbsp;&lt;strong&gt;&quot;Enabled&quot;: false&lt;/strong&gt;&amp;nbsp;is worth setting in your Integration and Preproduction environments &amp;mdash; otherwise a QA test order or a load test will strobe a light in a dark office at 2&amp;nbsp;a.m. Ask me how I know.&lt;/p&gt;
&lt;h2&gt;A few things to watch&lt;/h2&gt;
&lt;p&gt;A couple of honest caveats, because this is a novelty bolted onto a real checkout:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;It&amp;rsquo;s an unofficial API.&lt;/strong&gt;&amp;nbsp;&lt;strong&gt;wap.tplinkcloud.com&lt;/strong&gt;&amp;nbsp;is reverse-engineered &amp;mdash; the same path the Kasa app uses, but TP-Link could change it. Treat the bell as best-effort; the code already swallows every failure.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The success check is shallow &amp;mdash; on purpose.&lt;/strong&gt;&amp;nbsp;&lt;strong&gt;SetAsync&lt;/strong&gt;&amp;nbsp;inspects&amp;nbsp;&lt;strong&gt;error_code&lt;/strong&gt;&amp;nbsp;on the&amp;nbsp;&lt;em&gt;outer&lt;/em&gt;&amp;nbsp;cloud envelope, which only tells you TP-Link accepted and relayed your&amp;nbsp;&lt;strong&gt;passthrough&amp;nbsp;&lt;/strong&gt;request. The device&amp;rsquo;s own response is nested as a JSON string inside&amp;nbsp;&lt;strong&gt;result.responseData&lt;/strong&gt;, and we don&amp;rsquo;t crack it open &amp;mdash; so &amp;ldquo;success&amp;rdquo; means&amp;nbsp;&lt;em&gt;the cloud took the command&lt;/em&gt;, not&amp;nbsp;&lt;em&gt;the relay physically flipped&lt;/em&gt;. Fine for a novelty bell; don&amp;rsquo;t reuse this client where you need to confirm device state.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You probably run more than one node.&lt;/strong&gt;&amp;nbsp;On DXP each instance gets the&amp;nbsp;&lt;strong&gt;SavedOrder&lt;/strong&gt;&amp;nbsp;event, so each will try to ring. Either accept the extra cloud calls (harmless), gate ringing to one designated node, or move the bell behind a single small service. Your mileage may vary depending on your topology.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Throttle the strobe.&lt;/strong&gt;&amp;nbsp;The bounded channel keeps things from backing up, but during a real rush you may want one blink per&amp;nbsp;&lt;em&gt;N&lt;/em&gt;&amp;nbsp;orders instead of one per order. Nobody needs a strobe light.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The de-dupe is per-instance.&lt;/strong&gt;&amp;nbsp;The in-memory cache is fine for a light. If you need it exact across a farm, back it with distributed cache or key off the order&amp;rsquo;s status transition.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The fun part is that once&amp;nbsp;&lt;strong&gt;_bell.Ring()&lt;/strong&gt;&amp;nbsp;is a single line, the plug stops caring&amp;nbsp;&lt;em&gt;why&lt;/em&gt;&amp;nbsp;it fired. Swap the bell for a color-changing bulb (green for a sale, red for a failed payment), point it at a different event &amp;mdash; a first sale of the day, an order over some threshold, a low-stock SKU &amp;mdash; and you&amp;rsquo;ve given your Optimizely site a little presence in the physical world.&lt;/p&gt;
&lt;p&gt;The code above &lt;em&gt;is&lt;/em&gt; the sample &amp;mdash; it compiles and runs clean against Commerce 14 with nothing from any particular site, so you can drop the files straight in (the order-event API is unchanged in 15, though I&amp;rsquo;ve only run it on 14). The original Teams/Zoom &amp;ldquo;On Air&amp;rdquo; sign it grew out of &amp;mdash; the PowerShell watcher and smart-plug script &amp;mdash; is on GitHub: &lt;a href=&quot;https://github.com/kennygutierrez/on-air-sign&quot;&gt;github.com/kennygutierrez/on-air-sign&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thoughts, comments, concerns? Let me know below.&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/kennyg/dates/2026/7/ringing-a-physical-sales-bell-from-optimizely-commerce/</guid>            <pubDate>Mon, 06 Jul 2026 21:03:58 GMT</pubDate>           <category>Blog post</category></item><item> <title>Exploring Asset Lifecycle Management Approaches for Bynder and Optimizely SaaS CMS</title>            <link>https://world.optimizely.com/blogs/vipin-banka--learnings--insights/dates/2026/7/exploring-asset-lifecycle-management-approaches-for-bynder-and-optimizely-saas-cms/</link>            <description>&lt;p&gt;&lt;span class=&quot;far4bl _667h42&quot;&gt;Note: This is Part 3 of our Bynder integration series. For setup and filtering prerequisites, see &lt;a class=&quot;_667h42 _1l4j4nac _1c9dtv3 _1by2b93 _1140xq1 _667h42&quot; href=&quot;/link/4f215cd334254dfcbc121d5f4e20edd6.aspx&quot;&gt;Part 1&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a class=&quot;_667h42 _1l4j4nac _1c9dtv3 _1by2b93 _1140xq1 _667h42&quot; href=&quot;/link/30275ac47c4843148eeda8b7d6ed282a.aspx&quot;&gt;Part 2&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;In my previous article, I explored approaches for controlling asset ingestion from Bynder into Optimizely SaaS CMS through metadata-based filtering.&lt;/p&gt;
&lt;p&gt;Filtering assets before they enter the platform is an important first step, but in many enterprise DAM integrations, it only addresses part of the lifecycle.&lt;/p&gt;
&lt;p&gt;Once assets have been synchronized, a different set of challenges begins to emerge:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What happens when an asset&#39;s metadata changes after synchronization?&lt;/li&gt;
&lt;li&gt;How should previously synchronized assets be handled when they no longer meet business rules?&lt;/li&gt;
&lt;li&gt;How can organizations govern assets across Development, Staging, and Production environments?&lt;/li&gt;
&lt;li&gt;How can teams safely determine whether an asset is still being used before removing it?&lt;/li&gt;
&lt;li&gt;When does it make sense to extend an existing integration versus building a completely custom connector?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These questions gradually shift the conversation from asset synchronization to asset lifecycle management.&lt;/p&gt;
&lt;p&gt;This article explores some architectural considerations and potential approaches that may help address those challenges.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;&lt;strong&gt;The Asset Lifecycle Challenge&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Synchronization is rarely a one-time event.&amp;nbsp;Assets constantly evolve throughout their lifetime.&amp;nbsp;&lt;br /&gt;A typical lifecycle might look something like this:&lt;/p&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-7100fui-FluentProviderr6av ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-681&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;strong&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Asset Created&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Asset Synchronized&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Asset Referenced by Content&amp;nbsp; &amp;gt;&amp;nbsp; Asset &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Metadata Updated&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Visibility Rules Changed&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Environment Assignment Changed&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Asset No Longer Valid&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;Most DAM integrations handle the first half of this journey very well.&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;The second half is often where complexity starts to appear.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;An image may no longer belong to a target environment.&lt;/li&gt;
&lt;li&gt;An image may become hidden through metadata changes.&lt;/li&gt;
&lt;li&gt;An image may remain inside Optimizely despite no longer being available within Bynder.&lt;/li&gt;
&lt;li&gt;An image may still be actively referenced by content authors even though business rules indicate it should be removed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These scenarios introduce governance challenges that extend well beyond initial synchronization.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;&lt;strong&gt;Orphaned Assets&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;One scenario that stood out during evaluation was the possibility of orphaned assets.&lt;/p&gt;
&lt;p&gt;Consider the following sequence:&lt;/p&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-6816fui-FluentProviderr6b8 ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-682&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;strong&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Asset synchronized&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Metadata changes&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Asset moves out of scope&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Synchronization account &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;can no longer access asset&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Asset remains in Optimizely&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;From the perspective of the synchronization process, the asset has effectively disappeared.&lt;/p&gt;
&lt;p&gt;The integration can no longer retrieve information about the asset.&lt;/p&gt;
&lt;p&gt;However, the existing record may continue to exist inside Optimizely.&lt;/p&gt;
&lt;p&gt;Over time, these records could accumulate, creating a divergence between the source DAM and the target CMS repository.&lt;/p&gt;
&lt;p&gt;While this may not create an immediate problem, organizations with large asset libraries may eventually start asking:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Which assets are still valid?&lt;/li&gt;
&lt;li&gt;Which assets should still exist?&lt;/li&gt;
&lt;li&gt;Which assets are no longer governed by the current synchronization rules?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These questions become increasingly important as repositories grow.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;&lt;strong&gt;Environment Governance&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Another consideration involves environment ownership.&lt;/p&gt;
&lt;p&gt;Most enterprise implementations maintain separate environments:&lt;/p&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-1565fui-FluentProviderr6bh ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-683&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Development&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Staging&lt;/li&gt;
&lt;li&gt;Production&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;However, DAM platforms are often centrally managed.&lt;/p&gt;
&lt;p&gt;A common scenario looks something like this:&lt;/p&gt;
&lt;p&gt;&lt;img style=&quot;border-width: 1px; border-style: solid;&quot; src=&quot;/link/4c2f0e70051d44828bb2530d6be7e584.aspx&quot; alt=&quot;&quot; width=&quot;722&quot; height=&quot;482&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Without additional controls, all environments may receive identical assets.&lt;/p&gt;
&lt;p&gt;This can introduce several concerns:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Increased storage consumption&lt;/li&gt;
&lt;li&gt;Cluttered non-production environments&lt;/li&gt;
&lt;li&gt;Difficult testing scenarios&lt;/li&gt;
&lt;li&gt;Confusion around environment-specific assets&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;Suggested Environment Metadata Approach&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;One possible approach is introducing an additional metadata property or use tags inside Bynder.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;&quot;website-environment&quot; metadata property with p&lt;/span&gt;ossible values:&lt;/p&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-9217fui-FluentProviderr6cc ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-686&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;ul&gt;
&lt;li class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Development&lt;/span&gt;&lt;/li&gt;
&lt;li class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Staging&lt;/span&gt;&lt;/li&gt;
&lt;li class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Production&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This metadata could travel alongside normal asset synchronization and provide additional governance information to downstream systems.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Suggested Visibility Configuration&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Unlike visibility-based filtering rules, this property/tags does not need to setup separate profiles/users and any explicit filtering rules.&lt;/p&gt;
&lt;p&gt;The goal is not to hide assets. The goal is to communicate intent.&lt;/p&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-2862fui-FluentProviderr6cu ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-688&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;For example: If an asset that is tagged for development environment received in production environement then that asset should be treated as out of scope and vice versa for other environments.&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;Asset target Environment: Development&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;Asset Synced in: Production&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;Result: Potentially Out of Scope&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;scriptor-highlightWrapper&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;
&lt;div&gt;With this approach, a centralized DAM repository can continue serving multiple environments while still supporting environment-specific governance decisions.&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;h2&gt;&lt;strong&gt;Why Environment Metadata May Be Valuable&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Without environment metadata, every environment receives same assets.&lt;/p&gt;
&lt;p&gt;With environment metadata, environment validation processes can be setup to stop storing assets those are not required in the environment.&lt;/p&gt;
&lt;p&gt;This approach may provide a lightweight governance layer without introducing separate DAM repositories, separate taxonomies, or separate synchronization configurations.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;&lt;strong&gt;Architectural Note&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The workflow described in the following sections represents an architectural approach that emerged during the evaluation of lifecycle management challenges associated with large-scale DAM integrations.&lt;/p&gt;
&lt;p&gt;While the individual platform capabilities required for this model&amp;mdash;including Bynder webhooks, permanent access tokens, Optimizely Graph/Content Management APIs, and Optimizely Graph reference queries&amp;mdash; are available today, the complete end-to-end workflow has not yet been fully validated in a production implementation.&lt;/p&gt;
&lt;p&gt;The intent of this article is to explore a potential governance pattern and discuss its trade-offs rather than present a proven production architecture.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;&lt;strong&gt;Exploring an Event-Driven Governance Model&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;One approach that appears interesting from an architectural perspective is introducing a webhook-driven governance workflow.&lt;/p&gt;
&lt;p&gt;For simplicity, this article assumes the webhook endpoint is deployed inside the frontend nextjs application.&lt;/p&gt;
&lt;p&gt;In practice, the webhook could be hosted anywhere:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Next.js API Route&lt;/li&gt;
&lt;li&gt;Azure Function&lt;/li&gt;
&lt;li&gt;AWS Lambda&lt;/li&gt;
&lt;li&gt;Google Cloud Function&lt;/li&gt;
&lt;li&gt;Dedicated Middleware Service&lt;/li&gt;
&lt;li&gt;Integration Platform&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The location itself is less important than the validation process being executed.&lt;/p&gt;
&lt;p&gt;At a high level:&lt;/p&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-1675fui-FluentProviderr6dp ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-691&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;strong&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Bynder Calls Webhook&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Webhook Receives event&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Validation Logic&amp;nbsp; &amp;gt;&amp;nbsp; Asset remains or Deleted&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;strong&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;&lt;img style=&quot;border-width: 1px; border-style: solid;&quot; src=&quot;/link/6924927432474ebbbf0173898da1d109.aspx?1783236197175&quot; width=&quot;575&quot; height=&quot;699&quot; /&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-1955fui-FluentProviderr6e2 ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-692&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;scriptor-code-scroll-proxy&quot;&gt;
&lt;h2&gt;&lt;strong&gt;Three Gates&lt;/strong&gt;&lt;/h2&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;&lt;strong&gt;Gate 1: Visibility Validation&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The first validation stage could determine whether the asset remains visible to the synchronization account.&lt;br /&gt;Note: Use permanent token assigned for the synchronization account.&lt;/p&gt;
&lt;p&gt;Conceptually:&lt;/p&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-2459fui-FluentProviderr6eb ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-693&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Asset Updated&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Retrieve Asset&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Accessible&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;Decision&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-5518fui-FluentProviderr6ek ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-694&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Decision&amp;nbsp; &amp;gt;&amp;nbsp; YES&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Continue&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Decision&amp;nbsp; &amp;gt;&amp;nbsp; NO&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Potential Cleanup Candidate&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;The objective is not necessarily to delete the asset immediately. Instead, the objective is to determine whether the asset still falls within the intended synchronization scope. If visibility has changed, additional evaluation may be required.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;Gate 2: Environment Validation&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;The second validation stage could evaluate environmental ownership.&lt;/p&gt;
&lt;p&gt;Example workflow:&lt;/p&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-5562fui-FluentProviderr6et ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-695&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Asset Updated&amp;nbsp; &amp;gt; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Read website-environment&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Compare Against &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Current Environment&amp;nbsp; &amp;gt; &lt;/span&gt;Decision:&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-2919fui-FluentProviderr6f6 ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;CDXiecnD7ekDByb7Z+4oEA==&quot;&gt;
&lt;div class=&quot;r14iuplo fui-AriaLive__assertive&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Decision&amp;nbsp; &amp;gt;&amp;nbsp; Match&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Continue&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; Decision&amp;nbsp; &amp;gt;&amp;nbsp; No Match&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Potential Cleanup Candidate&lt;/span&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This allows governance decisions to be made without requiring separate DAM repositories.&lt;/p&gt;
&lt;p&gt;An asset intended exclusively for Production could potentially be excluded from lower environments while remaining available in Production.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;Gate 3: Reference Validation&lt;/strong&gt;&lt;/h3&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;Before any removal occurs, a critical question must be answered: &lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;Is the asset still being used?&lt;/strong&gt;&lt;/div&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;Optimizely Graph does not currently expose a built-in reverse-reference lookup operator. This means there is no single, generic query to answer &quot;which content items reference this asset?&quot; without knowledge of the content model.&lt;/div&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;Possible implementation approaches include:&lt;/strong&gt;&lt;/div&gt;
&lt;ol class=&quot;_667h42 _1l4j4na7&quot;&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot;&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;Full-text search&lt;/strong&gt;&amp;nbsp;&amp;mdash; Query&amp;nbsp;&lt;code class=&quot;_667h42 _1l4j4na5&quot;&gt;Content&lt;/code&gt;&amp;nbsp;using&amp;nbsp;&lt;code class=&quot;_667h42 _1l4j4na5&quot;&gt;_fulltext: { match: &quot;asset-id&quot; }&lt;/code&gt;&amp;nbsp;to search across all indexed content. Quick but imprecise &amp;mdash; depends on how asset IDs are indexed.&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot;&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;Schema introspection + targeted queries&lt;/strong&gt;&amp;nbsp;&amp;mdash; Use GraphQL introspection to discover all content types with reference-type fields, then query each one. More thorough but requires automation to be practical.&lt;/div&gt;
&lt;/li&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot;&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;Content Management API enumeration&lt;/strong&gt;&amp;nbsp;&amp;mdash; Use the CMS REST API to walk content and check references programmatically.&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;The right approach depends on your content model complexity, performance requirements, and how frequently this validation runs.&amp;nbsp;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;This gate will likely require a custom implementation tailored to your environment.&lt;/strong&gt;&lt;/div&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;Deleting Assets from Optimizely&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Once an asset has been evaluated, a governance process may decide that removal should occur.&lt;/p&gt;
&lt;p&gt;Important questions include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Is the asset still visible?&lt;/li&gt;
&lt;li&gt;Is the asset assigned to the current environment?&lt;/li&gt;
&lt;li&gt;Is the asset actively referenced?&lt;/li&gt;
&lt;li&gt;Should the asset remain synchronized?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If all validation checks indicate removal is appropriate, a deletion request could be submitted through the Content Management API.&lt;/p&gt;
&lt;p&gt;An important distinction exists between: &lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Soft Delete vs &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Hard Delete&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;For lifecycle-management scenarios, hard deletion may be more relevant because the objective is often to reduce repository footprint rather than move content into a recycle state.&lt;/p&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-9961fui-FluentProviderr6gs ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;CDXiecnD7ekDByb7Z+4oEA==&quot;&gt;
&lt;div class=&quot;r14iuplo fui-AriaLive__assertive&quot;&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100.013%; margin-left: 0px; border-width: 1px; border-style: solid; margin-right: auto;&quot;&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10.9517%; text-align: left; vertical-align: top; border-style: solid; border-width: 1px;&quot;&gt;&lt;strong&gt;Url &amp;amp; Headers&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 89.0357%; text-align: left; vertical-align: top; border-style: solid; border-width: 1px;&quot;&gt;
&lt;div class=&quot;_47QlA7XYWbfK2INfVvTUjg==&quot;&gt;
&lt;div class=&quot;iVmNpJv5Hu1Eu0ev0L3Ffg==&quot;&gt;
&lt;div class=&quot;KU8Z3uOm5OU11Ica53+OVA==&quot;&gt;
&lt;div class=&quot;fui-Overflow Ye6tJij6H1xMCTdS6F25rA== ___s5d2bt0 f3x039c facid5&quot;&gt;
&lt;div class=&quot;vCHKFE0-MqMN20DBXhx6Ow==&quot;&gt;
&lt;div class=&quot;fui-Badge r1p3wql8 _9liocQIfHYrfQrOa5IZ50A== ___engtnk0 f1soahph fyk0x7v f17ad7pc f1evqen2 f70w86f fmfhf0j f1ar0y7c f1fzzbuc f176ju0o&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
POST /api/content/v2/data?id=bynd HTTP/1.1&lt;br /&gt;Host: cg.optimizely.com&lt;br /&gt;Content-Type: application/x-ndjson&lt;br /&gt;Authorization: Basic V25KQmNtUlpSNTFYaDJuSmE1UWV5eEkwWW...[Your_Base64_Encoded_Credentials]&lt;br /&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-702&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10.9517%; text-align: left; vertical-align: top; border-style: solid; border-width: 1px;&quot;&gt;&lt;strong&gt;Body&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 89.0357%; text-align: left; vertical-align: top; border-style: solid; border-width: 1px;&quot;&gt;{&quot;delete&quot;:{&quot;_id&quot;:&quot;bynder-asset-guid-12345&quot;,&quot;language_routing&quot;:&quot;en&quot;}}&lt;br /&gt;{}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;width: 10.9517%; text-align: left; vertical-align: top; border-style: solid; border-width: 1px;&quot;&gt;&lt;strong&gt;Response&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;width: 89.0357%; text-align: left; vertical-align: top; border-style: solid; border-width: 1px;&quot;&gt;{&lt;br /&gt;&amp;nbsp; &quot;status&quot;: &quot;success&quot;,&lt;br /&gt;&amp;nbsp; &quot;total_records_processed&quot;: 1,&lt;br /&gt;&amp;nbsp; &quot;deleted&quot;: 1,&lt;br /&gt;&amp;nbsp; &quot;errors&quot;: [],&lt;br /&gt;&amp;nbsp; &quot;took&quot;: 42&lt;br /&gt;}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;_47QlA7XYWbfK2INfVvTUjg==&quot;&gt;
&lt;div class=&quot;iVmNpJv5Hu1Eu0ev0L3Ffg==&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-702&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;This would permanently remove the asset rather than transferring it into a recycle bin.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;&lt;strong&gt;Monitoring and Troubleshooting&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Whenever automated deletion is introduced, observability becomes extremely important.&lt;/p&gt;
&lt;p&gt;Questions that operations teams will eventually ask include:&lt;/p&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-868fui-FluentProviderr6h5 ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-703&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;ol&gt;
&lt;li class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Was a delete triggered?&lt;/span&gt;&lt;/li&gt;
&lt;li class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Which rule triggered it?&lt;/span&gt;&lt;/li&gt;
&lt;li class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Which asset was deleted?&lt;/span&gt;&lt;/li&gt;
&lt;li class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;When did it occur?&lt;/span&gt;&lt;/li&gt;
&lt;li class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;What response was returned?&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;A potential audit trail might capture:&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Asset identifier&lt;/li&gt;
&lt;li&gt;Event timestamp&lt;/li&gt;
&lt;li&gt;Validation results&lt;/li&gt;
&lt;li&gt;Environment&lt;/li&gt;
&lt;li&gt;API response&lt;/li&gt;
&lt;li&gt;Deletion outcome&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;strong&gt;Monitoring Deletion Activity&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;One area that would require validation during implementation is how deletion activity can be monitored within the platform.&lt;/p&gt;
&lt;p&gt;A potential starting point would be reviewing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Search &amp;amp; Navigation portal logs&lt;/li&gt;
&lt;li&gt;Graph activity logs&lt;/li&gt;
&lt;li&gt;API diagnostics&lt;/li&gt;
&lt;li&gt;Application telemetry&lt;/li&gt;
&lt;li&gt;Hosting platform logs&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This would help determine whether delete operations are executing successfully and provide additional visibility during troubleshooting.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;&lt;strong&gt;Extending the Existing Integration vs Building a Custom Connector&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;A natural question that often emerges is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;If lifecycle governance is required, should we simply build a custom connector?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The answer depends on organizational priorities.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 79.5271%; border-width: 1px; height: 368.425px; border-spacing: 5px; border-style: solid;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 57.625px;&quot;&gt;
&lt;td style=&quot;text-align: left; vertical-align: top; border-width: 1px; width: 50.4919%; padding: 1px; border-style: solid; height: 57.625px;&quot;&gt;
&lt;h4&gt;&lt;strong&gt;Option 1: Extend the Existing Integration&lt;/strong&gt;&lt;/h4&gt;
&lt;/td&gt;
&lt;td style=&quot;text-align: left; vertical-align: top; border-width: 1px; width: 49.4881%; padding: 1px; border-style: solid; height: 57.625px;&quot;&gt;
&lt;h4&gt;&lt;strong&gt;Option 2: Build a Fully Custom Connector&lt;/strong&gt;&lt;/h4&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 310.8px;&quot;&gt;
&lt;td style=&quot;text-align: left; vertical-align: top; border-width: 1px; width: 50.4919%; padding: 1px; border-style: solid; height: 310.8px;&quot;&gt;
&lt;p&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Bynder&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;OOTB Connector&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Optimizely &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;+ Governance Layer&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Advantages:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Faster implementation&lt;/li&gt;
&lt;li&gt;Lower maintenance overhead&lt;/li&gt;
&lt;li&gt;Vendor-supported synchronization&lt;/li&gt;
&lt;li&gt;Smaller operational footprint&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Potential limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Less control over synchronization internals&lt;/li&gt;
&lt;li&gt;Dependency on platform capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td style=&quot;text-align: left; vertical-align: top; border-width: 1px; width: 49.4881%; padding: 1px; border-style: solid; height: 310.8px;&quot;&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-9357fui-FluentProviderr6hn ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-705&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Bynder&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Custom Connector&amp;nbsp; &amp;gt;&amp;nbsp; &lt;/span&gt;&lt;span class=&quot;scriptor-textRun scriptor-inline&quot;&gt;Optimizely&lt;/span&gt;&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;div class=&quot;scriptor-paragraph&quot;&gt;Advantages:&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;Complete control&lt;/li&gt;
&lt;li&gt;Custom business logic&lt;/li&gt;
&lt;li&gt;Full synchronization ownership&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Potential considerations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Authentication management&lt;/li&gt;
&lt;li&gt;Delta synchronization&lt;/li&gt;
&lt;li&gt;Retry handling&lt;/li&gt;
&lt;li&gt;Error recovery&lt;/li&gt;
&lt;li&gt;Schema evolution&lt;/li&gt;
&lt;li&gt;Long-term maintenance costs&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;___77lcry0 f10pi13n&quot;&gt;
&lt;div class=&quot;___1hewfwb f10pi13n f7oukh6 f5p0z4x&quot;&gt;
&lt;div class=&quot;fui-FluentProvider codeBlock-3356fui-FluentProviderr6he ___1jk74h0 fzk5nv6 f6n0el9 f7x6x6c f1a9mlr7 flj889f f13g0yyb ffzn0d2&quot;&gt;
&lt;div class=&quot;scriptor-component-code-block NhtKn7PZLzk24rduw4FJVQ== scriptor-codeblock-virtualized&quot;&gt;
&lt;div class=&quot;UkrLoQNicnNa5hsNIz3QLw== SpjJXGAclwYtfY+SokpSTg== ZF-Q2MvOY8aWSpGWW7iKRQ== anUhzybDvd7+8CBdKK7ukg==&quot;&gt;
&lt;div class=&quot;AHKpBuU8t+rAbDNImLlOHQ== lHY5JJVFnU8S-jx-OGwJkg== IUtI8YkF5Dl2LTlcjMDTwg==&quot;&gt;
&lt;div class=&quot;___149cboo fssjx5q f11d9hfk fj2zk3l fmyxm6j f1ldmben f1rkeeuc&quot;&gt;
&lt;div class=&quot;___svqwvq0 fssjx5q f11d9hfk fj2zk3l f1ldmben fzdgvog f19k5jia fzv833z f1r8x5cv f1687457 fe71wc6 f1wco4xj f103jgab f12fk6ok f4j985t fv86erk f1b4dd42 f1qwtq3x f13gvrpj f132if0v f1vblqk2 fkxsc7s f18j3zqo f1386a7m f1w3nze9 f14pe09c f4skf1h f1lq0dgc f1jgwha3 fbf5vau fc8703c&quot;&gt;
&lt;div class=&quot;___ysqij10 fonrc96 f1d3un5n fdk4ulh f1cijgmw fzb3wgo fssjx5q f11d9hfk fee5icb fr1uqzy&quot;&gt;
&lt;div class=&quot;___sv9ola0 fj2zk3l f1f4vkoj scriptor-instance-704&quot;&gt;
&lt;div class=&quot;scriptor-canvas scriptor-styled-scrollbar focus-container&quot;&gt;
&lt;div class=&quot;scriptor-pageContainer&quot;&gt;
&lt;div class=&quot;scriptor-pageFrame scriptor-firstPage scriptor-webView scriptor-content-visibility-auto&quot;&gt;
&lt;div class=&quot;scriptor-code-editor scriptor-code-wrap-on scriptor-pageBody scriptor-webViewPage&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;For many organizations, extending an existing integration with additional governance capabilities may represent a more balanced approach than replacing the synchronization engine altogether.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;&lt;strong&gt;Assumptions and Validation Status&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The approaches discussed throughout this article are based on architectural evaluation and platform capability analysis rather than a fully validated production implementation.&lt;/p&gt;
&lt;p&gt;At the time of writing, the proposed event-driven webhook model remains an architectural concept that appears technically achievable based on the currently available capabilities of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Bynder webhooks&lt;/li&gt;
&lt;li&gt;Bynder permanent tokens&lt;/li&gt;
&lt;li&gt;Optimizely Content Management /Graph APIs&lt;/li&gt;
&lt;li&gt;Optimizely Graph reference lookups&lt;/li&gt;
&lt;li&gt;Standard event-driven integration patterns&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;However, several areas would benefit from additional validation before adoption within a production environment:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Large-scale webhook processing behavior&lt;/li&gt;
&lt;li&gt;API rate limiting and throttling characteristics&lt;/li&gt;
&lt;li&gt;Long-running operational reliability&lt;/li&gt;
&lt;li&gt;Deletion timing and synchronization race conditions&lt;/li&gt;
&lt;li&gt;Monitoring and alerting strategies&lt;/li&gt;
&lt;li&gt;Reconciliation requirements for lost events&lt;/li&gt;
&lt;li&gt;Long-term maintenance implications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As with any architectural pattern, organizations should conduct their own validation, performance testing, and operational reviews before implementing the approach within production workloads.&lt;/p&gt;
&lt;div&gt;&lt;hr /&gt;
&lt;h2&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Asset synchronization is only one stage in the lifecycle of an enterprise DAM integration.&lt;/p&gt;
&lt;p&gt;As asset repositories grow, organizations may also need to consider how visibility changes, environment allocation, content relationships, and cleanup processes should be handled over time.&lt;/p&gt;
&lt;p&gt;The approaches discussed in this article should be viewed as architectural considerations rather than implementation recommendations. While the proposed event-driven governance model appears technically feasible based on the capabilities provided by Bynder, Optimizely SaaS CMS, and Optimizely Graph, additional validation and testing would be required before considering it for production adoption.&lt;/p&gt;
&lt;p&gt;Ultimately, long-term success is unlikely to depend solely on controlling what enters the system. It may also require thoughtful approaches to governing assets throughout their lifecycle&amp;mdash;from synchronization and distribution through validation, retention, and eventual removal.&lt;/p&gt;
&lt;hr /&gt;
&lt;h4 class=&quot;_1l4j4na1 _1qskm0h c8urk _1a0p899 _5hqrjx _667h42&quot;&gt;&#128218; Bynder + Optimizely SaaS CMS Integration Series&lt;/h4&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;This article is the final installment of a 3-part comprehensive architecture guide:&lt;/em&gt;&lt;/div&gt;
&lt;ul class=&quot;_667h42 _1l4j4na6&quot;&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;✅ Part 1:&amp;nbsp;&lt;a class=&quot;_667h42 _1l4j4nac _1c9dtv3 _1by2b93 _1140xq1 _667h42&quot; href=&quot;/link/4f215cd334254dfcbc121d5f4e20edd6.aspx&quot;&gt;Implementing the Connector &amp;mdash; Lessons Learned&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;What metadata syncs, how URLs behave, and how to query/render assets in a Next.js frontend.&lt;br /&gt;&lt;br /&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;✅ Part 2:&amp;nbsp;&lt;a class=&quot;_667h42 _1l4j4nac _1c9dtv3 _1by2b93 _1140xq1 _667h42&quot; href=&quot;/link/30275ac47c4843148eeda8b7d6ed282a.aspx&quot;&gt;Planning &amp;amp; Filtering &amp;mdash; Avoiding Asset Sprawl and Unnecessary Sync&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;How we achieved metadata-based sync filtering with zero custom code.&lt;br /&gt;&lt;br /&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;&#128073; Part 3: Exploring Asset Lifecycle Management &amp;amp; Three-Gate Governance&lt;/strong&gt;&amp;nbsp;&lt;em class=&quot;far4bl _667h42&quot;&gt;(You are here)&lt;/em&gt;&lt;br /&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;A webhook-driven, three-gate model to handle asset updates, environments, and usage verification.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</description>            <guid>https://world.optimizely.com/blogs/vipin-banka--learnings--insights/dates/2026/7/exploring-asset-lifecycle-management-approaches-for-bynder-and-optimizely-saas-cms/</guid>            <pubDate>Sun, 05 Jul 2026 07:44:36 GMT</pubDate>           <category>Blog post</category></item><item> <title>Unlock AI-Ready Experiences with Optimizely</title>            <link>https://madhuanbalagan.com/?p=5026</link>            <description>&lt;p&gt;Over the past few months, almost every customer conversation has shifted from SEO to AI readiness. The questions are no longer just: &amp;#8220;How do we&amp;#46;&amp;#46;&amp;#46;&lt;/p&gt;
&lt;p&gt;The post &lt;a href=&quot;https://madhuanbalagan.com/unlock-ai-ready-experiences-with-optimizely&quot;&gt;Unlock AI-Ready Experiences with Optimizely&lt;/a&gt; appeared first on &lt;a href=&quot;https://madhuanbalagan.com&quot;&gt;Madhu Anbalagan&amp;#039;s Blog&lt;/a&gt;.&lt;/p&gt;
</description>            <guid>https://madhuanbalagan.com/?p=5026</guid>            <pubDate>Sun, 05 Jul 2026 05:40:14 GMT</pubDate>           <category>Blog post</category></item><item> <title>Planning Your Bynder DAM and Optimizely SaaS CMS Integration the Right Way: Avoiding Asset Sprawl and Unnecessary Synchronization</title>            <link>https://world.optimizely.com/blogs/vipin-banka--learnings--insights/dates/2026/7/planning-your-bynder-dam-integration-for-optimizely-saas-cms-avoiding-asset-sprawl-managing-costs-and-designing-for-scale/</link>            <description>&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span class=&quot;far4bl _667h42&quot;&gt;Note: This is Part 2 of our Bynder integration series. If you missed the Part 1, check out &quot;&lt;a href=&quot;/link/4f215cd334254dfcbc121d5f4e20edd6.aspx&quot;&gt;Implementing the Bynder DAM Connector with Optimizely SaaS CMS: Lessons Learned&lt;/a&gt;&quot;.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In my previous article, I explored how the Bynder DAM Connector integrates with Optimizely SaaS CMS and how synchronized assets become available through Optimizely Graph and the CMS authoring experience.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This article focuses specifically on the Out-of-the-Box (OOTB) Bynder Connector available through Optimizely Connect Platform (OCP). The goal is to understand how much control can be achieved using standard Optimizely and Bynder capabilities before introducing custom integrations, middleware, or synchronization processes.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;While the technical setup of the OOTB connector is relatively straightforward, I discovered that the most important decisions actually happen&amp;nbsp;&lt;em&gt;before&lt;/em&gt; the first synchronization is ever executed.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Many implementation teams focus on establishing the connection between Bynder and Optimizely. However, a more important architectural question is:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;What assets should Optimizely be allowed to see in the first place?&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;For organizations that use Bynder as a centralized Digital Asset Management platform, the answer has significant implications for governance, editor experience, operational overhead, and long-term scalability.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This article focuses on the planning and governance considerations that should be addressed before enabling the Bynder connector.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Understanding the Default Connector Behavior&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The Out-of-the-Box (OOTB) Bynder connector synchronizes assets that are visible to the authenticated Bynder account.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In simple terms, the connector does not determine which assets should be synchronized. Bynder determines that by evaluating the permissions of the account used during the authorization process.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;As a result, the overall scope of synchronization is directly influenced by:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l10 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;The permission profile assigned to the integration account&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l10 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Asset visibility settings within Bynder&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l10 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Metadata visibility rules&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l10 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;The account used during connector authorization&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The connector can only synchronize assets that the authenticated account can access.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This seemingly simple behavior becomes extremely important when working with large DAM implementations.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Why Asset Scope Matters&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In many organizations, Bynder contains assets for multiple business functions and audiences.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Examples include:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Website assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Campaign assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Product photography&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Internal communications&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Regional marketing materials&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Archived content&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Partner-specific assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Brand assets&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Not all of these assets are intended for websites powered by Optimizely.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Without careful planning, the connector can synchronize substantially more assets than editors actually need.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;At first glance this may not appear to be a major concern. However, every synchronized asset becomes another content item managed by the Optimizely ecosystem.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;As synchronization volume grows:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l12 level1 lfo3; tab-stops: list 36.0pt;&quot;&gt;More items are stored in Optimizely Graph&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l12 level1 lfo3; tab-stops: list 36.0pt;&quot;&gt;More content records are created&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l12 level1 lfo3; tab-stops: list 36.0pt;&quot;&gt;More synchronization events are processed&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l12 level1 lfo3; tab-stops: list 36.0pt;&quot;&gt;Asset selection becomes harder for editors&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l12 level1 lfo3; tab-stops: list 36.0pt;&quot;&gt;Governance becomes increasingly complex&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Most importantly, organizations should understand how content volume contributes to overall platform usage and operational overhead.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;For this reason, a successful DAM strategy is not about synchronizing everything that exists inside Bynder.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;It is about synchronizing only what is required.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Start With Governance, Not Technology&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;One of the biggest lessons learned during implementation was that DAM integrations are primarily a governance challenge rather than a technical challenge.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The connector itself can be configured very quickly.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Determining which assets should be synchronized requires considerably more thought.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Before connecting Bynder to Optimizely, I recommend answering questions such as:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l14 level1 lfo4; tab-stops: list 36.0pt;&quot;&gt;Which assets are intended for public websites?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l14 level1 lfo4; tab-stops: list 36.0pt;&quot;&gt;Which business teams own those assets?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l14 level1 lfo4; tab-stops: list 36.0pt;&quot;&gt;Which environments require those assets?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l14 level1 lfo4; tab-stops: list 36.0pt;&quot;&gt;Who approves synchronization scope changes?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l14 level1 lfo4; tab-stops: list 36.0pt;&quot;&gt;How will future asset growth be managed?&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Answering these questions early can prevent a significant amount of cleanup work later.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;The Common Mistake: Connecting With an Administrator Account&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The easiest way to enable the connector is often to authenticate using an administrator account.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The workflow usually looks something like this:&lt;/p&gt;
&lt;ol style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l4 level1 lfo5; tab-stops: list 36.0pt;&quot;&gt;Open the Bynder connector.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l4 level1 lfo5; tab-stops: list 36.0pt;&quot;&gt;Click Connect.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l4 level1 lfo5; tab-stops: list 36.0pt;&quot;&gt;Log in using administrative credentials.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l4 level1 lfo5; tab-stops: list 36.0pt;&quot;&gt;Approve access.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l4 level1 lfo5; tab-stops: list 36.0pt;&quot;&gt;Start synchronizing.&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The problem is that administrator accounts often see virtually everything.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;That means the connector can potentially see:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l8 level1 lfo6; tab-stops: list 36.0pt;&quot;&gt;Website assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l8 level1 lfo6; tab-stops: list 36.0pt;&quot;&gt;Internal assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l8 level1 lfo6; tab-stops: list 36.0pt;&quot;&gt;Historical assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l8 level1 lfo6; tab-stops: list 36.0pt;&quot;&gt;Regional assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l8 level1 lfo6; tab-stops: list 36.0pt;&quot;&gt;Unused assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l8 level1 lfo6; tab-stops: list 36.0pt;&quot;&gt;Archived assets&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In other words, the connector effectively inherits access to the entire DAM repository.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This removes any meaningful synchronization boundaries.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Why Creating a New User Is Not Enough&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;A common assumption is:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&quot;I&#39;ll simply create a new user for Optimizely and restrict its permissions.&quot;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Unfortunately, this is where many implementations run into trouble.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Bynder permissions are primarily controlled through Permission Profiles.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The effective model looks like this:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Permission Profile&amp;nbsp; &amp;rarr;&amp;nbsp; User&amp;nbsp; &amp;rarr;&amp;nbsp; Asset Visibility&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This means that simply creating a new user does not automatically reduce visibility.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;If the new integration user remains associated with a highly privileged profile, that user may still inherit broad access to assets.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In practice, creating a new user and placing it within an administrator-level permission profile often results in another highly privileged user.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The desired filtering behavior never materializes.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This is why a dedicated Permission Profile becomes essential.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;The Recommended Approach&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Instead of creating a user within an existing administrative profile, create:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo7; tab-stops: list 36.0pt;&quot;&gt;A dedicated synchronization user&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo7; tab-stops: list 36.0pt;&quot;&gt;A dedicated synchronization permission profile&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo7; tab-stops: list 36.0pt;&quot;&gt;Dedicated metadata visibility rules&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Together, these become the foundation of your synchronization strategy.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The goal is to create an account that acts as a read-only integration consumer and nothing more.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h4&gt;&lt;strong&gt;1. Creating a Dedicated Synchronization Profile&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The dedicated synchronization profile should be configured with only the permissions required for integration purposes.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Recommended permissions include:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Asset Bank&lt;/strong&gt;&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l15 level1 lfo8; tab-stops: list 36.0pt;&quot;&gt;View assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l15 level1 lfo8; tab-stops: list 36.0pt;&quot;&gt;Search assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l15 level1 lfo8; tab-stops: list 36.0pt;&quot;&gt;View asset details&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l15 level1 lfo8; tab-stops: list 36.0pt;&quot;&gt;View metaproperties&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;General / Integration&lt;/strong&gt;&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l2 level1 lfo9; tab-stops: list 36.0pt;&quot;&gt;API Access&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l2 level1 lfo9; tab-stops: list 36.0pt;&quot;&gt;Manage Webhooks&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Permissions that generally do not need to be enabled include:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l7 level1 lfo10; tab-stops: list 36.0pt;&quot;&gt;Upload assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l7 level1 lfo10; tab-stops: list 36.0pt;&quot;&gt;Edit assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l7 level1 lfo10; tab-stops: list 36.0pt;&quot;&gt;Delete assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l7 level1 lfo10; tab-stops: list 36.0pt;&quot;&gt;Manage taxonomy&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l7 level1 lfo10; tab-stops: list 36.0pt;&quot;&gt;Administrative functions&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;h4&gt;&lt;strong&gt;2. Create a Dedicated Synchronization Account&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Once the synchronization profile has been configured, create a dedicated service account and assign it exclusively to that profile.&lt;/p&gt;
&lt;p&gt;This account will be used during the Bynder authorization process and will ultimately determine which assets the Optimizely connector can access.&lt;/p&gt;
&lt;p&gt;Avoid assigning the account to an existing administrative profile or a profile used by content creators. The goal is to create a narrowly scoped integration account whose sole responsibility is synchronizing approved assets into Optimizely.&lt;/p&gt;
&lt;p&gt;By separating the integration account from day-to-day user accounts, you gain:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Predictable synchronization behavior&lt;/li&gt;
&lt;li&gt;Easier troubleshooting&lt;/li&gt;
&lt;li&gt;Clear ownership of integration permissions&lt;/li&gt;
&lt;li&gt;Reduced risk of unintentionally exposing additional assets to Optimizely&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;h4 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;3. Using Metadata as a Synchronization Boundary&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Many teams think about metadata exclusively in terms of search and categorization.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;During this implementation, I found it equally useful to think of metadata as a governance mechanism.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Metadata can help answer questions such as:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l13 level1 lfo11; tab-stops: list 36.0pt;&quot;&gt;Should this asset be visible to websites?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l13 level1 lfo11; tab-stops: list 36.0pt;&quot;&gt;Which business unit owns this asset?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l13 level1 lfo11; tab-stops: list 36.0pt;&quot;&gt;Which region can use this asset?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l13 level1 lfo11; tab-stops: list 36.0pt;&quot;&gt;Which environments should receive this asset?&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;By implementing metadata-driven visibility, organizations can define synchronization boundaries before assets enter Optimizely.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This keeps governance as close as possible to the source system.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h4 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;4. Configuring Metadata Visibility&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;One effective approach is to use a &lt;strong&gt;required metadata property&lt;/strong&gt; that identifies whether an asset is intended for website consumption.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;For example: &lt;strong&gt;VisibleTo&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;img style=&quot;border-width: 1px; border-style: solid;&quot; src=&quot;/link/9b93cf8ded06433fb473d4ee88ef7f0d.aspx?1783186950489&quot; width=&quot;447&quot; height=&quot;174&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;To configure this:&lt;/p&gt;
&lt;ol style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l17 level1 lfo12; tab-stops: list 36.0pt;&quot;&gt;Navigate to &lt;strong&gt;Settings&amp;nbsp; &amp;rarr;&amp;nbsp; Taxonomy&amp;nbsp; &amp;rarr;&amp;nbsp; Metaproperties Management&lt;/strong&gt;&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l17 level1 lfo12; tab-stops: list 36.0pt;&quot;&gt;Select the metadata property&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l17 level1 lfo12; tab-stops: list 36.0pt;&quot;&gt;Open the &lt;strong&gt;Visibility&lt;/strong&gt; configuration&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l17 level1 lfo12; tab-stops: list 36.0pt;&quot;&gt;Select the synchronization profile&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l17 level1 lfo12; tab-stops: list 36.0pt;&quot;&gt;Grant/deny visibility only to approved metadata values.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img style=&quot;border-width: 1px; border-style: solid;&quot; src=&quot;/link/f4763bfeca7d40b780f19110f800e0c8.aspx?1783187024542&quot; width=&quot;564&quot; height=&quot;330&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;When configured correctly, the synchronization account becomes effectively blind to assets outside the approved scope.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h4 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;5. Validate Before Connecting&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;One of the most valuable steps in the entire process happens before Optimizely is connected.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;After creating the synchronization account and permission profile:&lt;/p&gt;
&lt;ol style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l11 level1 lfo13; tab-stops: list 36.0pt;&quot;&gt;Open an Incognito or InPrivate browser session.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l11 level1 lfo13; tab-stops: list 36.0pt;&quot;&gt;Login using the synchronization account.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l11 level1 lfo13; tab-stops: list 36.0pt;&quot;&gt;Search for assets.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l11 level1 lfo13; tab-stops: list 36.0pt;&quot;&gt;Browse collections.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l11 level1 lfo13; tab-stops: list 36.0pt;&quot;&gt;Verify metadata visibility.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l11 level1 lfo13; tab-stops: list 36.0pt;&quot;&gt;Validate that only the intended assets are available.&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Ask yourself:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;If I connect Optimizely using this account right now, am I comfortable synchronizing every asset visible on this screen?&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;If the answer is no, continue refining the profile before proceeding.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This simple validation step can save considerable troubleshooting effort later.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;The Authorization Flow Trap&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Another lesson learned during implementation is that the authorization process deserves more attention than most teams initially give it.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The connector authorization flow uses the account that participates in the OAuth approval process.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;If an existing browser session already contains administrative Bynder credentials, those credentials may inadvertently be used during authorization.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;To avoid this:&lt;/p&gt;
&lt;ol style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l6 level1 lfo14; tab-stops: list 36.0pt;&quot;&gt;Open a fresh InPrivate or Incognito browser window.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l6 level1 lfo14; tab-stops: list 36.0pt;&quot;&gt;Login to Optimizely SaaS CMS.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l6 level1 lfo14; tab-stops: list 36.0pt;&quot;&gt;Start the Bynder App installation and connection process.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;font-weight: bold;&quot;&gt;&lt;strong&gt;Most Important:&lt;/strong&gt;
&lt;ol style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l6 level1 lfo14; tab-stops: list 36.0pt;&quot;&gt;Installation process must open the Bynder login page.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l6 level1 lfo14; tab-stops: list 36.0pt;&quot;&gt;Login using the dedicated synchronization account.&lt;/li&gt;
&lt;/ol&gt;
&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l6 level1 lfo14; tab-stops: list 36.0pt;&quot;&gt;Complete the authorization flow.&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Using a clean browser session helps ensure the connector is authorized with the intended account rather than accidentally inheriting access from an existing administrative session.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h4 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Understanding the Synchronization Flow&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Scenario A : Asset is visible to the synchronization account&lt;/strong&gt;&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo15; tab-stops: list 36.0pt;&quot;&gt;Asset uploaded/updated into Bynder.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo15; tab-stops: list 36.0pt;&quot;&gt;Bynder triggers the OCP connector webhook.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo15; tab-stops: list 36.0pt;&quot;&gt;Bynder receives a request from the connector.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo15; tab-stops: list 36.0pt;&quot;&gt;The synchronization account is authorized to view the asset.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo15; tab-stops: list 36.0pt;&quot;&gt;Bynder returns the asset payload.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo15; tab-stops: list 36.0pt;&quot;&gt;OCP processes the response.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo15; tab-stops: list 36.0pt;&quot;&gt;The asset is synchronized into Optimizely Graph.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo15; tab-stops: list 36.0pt;&quot;&gt;The asset may become available within CMS depending on configuration.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img style=&quot;border-width: 1px; border-style: solid;&quot; src=&quot;/link/a927f1a971c74079be8d3e97e45419be.aspx?1783187744711&quot; width=&quot;582&quot; height=&quot;391&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Scenario B : Asset is not visible to the synchronization account&lt;/strong&gt;&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li&gt;Asset uploaded/updated into Bynder.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo15; tab-stops: list 36.0pt;&quot;&gt;Bynder triggers the OCP connector webhook.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo15; tab-stops: list 36.0pt;&quot;&gt;Bynder receives a request from the connector.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l9 level1 lfo16; tab-stops: list 36.0pt;&quot;&gt;Bynder evaluates permissions.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l9 level1 lfo16; tab-stops: list 36.0pt;&quot;&gt;Access is denied because the synchronization account cannot see the asset.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l9 level1 lfo16; tab-stops: list 36.0pt;&quot;&gt;No asset payload is returned.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l9 level1 lfo16; tab-stops: list 36.0pt;&quot;&gt;OCP connector skips synchronization.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This means filtering occurs naturally through the permission model rather than through custom synchronization logic.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img style=&quot;border-width: 1px; border-style: solid;&quot; src=&quot;/link/cae36a1cec544c05918e7bcee09a60d8.aspx?1783187879183&quot; width=&quot;447&quot; height=&quot;428&quot; /&gt;&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Key Lessons Learned&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;One of the biggest realizations are that successful DAM integrations are defined long before the first asset is synchronized.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;A few recommendations I would strongly encourage:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l5 level1 lfo18; tab-stops: list 36.0pt;&quot;&gt;Define synchronization boundaries before configuring the connector.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l5 level1 lfo18; tab-stops: list 36.0pt;&quot;&gt;Create a dedicated integration profile instead of reusing administrative profiles.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l5 level1 lfo18; tab-stops: list 36.0pt;&quot;&gt;Use metadata strategically rather than treating it purely as a categorization tool.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l5 level1 lfo18; tab-stops: list 36.0pt;&quot;&gt;Validate permissions using a private browser session before connecting Optimizely.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l5 level1 lfo18; tab-stops: list 36.0pt;&quot;&gt;Think carefully about which assets truly belong inside the website ecosystem.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l5 level1 lfo18; tab-stops: list 36.0pt;&quot;&gt;Start with a smaller, controlled asset scope and expand incrementally if needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Most importantly:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Just because an asset exists in Bynder does not mean it needs to exist in Optimizely.&lt;/strong&gt;&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The Bynder connector makes it very easy to bring DAM assets into Optimizely SaaS CMS.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;However, the long-term success of the integration depends less on connector configuration and more on governance decisions made beforehand.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;By investing time in permission profiles, metadata design, synchronization boundaries, and dedicated integration accounts, organizations can significantly reduce operational overhead and create a much cleaner experience for both editors and developers.&lt;/p&gt;
&lt;div&gt;In my next article, I&#39;ll take a deeper look at what happens after synchronization is established. We&#39;ll explore how asset visibility changes can create orphan records, how synchronization behavior is impacted when assets move in and out of scope, and the operational challenges that emerge in multi-environment implementations. I&#39;ll also discuss environment-specific asset governance considerations, common pitfalls organizations encounter as their DAM footprint grows, and architectural approaches for keeping Optimizely environments clean, scalable, and maintainable over time.&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;h4 class=&quot;_1l4j4na1 _1qskm0h c8urk _1a0p899 _5hqrjx _667h42&quot;&gt;&#128218; Bynder + Optimizely SaaS CMS Integration Series&lt;/h4&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot;&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;This article is the second installment of a 3-part comprehensive architecture guide:&lt;/em&gt;&lt;/div&gt;
&lt;ul class=&quot;_667h42 _1l4j4na6&quot;&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;✅ Part 1:&amp;nbsp;&lt;a class=&quot;_667h42 _1l4j4nac _1c9dtv3 _1by2b93 _1140xq1 _667h42&quot; href=&quot;/link/4f215cd334254dfcbc121d5f4e20edd6.aspx&quot;&gt;Implementing the Connector &amp;mdash; Lessons Learned&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;What metadata syncs, how URLs behave, and how to query/render assets in a Next.js frontend.&lt;br /&gt;&lt;br /&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;&#128073; Part 2: Planning &amp;amp; Filtering &amp;mdash; Avoiding Asset Sprawl and Unnecessary Sync&lt;/strong&gt;&amp;nbsp;&lt;em class=&quot;far4bl _667h42&quot;&gt;(You are here)&lt;/em&gt;&lt;br /&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;How we achieved metadata-based sync filtering with zero custom code.&lt;br /&gt;&lt;br /&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;⏭️ Part 3:&amp;nbsp;&lt;a class=&quot;_667h42 _1l4j4nac _1c9dtv3 _1by2b93 _1140xq1 _667h42&quot; href=&quot;/link/650c1d72d9a84c28b2355e8942fc7cda.aspx&quot;&gt;Exploring Asset Lifecycle Management &amp;amp; Three-Gate Governance&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;Explore a webhook-driven, three-gate model to handle asset updates, environments, and usage verification.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;</description>            <guid>https://world.optimizely.com/blogs/vipin-banka--learnings--insights/dates/2026/7/planning-your-bynder-dam-integration-for-optimizely-saas-cms-avoiding-asset-sprawl-managing-costs-and-designing-for-scale/</guid>            <pubDate>Sat, 04 Jul 2026 18:28:12 GMT</pubDate>           <category>Blog post</category></item><item> <title>Implementing the Bynder DAM Connector with Optimizely SaaS CMS: Lessons Learned</title>            <link>https://world.optimizely.com/blogs/vipin-banka--learnings--insights/dates/2026/7/implementing-the-bynder-dam-connector-with-optimizely-saas-cms-lessons-learned/</link>            <description>&lt;p class=&quot;MsoNormal&quot;&gt;&lt;em&gt;What I learned while integrating Bynder DAM with Optimizely SaaS CMS, exploring Optimizely Graph, and building a headless frontend experience.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;
&lt;h2 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Introduction&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;While working on an Optimizely SaaS CMS implementation, I spent considerable time understanding how the Bynder DAM connector works, what data gets synchronized, how assets appear in Optimizely Graph, and how frontend applications should consume those assets.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Although both Optimizely and Bynder provide documentation, I found very little content that shows the complete end-to-end picture:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;What metadata gets synchronized?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;How do assets appear in Optimizely CMS?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;What does the data look like in Optimizely Graph?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;How do developers render images, videos, and documents?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;How do public and private assets behave?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;What are the limitations of the connector?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 12.0pt; line-height: 115%; font-family: &#39;Aptos&#39;,sans-serif; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: Aptos; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: &#39;Times New Roman&#39;; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-IN; mso-fareast-language: EN-US; mso-bidi-language: AR-SA;&quot;&gt;This article summarizes my findings and lessons learned from exploring the integration.&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;What is Optimizely SaaS CMS?&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Optimizely SaaS CMS is a cloud-native content management platform that enables organizations to create and manage content experiences across websites, mobile applications, portals, and other digital channels.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Key capabilities include:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Content modeling&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Headless content delivery&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Visual editing&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Multi-site architecture&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Optimizely Graph integration&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;API-first content management&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Unlike traditional CMS platforms, content in Optimizely SaaS is managed through content types and delivered through APIs and Optimizely Graph.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;What is Bynder?&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Bynder is an enterprise Digital Asset Management (DAM) platform.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Organizations typically use Bynder to manage:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Images&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Videos&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Brand assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Product photography&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Brochures and documents&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Marketing collateral&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Digital media libraries&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Bynder often serves as the single source of truth for digital assets while Optimizely serves as the source of truth for content.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3&gt;&lt;strong&gt;Why Do We Need a Connector?&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Without a connector, editorial teams typically follow this process:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Bynder DAM &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Download Asset &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Upload Asset to CMS &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Use Asset on Website&lt;br /&gt;OR&lt;br /&gt;Bynder DAM &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Copy Asset URL &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Paste Asset URL to CMS &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Use Asset on Website&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This creates multiple problems:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Duplicate storage&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Asset versioning issues&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Governance challenges&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Increased maintenance effort&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Multiple sources of truth&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The Bynder Connector changes the process significantly:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Bynder DAM &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; DAM Connector &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Optimizely Graph &amp;amp; CMS &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Frontend Application&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Benefits include:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0cm;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Single source of truth&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;No duplicate assets&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Improved governance&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Centralized asset management&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo2; tab-stops: list 36.0pt;&quot;&gt;Better scalability&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Editors never need to download and re-upload assets.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Instead, references to Bynder assets become available directly within Optimizely CMS.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Understanding the Bynder Asset Model&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;One of the first things I wanted to understand was what data becomes available. &lt;span style=&quot;font-size: 12.0pt; line-height: 115%; font-family: &#39;Aptos&#39;,sans-serif; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: Aptos; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: &#39;Times New Roman&#39;; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-IN; mso-fareast-language: EN-US; mso-bidi-language: AR-SA;&quot;&gt;A Bynder asset can be thought of as a combination of following:&lt;/span&gt;&lt;/p&gt;
&lt;ul class=&quot;article-editor-bullet-list&quot;&gt;
&lt;li class=&quot;article-editor-list-item&quot;&gt;
&lt;p class=&quot;article-editor-paragraph&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Bynder Managed Fields - &lt;/strong&gt;Maintained automatically by Bynder. These fields describe the physical asset itself.&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&quot;article-editor-list-item&quot; style=&quot;text-align: left;&quot;&gt;
&lt;p class=&quot;article-editor-paragraph&quot;&gt;&lt;strong&gt;User Managed Fields - &lt;/strong&gt;These fields are managed by DAM users and are often used for: Search, Categorization, Filtering, Metadata enrichment.&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&quot;article-editor-list-item&quot; style=&quot;text-align: left;&quot;&gt;
&lt;p class=&quot;article-editor-paragraph&quot;&gt;&lt;strong&gt;User Managed Flags: &lt;/strong&gt;These fields can influence asset behavior. These become particularly important when assets are exposed to public-facing websites.&lt;/p&gt;
&lt;/li&gt;
&lt;li class=&quot;article-editor-list-item&quot; style=&quot;text-align: left;&quot;&gt;
&lt;p class=&quot;article-editor-paragraph&quot;&gt;&lt;strong&gt;URLs:&lt;/strong&gt; Assets URLs based on asset object and various configurations and enabled features in Bynder.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;font-size: 12.0pt; line-height: 115%; font-family: &#39;Aptos&#39;,sans-serif; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: Aptos; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: &#39;Times New Roman&#39;; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-IN; mso-fareast-language: EN-US; mso-bidi-language: AR-SA;&quot;&gt;&lt;br /&gt;&lt;img src=&quot;/link/717b08ca5a0f40aaa9d6924e17798cc1.aspx&quot; /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Understanding the Available Asset URLs&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;One of the most useful discoveries was understanding which URLs are available for different asset types.&amp;nbsp;Not every asset type exposes the same URLs.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h4 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Image Assets - &lt;/strong&gt;Image assets typically provide:&lt;/h4&gt;
&lt;table class=&quot;MsoTableGrid&quot; style=&quot;border-collapse: collapse; margin-left: 0px; margin-right: auto; width: 79.5455%; height: 233px; border-image: initial; border: medium none currentcolor;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 40.7625px;&quot;&gt;
&lt;td style=&quot;width: 33.7357%; border: 1pt solid windowtext; padding: 0cm 5.4pt; text-align: left; line-height: 1; height: 40.7625px; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&lt;strong&gt;Original URL&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 32.4977%; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; line-height: 1; height: 40.7625px; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Thumbnail URL&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.5809%; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; line-height: 1; height: 40.7625px; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Transform Base URL&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 65.2px;&quot;&gt;
&lt;td style=&quot;width: 33.7357%; border-width: medium 1pt 1pt; border-style: none solid solid; border-color: currentcolor windowtext windowtext; border-image: initial; padding: 0cm 5.4pt; text-align: left; line-height: 1; height: 65.2px; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Represents the original uploaded file.&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 32.4977%; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; line-height: 1; height: 65.2px; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;Represents a smaller version of the image.&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.5809%; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; line-height: 1; height: 65.2px; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;Instead of generating multiple physical image versions, Bynder allows images to be transformed dynamically.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 135.262px;&quot;&gt;
&lt;td style=&quot;width: 33.7357%; border-width: medium 1pt 1pt; border-style: none solid solid; border-color: currentcolor windowtext windowtext; border-image: initial; padding: 0cm 5.4pt; text-align: left; line-height: 1; height: 135.262px; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Use cases:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;High-resolution download, &lt;br /&gt;Print-quality rendering, &lt;br /&gt;Internal consumption&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 32.4977%; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; line-height: 1; height: 135.262px; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Use cases:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Asset pickers, &lt;br /&gt;Search results, &lt;br /&gt;Content listings, &lt;br /&gt;Media libraries&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.5809%; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; line-height: 1; height: 135.262px; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Use cases:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Hero banners, &lt;br /&gt;Product images, &lt;br /&gt;Responsive image delivery, &lt;br /&gt;Mobile optimization, &lt;br /&gt;Social sharing images&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&amp;nbsp;Transform Base URL helps improve:&lt;/p&gt;
&lt;ul&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Performance&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Page speed&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Bandwidth consumption&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h4 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Video Assets - &lt;/strong&gt;Video assets typically provide:&lt;/h4&gt;
&lt;table class=&quot;MsoTableGrid&quot; style=&quot;width: 948px; border-collapse: collapse; border-image: initial; height: 188px; border: medium none currentcolor;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;mso-yfti-irow: 0; mso-yfti-firstrow: yes;&quot;&gt;
&lt;td style=&quot;width: 301.017px; border: 1pt solid windowtext; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&lt;strong&gt;Original URL&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 300.742px; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&lt;strong&gt;Thumbnail URL&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 299.905px; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Video Preview URL&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;mso-yfti-irow: 1;&quot;&gt;
&lt;td style=&quot;width: 301.017px; border-width: medium 1pt 1pt; border-style: none solid solid; border-color: currentcolor windowtext windowtext; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;The complete video asset&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 300.742px; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;Poster image for the video.&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 299.905px; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;Optimized preview version.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;mso-yfti-irow: 2; mso-yfti-lastrow: yes;&quot;&gt;
&lt;td style=&quot;width: 301.017px; border-width: medium 1pt 1pt; border-style: none solid solid; border-color: currentcolor windowtext windowtext; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Use cases:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Full playback,&lt;br /&gt;Downloads,&lt;br /&gt;Media processing&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 300.742px; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Use cases:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Video cards,&lt;br /&gt;Search results,&lt;br /&gt;Carousel view&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 299.905px; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Use cases:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;Video galleries,&lt;br /&gt;Content previews,&lt;br /&gt;Editorial review&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h4 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Document Assets - &lt;/strong&gt;Document assets typically provide:&lt;/h4&gt;
&lt;table class=&quot;MsoTableGrid&quot; style=&quot;width: 584px; border-collapse: collapse; border-image: initial; height: 177px; border: medium none currentcolor;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;mso-yfti-irow: 0; mso-yfti-firstrow: yes;&quot;&gt;
&lt;td style=&quot;width: 276.225px; border: 1pt solid windowtext; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&lt;strong&gt;Original URL&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 276.238px; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&lt;strong&gt;Thumbnail URL&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;mso-yfti-irow: 1; mso-yfti-lastrow: yes;&quot;&gt;
&lt;td style=&quot;width: 276.225px; border-width: medium 1pt 1pt; border-style: none solid solid; border-color: currentcolor windowtext windowtext; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Used for:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Document downloads,&lt;br /&gt;Direct viewing,&lt;br /&gt;PDF rendering&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 276.238px; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Used for:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Document previews,&lt;br /&gt;Search results,&lt;br /&gt;Asset browsers&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Setting Up the Connector&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Connector setup is relatively straightforward. Follow the documentation here:&lt;br /&gt;&lt;a href=&quot;https://support.optimizely.com/hc/en-us/articles/37465644973069-Configure-the-Bynder-app&quot;&gt;https://support.optimizely.com/hc/en-us/articles/37465644973069-Configure-the-Bynder-app&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Typical configuration requires:&lt;/p&gt;
&lt;ol&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;!-- [if !supportLists]--&gt;Bynder Admin Access&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;!--[endif]--&gt;Webhook permissions on your Bynder user profile to authorize this integration.&lt;br /&gt;&lt;span style=&quot;mso-no-proof: yes;&quot;&gt;&lt;img src=&quot;/link/9c05c0fedea141afa9dab9a3c5c06c34.aspx&quot; width=&quot;333&quot; height=&quot;338&quot; border=&quot;0&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;mso-no-proof: yes;&quot;&gt;&lt;span style=&quot;text-indent: -18pt;&quot;&gt;Bynder OAuth App, Client ID, Client Secret&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;text-indent: -18pt;&quot;&gt;OCP (Connect Platform) access in Optimizely SaaS instance.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Note that:&lt;br /&gt;a) Setup separate sync for:&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpFirst&quot; style=&quot;margin-left: 54pt; text-indent: -18pt; text-align: left;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-bidi-font-family: Aptos; mso-bidi-theme-font: minor-latin;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;1.&lt;span style=&quot;font: 7.0pt &#39;Times New Roman&#39;;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Each Bynder object i.e. image, document, video.&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpMiddle&quot; style=&quot;margin-left: 54pt; text-indent: -18pt; text-align: left;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-bidi-font-family: Aptos; mso-bidi-theme-font: minor-latin;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;2.&lt;span style=&quot;font: 7.0pt &#39;Times New Roman&#39;;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Each Optimizely environment i.e. Dev, Stage, Prod (test1, test2, Production)&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpLast&quot; style=&quot;margin-left: 54pt; text-indent: -18pt; text-align: left;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-bidi-font-family: Aptos; mso-bidi-theme-font: minor-latin;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;3.&lt;span style=&quot;font: 7.0pt &#39;Times New Roman&#39;;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Each Language (if applicable) otherwise use Neutral language&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;b) &lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp;&lt;/span&gt;In the Destination create separate ContentType for each object i.e. Image &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; BynderImage, Document &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; BynderDocument, Video &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; BynderVideo&lt;br /&gt;&lt;span style=&quot;mso-no-proof: yes;&quot;&gt;&lt;!-- [if gte vml 1]&gt;&lt;v:shape id=&quot;Picture_x0020_1&quot;
 o:spid=&quot;_x0000_i1027&quot; type=&quot;#_x0000_t75&quot; style=&#39;width:141.6pt;height:142.8pt;
 visibility:visible;mso-wrap-style:square&#39;&gt;
 &lt;v:imagedata src=&quot;file:///C:/Users/VBanka/AppData/Local/Temp/msohtmlclip1/01/clip_image003.png&quot;
  o:title=&quot;&quot;/&gt;
&lt;/v:shape&gt;&lt;![endif]--&gt;&lt;!-- [if !vml]--&gt;&lt;img src=&quot;/link/f5f31192a9884124b0db9dd9fd09fd70.aspx&quot; width=&quot;240&quot; height=&quot;241&quot; border=&quot;0&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--[endif]--&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;c) Ensure selection of &amp;ldquo;Make available as CMS Content&amp;rdquo; checkbox.&lt;br /&gt;&lt;span style=&quot;mso-no-proof: yes;&quot;&gt;&lt;!-- [if gte vml 1]&gt;&lt;v:shape id=&quot;Picture_x0020_18&quot;
 o:spid=&quot;_x0000_i1026&quot; type=&quot;#_x0000_t75&quot; style=&#39;width:277.8pt;height:293.4pt;
 visibility:visible;mso-wrap-style:square&#39;&gt;
 &lt;v:imagedata src=&quot;file:///C:/Users/VBanka/AppData/Local/Temp/msohtmlclip1/01/clip_image005.png&quot;
  o:title=&quot;&quot;/&gt;
&lt;/v:shape&gt;&lt;![endif]--&gt;&lt;!-- [if !vml]--&gt;&lt;img src=&quot;/link/282149262aa94df1b3376c4a82e1ac77.aspx&quot; width=&quot;370&quot; height=&quot;391&quot; border=&quot;0&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;!--[endif]--&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Once configured successfully:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Bynder Assets &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; DAM Connector &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Optimizely Graph + CMS Content Type&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Assets become available inside Optimizely Graph and CMS both without custom code.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Content Manager Experience&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;From an editorial perspective, this is where things become interesting.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;After configuration, editors can browse DAM assets directly inside CMS.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;The Content Manager navigation typically exposes a dedicated content provider area.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;mso-no-proof: yes;&quot;&gt;&lt;!-- [if gte vml 1]&gt;&lt;v:shapetype
 id=&quot;_x0000_t75&quot; coordsize=&quot;21600,21600&quot; o:spt=&quot;75&quot; o:preferrelative=&quot;t&quot;
 path=&quot;m@4@5l@4@11@9@11@9@5xe&quot; filled=&quot;f&quot; stroked=&quot;f&quot;&gt;
 &lt;v:stroke joinstyle=&quot;miter&quot;/&gt;
 &lt;v:formulas&gt;
  &lt;v:f eqn=&quot;if lineDrawn pixelLineWidth 0&quot;/&gt;
  &lt;v:f eqn=&quot;sum @0 1 0&quot;/&gt;
  &lt;v:f eqn=&quot;sum 0 0 @1&quot;/&gt;
  &lt;v:f eqn=&quot;prod @2 1 2&quot;/&gt;
  &lt;v:f eqn=&quot;prod @3 21600 pixelWidth&quot;/&gt;
  &lt;v:f eqn=&quot;prod @3 21600 pixelHeight&quot;/&gt;
  &lt;v:f eqn=&quot;sum @0 0 1&quot;/&gt;
  &lt;v:f eqn=&quot;prod @6 1 2&quot;/&gt;
  &lt;v:f eqn=&quot;prod @7 21600 pixelWidth&quot;/&gt;
  &lt;v:f eqn=&quot;sum @8 21600 0&quot;/&gt;
  &lt;v:f eqn=&quot;prod @7 21600 pixelHeight&quot;/&gt;
  &lt;v:f eqn=&quot;sum @10 21600 0&quot;/&gt;
 &lt;/v:formulas&gt;
 &lt;v:path o:extrusionok=&quot;f&quot; gradientshapeok=&quot;t&quot; o:connecttype=&quot;rect&quot;/&gt;
 &lt;o:lock v:ext=&quot;edit&quot; aspectratio=&quot;t&quot;/&gt;
&lt;/v:shapetype&gt;&lt;v:shape id=&quot;Picture_x0020_20&quot; o:spid=&quot;_x0000_i1052&quot; type=&quot;#_x0000_t75&quot;
 style=&#39;width:451.2pt;height:151.8pt;visibility:visible;mso-wrap-style:square&#39;
 o:bordertopcolor=&quot;yellow pure&quot; o:borderleftcolor=&quot;yellow pure&quot;
 o:borderbottomcolor=&quot;yellow pure&quot; o:borderrightcolor=&quot;yellow pure&quot;&gt;
 &lt;v:imagedata src=&quot;file:///C:/Users/VBanka/AppData/Local/Temp/msohtmlclip1/01/clip_image001.png&quot;
  o:title=&quot;&quot;/&gt;
 &lt;w:bordertop type=&quot;single&quot; width=&quot;6&quot;/&gt;
 &lt;w:borderleft type=&quot;single&quot; width=&quot;6&quot;/&gt;
 &lt;w:borderbottom type=&quot;single&quot; width=&quot;6&quot;/&gt;
 &lt;w:borderright type=&quot;single&quot; width=&quot;6&quot;/&gt;
&lt;/v:shape&gt;&lt;![endif]--&gt;&lt;!-- [if !vml]--&gt;&lt;img src=&quot;/link/470118ee057e4cdcb0fbfd2a052e02bb.aspx&quot; width=&quot;603&quot; height=&quot;204&quot; /&gt;&lt;!--[endif]--&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;span style=&quot;mso-no-proof: yes;&quot;&gt;&lt;!-- [if gte vml 1]&gt;&lt;v:shape
 id=&quot;Picture_x0020_1&quot; o:spid=&quot;_x0000_i1051&quot; type=&quot;#_x0000_t75&quot; style=&#39;width:451.2pt;
 height:169.8pt;visibility:visible;mso-wrap-style:square&#39; o:bordertopcolor=&quot;yellow pure&quot;
 o:borderleftcolor=&quot;yellow pure&quot; o:borderbottomcolor=&quot;yellow pure&quot;
 o:borderrightcolor=&quot;yellow pure&quot;&gt;
 &lt;v:imagedata src=&quot;file:///C:/Users/VBanka/AppData/Local/Temp/msohtmlclip1/01/clip_image003.png&quot;
  o:title=&quot;&quot;/&gt;
 &lt;w:bordertop type=&quot;single&quot; width=&quot;6&quot;/&gt;
 &lt;w:borderleft type=&quot;single&quot; width=&quot;6&quot;/&gt;
 &lt;w:borderbottom type=&quot;single&quot; width=&quot;6&quot;/&gt;
 &lt;w:borderright type=&quot;single&quot; width=&quot;6&quot;/&gt;
&lt;/v:shape&gt;&lt;![endif]--&gt;&lt;!-- [if !vml]--&gt;&lt;img src=&quot;/link/aaa2751bab514ace865a38bbd7c8ab7d.aspx&quot; width=&quot;603&quot; height=&quot;228&quot; /&gt;&lt;!--[endif]--&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;At this point, editors do not need to leave CMS to discover assets stored in Bynder.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;They can:&amp;nbsp;Search, Browse, Filter, Reference assets&amp;nbsp;directly from the content authoring experience.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;How Assets Appear in Optimizely Graph&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Once synchronized, DAM assets become queryable through Graph.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;A simplified query may look like (the exact query will depend on your field mappings)&lt;br style=&quot;mso-special-character: line-break;&quot; /&gt;&lt;!-- [if !supportLineBreakNewLine]--&gt;&lt;br style=&quot;mso-special-character: line-break;&quot; /&gt;&lt;!--[endif]--&gt;&lt;/p&gt;
&lt;table class=&quot;MsoTableGrid&quot; style=&quot;border-collapse: collapse; margin-left: 0px; margin-right: auto; border-image: initial; height: 362px; width: 73.2839%; border: medium none currentcolor;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;mso-yfti-irow: 0; mso-yfti-firstrow: yes;&quot;&gt;
&lt;td style=&quot;width: 0%; border: 1pt solid windowtext; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Image&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 0%; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Video&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 0%; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Document&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;mso-yfti-irow: 1; mso-yfti-lastrow: yes;&quot;&gt;
&lt;td style=&quot;width: 0%; border-width: medium 1pt 1pt; border-style: none solid solid; border-color: currentcolor windowtext windowtext; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;query {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp; BynderImage {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; items {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; id&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; originalUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thumbnailUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; transformBaseUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;}&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 0%; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;query {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp; BynderVideo {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; items {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; id&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; originalUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thumbnailUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;videoPreviewURL&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;}&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 0%; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;query {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp; BynderDocument {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; items {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; id&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; originalUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thumbnailUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;}&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;One of the biggest advantages is that content and media can now be retrieved through a single API layer.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Using DAM Assets in Content Types&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;The connector enables DAM-specific property types.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Example:&lt;/p&gt;
&lt;table class=&quot;MsoTableGrid&quot; style=&quot;border-collapse: collapse; border-image: initial; height: 203px; width: 67.718%; border: medium none currentcolor;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes;&quot;&gt;
&lt;td style=&quot;width: 0%; border: 1pt solid windowtext; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;News Article Page&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpFirst&quot; style=&quot;mso-add-space: auto; text-indent: -18.0pt; line-height: normal; mso-list: l0 level1 lfo1; margin: 0cm 0cm 0cm 54.0pt;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-ascii-font-family: Aptos; mso-fareast-font-family: Aptos; mso-hansi-font-family: Aptos; mso-bidi-font-family: Aptos;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;-&lt;span style=&quot;font: 7.0pt &#39;Times New Roman&#39;;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Headline&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpMiddle&quot; style=&quot;mso-add-space: auto; text-indent: -18.0pt; line-height: normal; mso-list: l0 level1 lfo1; margin: 0cm 0cm 0cm 54.0pt;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-ascii-font-family: Aptos; mso-fareast-font-family: Aptos; mso-hansi-font-family: Aptos; mso-bidi-font-family: Aptos;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;-&lt;span style=&quot;font: 7.0pt &#39;Times New Roman&#39;;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Summary&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpLast&quot; style=&quot;mso-add-space: auto; text-indent: -18.0pt; line-height: normal; mso-list: l0 level1 lfo1; margin: 0cm 0cm 0cm 54.0pt;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-ascii-font-family: Aptos; mso-fareast-font-family: Aptos; mso-hansi-font-family: Aptos; mso-bidi-font-family: Aptos;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;-&lt;span style=&quot;font: 7.0pt &#39;Times New Roman&#39;;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Hero Image&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Where:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Hero Image&amp;nbsp;is a Bynder Image reference.&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 0%; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Product Page&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpFirst&quot; style=&quot;mso-add-space: auto; text-indent: -18.0pt; line-height: normal; mso-list: l0 level1 lfo1; margin: 0cm 0cm 0cm 54.0pt;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-ascii-font-family: Aptos; mso-fareast-font-family: Aptos; mso-hansi-font-family: Aptos; mso-bidi-font-family: Aptos;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;-&lt;span style=&quot;font: 7.0pt &#39;Times New Roman&#39;;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Title&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpMiddle&quot; style=&quot;mso-add-space: auto; text-indent: -18.0pt; line-height: normal; mso-list: l0 level1 lfo1; margin: 0cm 0cm 0cm 54.0pt;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-ascii-font-family: Aptos; mso-fareast-font-family: Aptos; mso-hansi-font-family: Aptos; mso-bidi-font-family: Aptos;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;-&lt;span style=&quot;font: 7.0pt &#39;Times New Roman&#39;;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Product Image&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpMiddle&quot; style=&quot;mso-add-space: auto; text-indent: -18.0pt; line-height: normal; mso-list: l0 level1 lfo1; margin: 0cm 0cm 0cm 54.0pt;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-ascii-font-family: Aptos; mso-fareast-font-family: Aptos; mso-hansi-font-family: Aptos; mso-bidi-font-family: Aptos;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;-&lt;span style=&quot;font: 7.0pt &#39;Times New Roman&#39;;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Product Video&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpLast&quot; style=&quot;mso-add-space: auto; text-indent: -18.0pt; line-height: normal; mso-list: l0 level1 lfo1; margin: 0cm 0cm 0cm 54.0pt;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-ascii-font-family: Aptos; mso-fareast-font-family: Aptos; mso-hansi-font-family: Aptos; mso-bidi-font-family: Aptos;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;-&lt;span style=&quot;font: 7.0pt &#39;Times New Roman&#39;;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;Product Brochure&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Where:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;Each asset property can reference a different Bynder asset type i.e. BynderImage, BynderVideo, and BynderDocument&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h3 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Frontend Consumption&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Once data is available through Graph, frontend applications can retrieve and render it.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Example:&lt;/p&gt;
&lt;table class=&quot;MsoTableGrid&quot; style=&quot;border-collapse: collapse; margin-left: 0px; margin-right: auto; border-image: initial; height: 714px; width: 76.9944%; border: medium none currentcolor;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;mso-yfti-irow: 0; mso-yfti-firstrow: yes; mso-yfti-lastrow: yes;&quot;&gt;
&lt;td style=&quot;width: 0%; border: 1pt solid windowtext; padding: 0cm 5.4pt; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;query {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp; NewsArticle {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; items {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; headline&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; heroImage {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thumbnailUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; originalUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; transformBaseUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;}&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 0%; border: 1pt solid windowtext; padding: 0cm 5.4pt; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;query {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp; Product {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; items {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; title&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; productImage {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thumbnailUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; originalUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; transformBaseUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; productVideo {&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thumbnailUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; originalUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; videoPreviewUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; productBrochure{&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; name&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; thumbnailUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; originalUrl&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;&amp;nbsp; }&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8pt; line-height: 115%; text-align: left;&quot;&gt;}&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;
&lt;h3&gt;&lt;strong&gt;Asset Rendering:&lt;/strong&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;table class=&quot;MsoTableGrid&quot; style=&quot;border-collapse: collapse; margin-left: 0px; margin-right: auto; width: 75.9895%; border-image: initial; height: 186px; border: medium none currentcolor;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;mso-yfti-irow: 0; mso-yfti-firstrow: yes;&quot;&gt;
&lt;td style=&quot;width: 30.8527%; border: 1pt solid windowtext; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Rendering Images&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.8999%; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Rendering Videos&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 35.227%; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Rendering Documents&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;mso-yfti-irow: 1; mso-yfti-lastrow: yes;&quot;&gt;
&lt;td style=&quot;width: 30.8527%; border-width: medium 1pt 1pt; border-style: none solid solid; border-color: currentcolor windowtext windowtext; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Basic rendering:&lt;/strong&gt;&lt;br /&gt;&amp;lt;img src=&quot;{thumbnailUrl}&quot; /&amp;gt;&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; text-align: center; line-height: normal;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;br /&gt;&lt;strong&gt;Responsive Rendering:&lt;/strong&gt;&lt;br /&gt;&amp;lt;img&lt;br /&gt;src=&quot;{transformBaseUrl}?width=200&quot; &lt;br /&gt;/&amp;gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 33.8999%; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&lt;strong&gt;Video example:&lt;/strong&gt;&lt;br /&gt;&amp;lt;video controls&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp;&amp;lt;source src=&quot;{originalUrl}&quot; /&amp;gt;&lt;br /&gt;&amp;lt;/video&amp;gt;&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; line-height: normal;&quot;&gt;&lt;strong&gt;Video Poster:&lt;br /&gt;&lt;/strong&gt;&amp;lt;img src=&quot;{thumbnailUrl}&quot; /&amp;gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 35.227%; border-width: medium 1pt 1pt medium; border-style: none solid solid none; border-color: currentcolor windowtext windowtext currentcolor; padding: 0cm 5.4pt; text-align: left; vertical-align: top;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&lt;strong&gt;PDF example:&lt;/strong&gt;&lt;br /&gt;&amp;lt;a href=&quot;{originalUrl}&quot;&amp;gt;&lt;br /&gt;&amp;nbsp; &amp;nbsp; Download PDF&lt;br /&gt;&amp;lt;/a&amp;gt;&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 0cm; text-align: center; line-height: normal;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&lt;strong&gt;Preview example:&lt;br /&gt;&lt;/strong&gt;&amp;lt;img src=&quot;{thumbnailUrl}&quot; /&amp;gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;An ideal worflow (Bynder &lt;span style=&quot;font-size: 12.0pt; line-height: 115%; font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: Aptos; mso-fareast-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: &#39;Times New Roman&#39;; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-IN; mso-fareast-language: EN-US; mso-bidi-language: AR-SA; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt;&amp;nbsp;Optimizely &lt;span style=&quot;font-size: 12.0pt; line-height: 115%; font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: Aptos; mso-fareast-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: &#39;Times New Roman&#39;; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-IN; mso-fareast-language: EN-US; mso-bidi-language: AR-SA; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt;&amp;nbsp;Frontend application):&lt;/h2&gt;
&lt;ol&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Asset will be uploaded into Bynder along with metadata.&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Asset will be marked as Public in Bynder (if asset must be available using a public URL).&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;OCP Connector will sync the asset inforamtion into Optimizely Graph.&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Authors in Optimizely SaaS CMS will be able to ses/select the asset inside the content manager/content items for referencing on relevant fields.&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Content Items will be published in Optimizely SaaS CMS.&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Frontend application (nextjs) will retrieve the page item content along with asset URLs using Graph query.&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;Appropriate URL of asset will be used to render/retrieve the asset infroamtion in the application/browser.&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;If frontend application needs asset information that is not synced in Optimizely but available in Bynder then frontend application will use Bynder APIs to retrieve the information.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Public vs Private Assets&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;One area that deserves special attention is asset visibility.&lt;/p&gt;
&lt;table class=&quot;MsoTableGrid&quot; style=&quot;border-collapse: collapse; width: 67.1769%; height: 327px; border-image: initial; border: medium none currentcolor;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 308.862px;&quot;&gt;
&lt;td style=&quot;width: 50.0644%; border: 1pt solid windowtext; padding: 0cm 5.4pt; text-align: left; vertical-align: top; height: 308.862px;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&lt;strong&gt;Public Assets&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;IsPublic = true&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Typically means:&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;line-height: 115%;&quot;&gt;Frontend can access asset directly.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;line-height: 115%;&quot;&gt;No authentication required.&lt;/li&gt;
&lt;/ul&gt;
&lt;/td&gt;
&lt;td style=&quot;width: 50.0644%; border-width: 1pt 1pt 1pt medium; border-style: solid solid solid none; border-color: windowtext windowtext windowtext currentcolor; border-image: initial; padding: 0cm 5.4pt; text-align: left; vertical-align: top; height: 308.862px;&quot;&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;&lt;strong&gt;Non-Public Assets&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;IsPublic = false&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;Potential implications:&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;line-height: 115%;&quot;&gt;Requires authentication&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;line-height: 115%;&quot;&gt;Requires authorization&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;line-height: 115%;&quot;&gt;URL will not be accessible publicly&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%;&quot;&gt;This becomes extremely important for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Extranets&lt;/li&gt;
&lt;li&gt;Employee portals&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;margin-bottom: 8.0pt; line-height: 115%; mso-list: l0 level1 lfo1; tab-stops: list 36.0pt;&quot;&gt;Restricted content&lt;/li&gt;
&lt;/ul&gt;
&lt;p style=&quot;margin-bottom: 8pt; line-height: 115%;&quot;&gt;Use &lt;a href=&quot;https://bynder-api-documentation.readme.io/reference/get_api-v4-media-id-download&quot;&gt;Retrieve asset download&lt;/a&gt; location from Bynder API to get the URL to dowlaod the asset item.&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Things I Learned&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;After exploring Bynder and the connector, several observations stood out.&lt;/p&gt;
&lt;ul&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Not every asset type exposes the same URLs&lt;br /&gt;&lt;/strong&gt;Images typically expose more transformation capabilities than videos or documents.&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Transform Base URL is incredibly useful&lt;br /&gt;&lt;/strong&gt;The Transform Base URL alone can eliminate the need for multiple image renditions.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Public vs Private matters early&lt;br /&gt;&lt;/strong&gt;Teams should decide asset visibility strategy before building the frontend application.&lt;br /&gt;Changing this later can require rework.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Things to Validate Early&lt;/strong&gt;&lt;/h2&gt;
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Metadata Availability&lt;/strong&gt;
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Not every Bynder field is necessarily synchronized.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Always validate:
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Which fields are available?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Which fields are searchable?&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Which fields appear in Graph?&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Filtering of Assets&lt;/strong&gt;
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;You may not need to have all assets in Optimizely. Ideally Assets used on your website or target channel must be synced but rest assets should be avoided.&lt;br /&gt;Read the article &lt;a href=&quot;/link/30275ac47c4843148eeda8b7d6ed282a.aspx&quot;&gt;[Planning Your Bynder DAM and Optimizely SaaS CMS Integration the Right Way: Avoiding Asset Sprawl and Unnecessary Synchronization]&lt;/a&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Private Asset Consumption&lt;/strong&gt;
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Private assets often introduce additional frontend delivery considerations.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Validate architecture before implementation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Transformation Support&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Image transformations are powerful.&lt;/li&gt;
&lt;li&gt;Equivalent functionality may not exist for every asset type.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Connector Scope&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;The connector solves many DAM scenarios, but not every possible Bynder feature, or workflow may be surfaced through the OOTB connector.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Language Translation&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Bynder does not have concept of language version of asset items hence if you need to store language specific content in your assets metadata properties then figure out where that content will be stored and how the translation workflow will be executed. One of the options to keep language specific content inside Bynder is to create language specific properties e.g. Title_en, Title_fr etc. These properties can then be read through the &lt;a href=&quot;https://bynder-api-documentation.readme.io/reference/get_api-v4-media-id&quot;&gt;Retrieve specific asset&lt;/a&gt; endpoint.&lt;/li&gt;
&lt;li&gt;Also note that&amp;nbsp; Bynder allows to set the language specific labels for the options inside single select and multi-select properties. But when you retrieve assets information using the API it only returns the default language labels. In case you need language specific labels in your frontend application then you need to get all metadata properties using &lt;a href=&quot;https://bynder-api-documentation.readme.io/reference/get_api-v4-metaproperties&quot;&gt;Retrieve metaproperties&lt;/a&gt; API endpoint.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Frequently Asked Questions&lt;/strong&gt;&lt;/h2&gt;
&lt;ol&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Does the connector synchronize custom metadata fields?&lt;br /&gt;&lt;/strong&gt;All text type metadata fields in Bynder are supposed to be exposed through synchronization but actual synchronization depends on the connector configuration. &lt;br /&gt;Always validate available fields before finalizing content models.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Can filtering of assets be set during sync configuration?&lt;br /&gt;&lt;/strong&gt;OOTB connector does not support filtering; it is developed to sync all assets.&lt;br /&gt;&lt;span class=&quot;far4bl _667h42&quot;&gt;The connector itself has no filtering UI, but selective synchronization can be achieved through Bynder&#39;s permission profiles and metadata visibility rules &amp;mdash; see &lt;a href=&quot;/link/30275ac47c4843148eeda8b7d6ed282a.aspx&quot;&gt;[Planning Your Bynder DAM and Optimizely SaaS CMS Integration the Right Way: Avoiding Asset Sprawl and Unnecessary Synchronization]&lt;/a&gt;.&lt;/span&gt;&lt;br /&gt;Or Using the Bynder API custom connector can be developed to support filtering and other required features based on your business needs.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;strong&gt;Can I call Bynder APIs directly from my frontend application?&lt;br /&gt;&lt;/strong&gt;Absolutely. A common pattern is:&amp;nbsp;DAM Connector + Bynder APIs.&amp;nbsp;&lt;br /&gt;The connector handles asset references while custom APIs handle advanced functionality.&lt;br /&gt;Use &lt;a href=&quot;https://bynder-api-documentation.readme.io/reference/get_api-v4-media-id&quot;&gt;Retrieve specific asset&lt;/a&gt; endpoint from Bynder API to retrieve metadata and URLs (including custom metadata) for a specific assets.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;strong&gt;What if information is not synchronized?&lt;br /&gt;&lt;/strong&gt;Retrieve it directly from Bynder APIs. Examples: Workflow Status, Usage Rights, Approval State, Custom Metadata.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li style=&quot;text-align: left;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;strong&gt;Can frontend applications retrieve private assets?&lt;br /&gt;&lt;/strong&gt;It depends on the DAM security model and implementation approach.&amp;nbsp;&lt;br /&gt;Possible solutions include: Authentication, Proxy APIs, Token-based access.&lt;/li&gt;
&lt;/ol&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h2 class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;The Bynder DAM Connector provides a clean bridge between enterprise asset management and modern headless content delivery.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;The most important takeaway for me was that the connector is not simply an asset picker. It establishes a relationship between:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;Bynder DAM &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Optimizely Graph &amp;amp; Optimizely CMS &lt;span style=&quot;font-family: Wingdings; mso-ascii-font-family: Aptos; mso-ascii-theme-font: minor-latin; mso-hansi-font-family: Aptos; mso-hansi-theme-font: minor-latin; mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&lt;span style=&quot;mso-char-type: symbol; mso-symbol-font-family: Wingdings;&quot;&gt;&amp;agrave;&lt;/span&gt;&lt;/span&gt; Frontend Applications&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;When implemented correctly, it enables organizations to maintain Bynder as the single source of truth for digital assets while still providing content authors with a seamless CMS authoring experience.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot;&gt;For organizations already invested in Bynder and Optimizely SaaS CMS, the connector can significantly simplify asset governance, reduce duplication, and improve overall content delivery architecture.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: left;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;h4 class=&quot;_1l4j4na1 _1qskm0h c8urk _1a0p899 _5hqrjx _667h42&quot; style=&quot;text-align: left;&quot;&gt;&#128218; Bynder + Optimizely SaaS CMS Integration Series&lt;/h4&gt;
&lt;div class=&quot;_1l4j4na3 _667h42&quot; style=&quot;text-align: left;&quot;&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;This article is the first installment of a 3-part comprehensive architecture guide:&lt;/em&gt;&lt;/div&gt;
&lt;ul class=&quot;_667h42 _1l4j4na6&quot;&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;&#128073; Part 1: Implementing the Connector &amp;mdash; Lessons Learned&lt;/strong&gt;&amp;nbsp;&lt;em class=&quot;far4bl _667h42&quot;&gt;(You are here)&lt;/em&gt;&lt;br /&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;What metadata syncs, how URLs behave, and how to query/render assets in a Next.js frontend.&lt;br /&gt;&lt;br /&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;⏭️ Part 2:&amp;nbsp;&lt;a class=&quot;_667h42 _1l4j4nac _1c9dtv3 _1by2b93 _1140xq1 _667h42&quot; href=&quot;/link/30275ac47c4843148eeda8b7d6ed282a.aspx&quot;&gt;Planning &amp;amp; Filtering &amp;mdash; Avoiding Asset Sprawl and Unnecessary Sync&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;Discover how we achieved metadata-based sync filtering with zero custom code.&lt;br /&gt;&lt;br /&gt;&lt;/em&gt;&lt;/li&gt;
&lt;li class=&quot;_667h42 _1l4j4na2&quot; style=&quot;text-align: left;&quot;&gt;&lt;strong class=&quot;far4bl _1a0p899 _667h42&quot;&gt;⏭️ Part 3:&amp;nbsp;&lt;a class=&quot;_667h42 _1l4j4nac _1c9dtv3 _1by2b93 _1140xq1 _667h42&quot; href=&quot;/link/650c1d72d9a84c28b2355e8942fc7cda.aspx&quot;&gt;Exploring Asset Lifecycle Management &amp;amp; Three-Gate Governance&lt;/a&gt;&lt;/strong&gt;&lt;br /&gt;&lt;em class=&quot;far4bl _667h42&quot;&gt;Explore a webhook-driven, three-gate model to handle asset updates, environments, and usage verification.&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;</description>            <guid>https://world.optimizely.com/blogs/vipin-banka--learnings--insights/dates/2026/7/implementing-the-bynder-dam-connector-with-optimizely-saas-cms-lessons-learned/</guid>            <pubDate>Fri, 03 Jul 2026 12:46:54 GMT</pubDate>           <category>Blog post</category></item><item> <title>Optimizely London developer meetup 2026: a round up </title>            <link>https://world.optimizely.com/blogs/scott-reed/dates/2026/7/optimizely-london-developer-meetup-2026-a-round-up-/</link>            <description>&lt;p&gt;Well, what can I say?&lt;/p&gt;
&lt;p&gt;Last night we wrapped up! Yet another London Developer Meetup, hosted at the superb Lightwell venue&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/76833ab648a340cda1bd972ff738f2f5.aspx&quot; width=&quot;638&quot; height=&quot;336&quot; /&gt;&lt;/p&gt;
&lt;p&gt;And this is also a celebration of my 10th year of co-hosting/hosting this meetup, something that has been very dear to my heart because of my love of the Optimizely community. It&#39;s always been the greatest of pleasures to organise these and help people get together, because the people I&#39;ve met, the friends I&#39;ve made, and the conversations we&#39;ve had over a couple of beers have always made everything seem more vibrant and exciting and have really made my life so much better. Thank you to everyone who&#39;s been to any of these and connected with me. You&#39;re all amazing.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;So the night, we had a great packed line up of talks&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;img src=&quot;/link/e95702782ac841ea9c0db1f42bd290d4.aspx&quot; width=&quot;830&quot; height=&quot;725&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So we kicked off with a bit of an intro and a retro from myself and Mark, talking a little bit about where we were ten years ago and sharing a number of photos!&amp;nbsp;&lt;/p&gt;
&lt;p&gt;As a really touching point, our Niteco UK/US leader and friend Mark Welland (&lt;a href=&quot;https://www.linkedin.com/in/markwelland/&quot;&gt;https://www.linkedin.com/in/markwelland/&lt;/a&gt;) arranged a couple of videos to celebrate my 10 years from Patrick Lam &lt;a href=&quot;https://www.linkedin.com/in/patrickpclam/&quot;&gt;https://www.linkedin.com/in/patrickpclam/&lt;/a&gt; Nicola Ayan (&lt;a href=&quot;https://www.linkedin.com/in/nicolaayan/)&quot;&gt;https://www.linkedin.com/in/nicolaayan/)&lt;/a&gt; and the big dog and CEO of Optimizely Alex Atzberger (&lt;a href=&quot;https://www.linkedin.com/in/aatzberger/)&quot;&gt;https://www.linkedin.com/in/aatzberger/)&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;these are all such lovely videos, and it was really, really kind of everyone to put together such touching thoughts. It really meant the world to me.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;And then we had all of the talks. Every single one of the talks was well thought out, well presented, and engaging, and I want to thank every single one of the speakers. Rather than recap it all here, you can actually view the recorded and live streamed output masterfully created by my good friend Jacob Pretorius (&lt;a href=&quot;https://www.linkedin.com/in/jacobpretorius/&quot;&gt;https://www.linkedin.com/in/jacobpretorius/&lt;/a&gt;) here&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.youtube.com/watch?v=ocnckRb179s&quot;&gt;&lt;img src=&quot;/link/e5c3a7bebafc4f94a2fbc3c7f94177a1.aspx&quot; width=&quot;948&quot; height=&quot;554&quot; /&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;and also a big thank you to Techspace and the amazing food spread that they put on. We&#39;ve been coming here a number of years, and it really is a great venue. Also, thank you so much to Satata (&lt;a href=&quot;https://www.linkedin.com/in/satatasatez/&quot;&gt;https://www.linkedin.com/in/satatasatez/&lt;/a&gt;). Patrick and Shamim (&lt;a href=&quot;https://www.linkedin.com/in/shamim605/&quot;&gt;https://www.linkedin.com/in/shamim605/&lt;/a&gt;) for helping organise this and a big thank you to every one of the speakers today.&amp;nbsp;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Mark Evard - &lt;a href=&quot;https://www.linkedin.com/in/everard/&quot;&gt;https://www.linkedin.com/in/everard/&lt;/a&gt; and thank you so much for all the kind words.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Guilherme Menezes -&amp;nbsp;&lt;a href=&quot;https://www.linkedin.com/in/guilherme-menezes-0521a715a/&quot;&gt;https://www.linkedin.com/in/guilherme-menezes-0521a715a/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Minesh Shah - &lt;a href=&quot;https://www.linkedin.com/in/minesh-shah-dev/&quot;&gt;https://www.linkedin.com/in/minesh-shah-dev/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Graham Carr - &lt;a href=&quot;https://www.linkedin.com/in/carrgraham/&quot;&gt;https://www.linkedin.com/in/carrgraham/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Simon Chapman - &lt;a href=&quot;https://www.linkedin.com/in/sgchapman/&quot;&gt;https://www.linkedin.com/in/sgchapman/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Andrew Markham - &lt;a href=&quot;https://www.linkedin.com/in/markham-andrew/&quot;&gt;https://www.linkedin.com/in/markham-andrew/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks everyone for attending, and I look forward to next year.&amp;nbsp;&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/scott-reed/dates/2026/7/optimizely-london-developer-meetup-2026-a-round-up-/</guid>            <pubDate>Fri, 03 Jul 2026 11:50:58 GMT</pubDate>           <category>Blog post</category></item><item> <title>AvantiBit Custom Settings for Optimizely CMS</title>            <link>https://www.avantibit.com/blog/avantibit-optimizely-custom-settings</link>            <description>AvantiBit Custom Settings is a free, Apache-2.0 Optimizely CMS add-on for typed, site- and language-aware configuration that stays out of content while supporting policy-based access, caching, and multi-server sync.</description>            <guid>https://www.avantibit.com/blog/avantibit-optimizely-custom-settings</guid>            <pubDate>Fri, 03 Jul 2026 00:00:00 GMT</pubDate>           <category>Blog post</category></item><item> <title>Building an experience with Visual Builder in Optimizely CMS 13</title>            <link>http://parwissmark.wordpress.com/?p=355</link>            <description>Visual Builder changes how we can think about campaign pages, landing pages and other highly curated editorial experiences in Optimizely CMS. Instead of modeling every page layout as a fixed set of content areas, editors can compose an experience from sections, rows, columns and reusable elements. That gives us more flexibility, but it also gives [&amp;#8230;]</description>            <guid>http://parwissmark.wordpress.com/?p=355</guid>            <pubDate>Thu, 02 Jul 2026 13:35:17 GMT</pubDate>           <category>Blog post</category></item><item> <title>LanguageMaster! From Managing to Mastering Languages!</title>            <link>https://world.optimizely.com/blogs/matt-pallatt-is-not-a-developer/dates/2026/7/from-managing-to-mastering-localisation/</link>            <description>&lt;p class=&quot;MsoNormal&quot;&gt;Two years ago, I released &lt;a href=&quot;https://nuget.optimizely.com/packages/mp.languagemanager.deepltranslate/1.0.10&quot;&gt;my first Optimizely add-on&lt;/a&gt;. It was an extension to the Labs.LanguageManager tool from Optimizely that allowed the user to choose to use DeepL as their translation provider. I noticed recently that it has the highest number of downloads of any NuGet package used by LanguageManager &amp;ndash; I&amp;rsquo;m very sure more to do with how many people are using DeepL rather than with the stunning code quality.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/0f2f8ab3a2e549a2a0d268b442f581c0.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In the two years since, we have used DeepL and LanguageManager with a few of our clients, and I&amp;rsquo;m sure each of them would have a significant list of issues with both the functionality and usability of LanguageManager, and more than a few would have complaints about the quality of DeepL too &amp;ndash; and I don&amp;rsquo;t particularly think the issues or complaints they&#39;re raised (and internalised) are unfounded.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;As a tool, LanguageManager (which has been newly updated to support CMS 13) allows CMS users to select a root node, then either choose to include all children, and/or all associated blocks, and then fire them at a translation endpoint, where what is returned is used to create or update a new language branch version of the source page. It&amp;rsquo;s basic, though does the job, but also has some shortcomings &amp;ndash; especially (in my humblest of opinions) with Page References in content areas, where suddenly those &amp;ldquo;children and associated content items&amp;rdquo; checkboxes can result in what you thought was a 15 item content translation job turning into 15,000 content items as the spider crawls outwards, upwards and forever on and on (this has happened, huge costs have been incurred, people have not been happy).&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;And you&amp;rsquo;re tied to one translation provider at a time &amp;ndash; maybe Azure is great for general content, but products would benefit going through DeepL? And translations into Chinese must use Baidu because it&amp;rsquo;s got the best vocab for that locale. LanguageManager can&amp;rsquo;t do that without constantly updating the settings to match the provider you have in mind.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;And the locale granularity problem, where in China for example, the many variations of dialect and character mean that the target slug as a translation target isn&#39;t ideal - you want Hong Kong oriented translations on /cn? No way!&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In small demo sites, translation management can look simple, but in the real-world of CMS and Commerce builds, content relationships, reusable blocks, products, variants, regional language requirements and even provider functionality make it much more complicated.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Enter Language Master!&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Powerful selection tools for choosing what you want to translate, including full CMS and Commerce content tree, and Smart Select functionality for batch selections!&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Multi-provider functionality for different scenarios, with translation endpoints for MS Azure, DeepL, Google Cloud, Amazon Translate, Claude, Baidu, ModernMT, OpalAI and Smartling &amp;ndash; or build your own!&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Per provider translation caching &amp;ndash; so you can&amp;rsquo;t accidentally end up repeatedly sending the same source language and content items to be translated!&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Provider routing so you can choose which configured provider delivers translations for which content!&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Chained provider routing allows you to make better use of monthly free character tiers across multiple providers. Once Azure&amp;rsquo;s free allowance is used, for example, fallback can seamlessly continue through Google&amp;rsquo;s free allowance!&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Language target override allows you to use a specific provider-supported locale, such as zh-Hant-HK, even when your site branch uses a simpler slug such as /cn/!&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Projects allow you to build translation packages over time and run them once when you&amp;rsquo;re ready to translate all your content!&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Full audit logging allows you to see if anything went wrong and why!&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Commerce support for Categories, Products and Variations!&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;And&amp;hellip; Multisite support!&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;What all of that looks like in practice...&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Language Master&amp;rsquo;s &lt;strong&gt;Tree View&lt;/strong&gt; allows an editor to select page content nodes, select block content node, select child nodes - you have full individual control over what is going to be translated. It also shows what&amp;rsquo;s already been translated, and what&amp;rsquo;s still in need of a new language version.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/fb1b443dc74346248e1a98eee837a852.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;For larger trees, &lt;strong&gt;Smart Select&lt;/strong&gt; allows for batch selections based on defined criteria &amp;ndash; content types, publish status, parent node, date modified &amp;ndash; completely extensible interface to build your own criteria for selection.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/075fa458c86c410d9f5736e9123d6a64.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Language Master has pre-built &lt;strong&gt;Translation Providers&lt;/strong&gt; for MS Azure, DeepL, Google Cloud, Amazon Translate, Claude, Baidu, ModernMT, OpalAI and Smartling &amp;ndash; all of which can be configured and activated at the same time! And a framework to allow you to build your own provider if it&amp;rsquo;s not in the list.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/f1a593308ea34f318f851a425ff135b1.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Your activated providers can then be used to create &lt;strong&gt;Routing Rules&lt;/strong&gt; for different language pairs &amp;ndash; with a fallback for if you&amp;rsquo;ve got no specific language requirements.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/3306ada08cd545cbb3e3f15e73120a84.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The same language pairs can be configured multiple times &amp;ndash; essentially &lt;strong&gt;Chaining Providers&lt;/strong&gt; - to provide fallback in the event of error &amp;ndash; or having no translation credits left.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Provider Overrides&lt;/strong&gt; mean that for content specific cases, you can abandon routing rules and send individual content items to a selected provider.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/78fc054736444a4a99faa737b4bb539c.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Language target override&lt;/strong&gt; allows the editor to define the specific language code to be used to translate into &amp;ndash; depending on provider availability!&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/6b12e4d576ff4660bedb900abccec400.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Batch Update&lt;/strong&gt; means that selected content items can have their translation properties &amp;ndash; publish status, provider choice, name and slug translation options - updated all at once.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/cdb91802d9cb424ab7d353badb2be47b.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Projects &lt;/strong&gt;update the tree view to show what is in the project and what is not.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/5602c4f19674499b952caf3dc535d6c3.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Projects can support multiple language pairs, making it possible to prepare translation work for different source and target content items, and run them as a single package when the content is ready. This means you don&amp;rsquo;t need to have separate projects for different languages &amp;ndash; though you can if you want to!&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/3c870f05a673462ba93d71073c8ecf63.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;And provides a way of batching together multiple updates over time, to be translated all at once.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/3b051cb389d64417890eebe6ba48edb5.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Audit Log&lt;/strong&gt; allows the editor to see what has been translated and when, whether any errors occurred, and if needed allows the editor to invalidate any cache that exists for the content item and provider.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/f092b61977e742a6930861a4ab034956.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;And it has &lt;strong&gt;Commerce support. &lt;/strong&gt;Language Master covers Categories, Products, and Variations &amp;mdash; not just CMS pages and blocks.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;img src=&quot;/link/6e02d19e9ec44c48ad683bd90b8440f6.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Going back to that DeepL extension: releasing it and watching it used across real projects showed me exactly where LanguageManager struggles. Not because it&#39;s a bad tool &amp;mdash; it does what it does &amp;mdash; but because real multilingual projects in production are messier than it was built to handle.&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Language Master has been designed to tidy up that mess.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The packages are available on &lt;a href=&quot;https://nuget.optimizely.com/?q=mp.languagemaster&quot;&gt;Optimizely&#39;s Nuget Feed&lt;/a&gt; for CMS and optionally Commerce.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;If you try it, I&#39;d genuinely like to hear what works, what doesn&#39;t, and what you&#39;d want to see next - I&#39;m thinking a SaaS version...?&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/matt-pallatt-is-not-a-developer/dates/2026/7/from-managing-to-mastering-localisation/</guid>            <pubDate>Thu, 02 Jul 2026 08:52:15 GMT</pubDate>           <category>Blog post</category></item><item> <title>List Properties of a Optimizely Content Type programmatically</title>            <link>https://world.optimizely.com/blogs/akash/dates/2023/10/how-to-get-a-list-of-properties-of-a-content-type-defined-in-optimizely/</link>            <description>&lt;p&gt;Properties are simply fields used to create a content type in Optimizely. Lets explore how to get a list of properties of a specific content type defined in Optimizely. These properties can be simple text, rich text, images, links, etc. The blog is useful for devs aiming to map opti content type properties while migrating content.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Content&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In Optimizely CMS, the first term you will hear is content. Content is just like items in Sitecore.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Content Type&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The different types of content could be of type page, block, media, video, image, or a custom type.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IContentTypeRepository&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;To get a list of all available content types defined in Optimizely CMS project, first, we will need an instance of IContentTypeRepository, as this is the primary API for accessing the repository methods.&lt;/p&gt;
&lt;p&gt;Through the content type repository instance, we can perform CRUD (Create, Read, Update and Delete) operations on content. Alternatively, if you only need read-only access, use the IContentLoader instance.&lt;/p&gt;
&lt;p&gt;var repository = ServiceLocator.Current.GetInstance&amp;lt;IContentTypeRepository&amp;gt;();&lt;/p&gt;
&lt;p&gt;The list() method lists all available content types (Block, Media, Page, Image, Video) in the repository.&lt;/p&gt;
&lt;p&gt;var contentTypeList = repository.List();&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/ed7ec1b5b07445e1a4cd4fe8ecf84675.aspx&quot; alt=&quot;&quot; width=&quot;640&quot; height=&quot;558&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Content type &lt;/strong&gt;- To get the content type of block or page type, we can filter the list by passing the content type.&lt;/p&gt;
&lt;p&gt;var pageTypes = repository.List().OfType&amp;lt;PageType&amp;gt;();&lt;/p&gt;
&lt;p&gt;var blockTypes = repository.List().OfType&amp;lt;BlockType&amp;gt;();&lt;/p&gt;
&lt;p&gt;By passing PageType as a parameter, we shall get all the content of the type page.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;img src=&quot;/link/03c822b310a2408aab198f39b8b999c6.aspx&quot; alt=&quot;&quot; /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;To get a specific content type, use the Load() method on the repository instance. The Load() methods have overloads, and we can get the specific content type by passing Id, Guid, ContentType, or Name as parameter.&lt;/p&gt;
&lt;p&gt;var contentType = repository.Load&amp;lt;LocationItemPage&amp;gt;();&lt;/p&gt;
&lt;p&gt;In solutions, which do not have a reference to the Optimizely CMS project example a razor class library project. The specific content type is not accessible, which is present in Optimizely Project. In such a scenario, we can use the Guid or Id saved in global constants file.&lt;/p&gt;
&lt;p&gt;var contentTypeById = contentTypeRepository.Load(contentTypeId);&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/3807614550aa4450b2dbf0814f573e5f.aspx&quot; alt=&quot;&quot; width=&quot;854&quot; height=&quot;447&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;PropertyDefinitions&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Returns a property collection containing all properties defined in a specific content type.&lt;/p&gt;
&lt;p&gt;var properties = contentType.PropertyDefinitions;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/f1f20e0a72254d4bab532b79701a0b98.aspx&quot; alt=&quot;&quot; width=&quot;745&quot; height=&quot;419&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Getting property names&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We can retrieve the properties and save them in list. we can use EditCaption property for getting display names of properties. If one needs actual property names use Name property.&lt;/p&gt;
&lt;p&gt;List Properties = new List&amp;lt;string&amp;gt;();&lt;/p&gt;
&lt;p&gt;foreach (var property in properties)&lt;/p&gt;
&lt;p&gt;&amp;nbsp;{&lt;/p&gt;
&lt;p&gt;&amp;nbsp;string propertyName = property.EditCaption;&lt;/p&gt;
&lt;p&gt;Properties.Add(propertyName);&lt;/p&gt;
&lt;p&gt;}&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/98aa5751dfdc4df4bdde68d3d773d974.aspx&quot; alt=&quot;&quot; width=&quot;769&quot; height=&quot;584&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;You can further explore PropertyDefinitions class as it gives access to other properties and methods which can be of use in development.&lt;/p&gt;
&lt;p&gt;Happy Learning!&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/akash/dates/2023/10/how-to-get-a-list-of-properties-of-a-content-type-defined-in-optimizely/</guid>            <pubDate>Thu, 02 Jul 2026 08:48:45 GMT</pubDate>           <category>Blog post</category></item><item> <title>Optimizely CMS SaaS – Chrome Extension to Stop Accidentally Editing Production</title>            <link>https://kpbasics.com/?p=8353</link>            <description>If you work with Optimizely CMS SaaS across multiple clients, you know the anxiety — multiple tabs, multiple environments, and one wrong edit away from breaking a live site. At Horizontal Digital, we manage several Optimizely CMS instances for different clients, each with production and test environments. The Optimizely UI looks identical across all of [&amp;#8230;]</description>            <guid>https://kpbasics.com/?p=8353</guid>            <pubDate>Wed, 01 Jul 2026 13:18:25 GMT</pubDate>           <category>Blog post</category></item><item> <title>Optimizely SaaS CMS Contracts: Define Shared Structure Across Content Types</title>            <link>https://kpbasics.com/?p=8339</link>            <description>&amp;#x1f4cc; Scope: This post covers Optimizely CMS (SaaS) only — using the @optimizely/cms-sdk toolchain. CMS 13 (PaaS) handles shared structure differently via .NET interfaces. When you&amp;#8217;re building a multi-content-type site, you quickly run into a problem: Blog Articles, Press Releases, and News Pages all need category and tags — but without a shared structure, you [&amp;#8230;]</description>            <guid>https://kpbasics.com/?p=8339</guid>            <pubDate>Wed, 01 Jul 2026 13:09:35 GMT</pubDate>           <category>Blog post</category></item><item> <title>Finding Thomas Part 3 - The Moment of Recognition</title>            <link>https://world.optimizely.com/blogs/ritu-madan/dates/2026/6/finding-thomas-part-3---the-moment-of-recognition/</link>            <description>&lt;h3 class=&quot;ember-view reader-text-block__heading-3&quot;&gt;Remember Thomas?&lt;/h3&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;&lt;em&gt;In digital landscape, Thomas is the returning visitor who reads everything, opens every email, converts on nothing. In standard reporting, &lt;strong&gt;he is invisible&lt;/strong&gt; &amp;mdash; absorbed into aggregate metrics that look healthy, precisely because he keeps showing up.&lt;/em&gt;&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;In &lt;span style=&quot;color: rgb(35, 111, 161);&quot;&gt;&lt;em&gt;&lt;strong&gt;&lt;a class=&quot;uPrscYCJahCprYhlPAURdHcDRCZBqqmbEI &quot; style=&quot;color: rgb(35, 111, 161);&quot; href=&quot;https://www.linkedin.com/pulse/finding-thomas-part-1-observation-post-ritu-madan-8kkwe&quot;&gt;Part 1&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;, we talked about the &lt;strong&gt;CMS&lt;/strong&gt; - how it watches Thomas&#39;s behavior, page by page, scroll by scroll, without anyone assembling that data into a story.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;In &lt;span style=&quot;color: rgb(35, 111, 161);&quot;&gt;&lt;em&gt;&lt;strong&gt;&lt;a class=&quot;uPrscYCJahCprYhlPAURdHcDRCZBqqmbEI &quot; style=&quot;color: rgb(35, 111, 161);&quot; href=&quot;https://www.linkedin.com/pulse/finding-thomas-part-2-recognition-engine-ritu-madan-wq2ef/&quot;&gt;Part 2&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt;&lt;/span&gt;, we talked about &lt;strong&gt;ODP&lt;/strong&gt; - how it takes that behavioral data and turns it into a real, scorable profile, complete with an Engagement Trajectory that tells you Thomas is Drifting before he&#39;s gone.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;Here&#39;s where we left off - the data has recognized Thomas but the experience hasn&#39;t!&lt;/p&gt;
&lt;h3 class=&quot;ember-view reader-text-block__heading-3&quot;&gt;In Part 3,&amp;nbsp; we recognize Thomas and curate his experience of your site.&lt;/h3&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;This is where &lt;strong&gt;Optimizely Personalization&lt;/strong&gt; comes into play. It translates Thomas&#39;s behavioural data profile from ODP into an experience that finally makes him feel seen without naing him or using surveillance language.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;Read the full story&amp;nbsp;&lt;em&gt;&lt;strong&gt;&lt;a href=&quot;https://www.linkedin.com/pulse/finding-thomas-part-3-moment-recognition-ritu-madan-5hvwe/&quot;&gt;&lt;span style=&quot;color: rgb(35, 111, 161);&quot;&gt;here&lt;/span&gt;&lt;/a&gt;&lt;/strong&gt;&lt;/em&gt; on how we remove the friction points and recalibrate the experience to appreciate Thomas&#39;s loyalty.&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/ritu-madan/dates/2026/6/finding-thomas-part-3---the-moment-of-recognition/</guid>            <pubDate>Fri, 26 Jun 2026 17:08:48 GMT</pubDate>           <category>Blog post</category></item><item> <title>Add more scheduled job settings from the Optimizely CMS 12 admin UI -- with OptiScheduledJob.ExtraParameters</title>            <link>https://world.optimizely.com/blogs/binh-nguyen/dates/2026/6/add-more-scheduled-job-settings-from-the-optimizely-cms-12-admin-ui----with-optischeduledjob.extraparameters</link>            <description>&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;Optimizely (EPiServer) CMS 12 ships a great scheduled-jobs framework, but it has one&amp;nbsp;frustrating gap: &lt;strong&gt;a job has nowhere to store its own configuration&lt;/strong&gt;. Want an administrator to tweak a batch size, flip a feature flag, pick a priority, or set a cut-off date for a job &amp;mdash; within Scheduled Job Settings UI directly? Out of the box you can&#39;t. Teams usually end up hard-coding values, hanging them off `appsettings.json`, adding more content type as settings type.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;OptiScheduledJob.ExtraParameters&lt;/strong&gt; closes that gap. It lets you attach a strongly-typed settings class to any custom scheduled job and edit it &lt;strong&gt;right on the job&#39;s detail page&lt;/strong&gt;&amp;nbsp;in the admin UI &amp;mdash; no extra plumbing, no custom screens.&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;✅ &lt;strong&gt;Edited by CMS admins&lt;/strong&gt; in a form rendered automatically under the default job settings&lt;/div&gt;
&lt;div&gt;✅ &lt;strong&gt;Persisted&lt;/strong&gt; in Optimizely&#39;s Dynamic Data Store&lt;/div&gt;
&lt;div&gt;✅ &lt;strong&gt;Read back&lt;/strong&gt; inside the job at execution time through a simple service&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3&gt;&lt;strong&gt;How to install&lt;/strong&gt;&lt;/h3&gt;
&lt;div&gt;The package is published to the &lt;strong&gt;Optimizely NuGet feed&lt;/strong&gt; https://nuget.optimizely.com. Register that feed as a source first, then install:&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;dotnet nuget add source https://api.nuget.optimizely.com/v3/index.json -n optimizely&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;dotnet add package OptiScheduledJob.ExtraParameters&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;Register the module once in Startup.cs:&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;using OptiScheduledJob.ExtraParameters.Infrastructure.Configuration;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; services.AddCms();&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; // ...&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; services.AddScheduledJobExtraParameters();&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;1. Define your settings&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&lt;br /&gt;Create a class deriving from ScheduledJobExtraParametersBase and decorate each property with&lt;/div&gt;
&lt;div&gt;[ExtraParametersPropertyDisplay] for its label, help text, and (optionally) dropdown options:&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;using OptiScheduledJob.ExtraParameters.Attributes;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;using OptiScheduledJob.ExtraParameters.Models;&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;code&gt;public class CleanupJobParameters : ScheduledJobExtraParametersBase&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; [ExtraParametersPropertyDisplay(DisplayName = &quot;Source folder&quot;, Description = &quot;Path to scan&quot;)]&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; public string SourceFolder { get; set; }&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; [ExtraParametersPropertyDisplay(DisplayName = &quot;Batch size&quot;, Description = &quot;Items per run&quot;)]&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; public int BatchSize { get; set; }&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; [ExtraParametersPropertyDisplay(DisplayName = &quot;Threshold&quot;, Description = &quot;Minimum match score&quot;)]&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; public decimal Threshold { get; set; }&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; [ExtraParametersPropertyDisplay(DisplayName = &quot;Send notifications&quot;)]&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; public bool SendNotifications { get; set; }&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; [ExtraParametersPropertyDisplay(DisplayName = &quot;Run after&quot;)]&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; public DateTime RunAfter { get; set; }&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; // A string[] of options renders a dropdown.&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; [ExtraParametersPropertyDisplay(DisplayName = &quot;Priority&quot;, Options = new[] { &quot;Low&quot;, &quot;Medium&quot;, &quot;High&quot; })]&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; public string Priority { get; set; }&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;strong&gt;2. Attach it to your job&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;[ScheduledPlugInWithExtraParameters] is a drop-in replacement for [ScheduledPlugIn]:&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;using EPiServer.Scheduler;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;using OptiScheduledJob.ExtraParameters.Attributes;&lt;/code&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;[ScheduledPlugInWithExtraParameters(&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; DisplayName = &quot;Unused Image Removal&quot;,&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; ExtraParameterDefinition = typeof(CleanupJobParameters))]&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;public class UnusedImageRemovalJob : ScheduledJobBase&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; // ...&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;strong&gt;3. Read the values when the job runs&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;using OptiScheduledJob.ExtraParameters.Services;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;public class UnusedImageRemovalJob : ScheduledJobBase&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;{&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; private readonly IScheduledJobExtraParametersDataService _extraParameters;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; public UnusedImageRemovalJob(IScheduledJobExtraParametersDataService extraParameters)&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; {&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; _extraParameters = extraParameters;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; public override string Execute()&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; {&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; var settings = _extraParameters.Get&amp;lt;CleanupJobParameters&amp;gt;(this.ScheduledJobId);&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; var batchSize = settings?.BatchSize ?? 100;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; // ... use the settings&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; return &quot;Done&quot;;&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; }&lt;/code&gt;&lt;/div&gt;
&lt;div&gt;&lt;code&gt;}&lt;/code&gt;&lt;/div&gt;
&lt;h3&gt;&amp;nbsp;&lt;/h3&gt;
&lt;h3&gt;&lt;strong&gt;How it looks in the admin&lt;/strong&gt;&lt;/h3&gt;
&lt;div&gt;Open &lt;strong&gt;Admin &amp;rarr; Scheduled Jobs &amp;rarr; your job&lt;/strong&gt;. Below the standard &quot;When to run&quot; controls, an&amp;nbsp;&lt;strong&gt;Extra Parameters&lt;/strong&gt; form appears automatically. Each property is rendered with the right&amp;nbsp;input control for its type &amp;mdash; text box, number, date picker, checkbox or dropdown &amp;mdash; one per row:&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/27681771fdc74a6f9d9c7891f7c4acd4.aspx&quot; width=&quot;1322&quot; height=&quot;729&quot; /&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;div&gt;&lt;strong&gt;Saving &amp;mdash; with notification&lt;/strong&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;Hit &lt;strong&gt;Save&lt;/strong&gt; on the Extra Parameters form and the values are posted back&amp;nbsp;stored. You get a clear toast notification confirming the result:&lt;/div&gt;
&lt;p&gt;&lt;img src=&quot;/link/b0e9cd4c35384f3fa1b09241e8eec286.aspx&quot; width=&quot;1306&quot; height=&quot;721&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Compatibility&lt;/strong&gt;&lt;/h3&gt;
&lt;div&gt;- &lt;strong&gt;Optimizely CMS 12&lt;/strong&gt; (EPiServer.CMS 12.x)&lt;/div&gt;
&lt;div&gt;- &lt;strong&gt;.NET 6, 8, 9 and 10&lt;/strong&gt; &amp;mdash; the package multi-targets all four runtimes&lt;/div&gt;
&lt;div&gt;- &lt;em&gt;&lt;strong&gt;Optimizely CMS 13 -&amp;nbsp; planned in future no far&lt;/strong&gt;&lt;/em&gt;&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Links&lt;/strong&gt;&lt;/h3&gt;
&lt;div&gt;- NuGet: &lt;strong&gt;Optimizely NuGet feed&lt;/strong&gt;&amp;nbsp;&amp;mdash; https://nuget.optimizely.com/&lt;/div&gt;
&lt;div&gt;- Source &amp;amp; issues: https://github.com/binhboong1802/optimizely-scheduledjob-extraparameters&lt;/div&gt;</description>            <guid>https://world.optimizely.com/blogs/binh-nguyen/dates/2026/6/add-more-scheduled-job-settings-from-the-optimizely-cms-12-admin-ui----with-optischeduledjob.extraparameters</guid>            <pubDate>Thu, 25 Jun 2026 14:25:57 GMT</pubDate>           <category>Blog post</category></item><item> <title>Automated Search &amp; Navigation to Graph Migration with Claude Code</title>            <link>https://world.optimizely.com/blogs/connor-fortin/dates/2026/6/automated-search--navigation-to-graph-migration-with-claude-code/</link>            <description>&lt;p style=&quot;font-size: 1.2rem; color: #555; margin-bottom: 8px; font-weight: 400;&quot;&gt;A Claude Code plugin that scans your S&amp;amp;N codebase, applies Graph SDK transformations, and validates the result. Install once, run one command.&lt;/p&gt;
&lt;div style=&quot;display: flex; flex-wrap: wrap; gap: 8px; margin-bottom: 32px;&quot;&gt;&lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;CMS 13&lt;/span&gt; &lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;Optimizely Graph&lt;/span&gt; &lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;Migration&lt;/span&gt; &lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;Claude Code&lt;/span&gt; &lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;Automation&lt;/span&gt; &lt;span style=&quot;background: #f0f4ff; color: #0037ff; font-size: 0.75rem; font-weight: 600; padding: 3px 10px; border-radius: 12px; display: inline-block;&quot;&gt;Search &amp;amp; Navigation&lt;/span&gt;&lt;/div&gt;
&lt;div style=&quot;background: linear-gradient(135deg,#f0f4ff 0%,#e8f0fe 100%); border: 1px solid #93c5fd; border-left: 4px solid #2563eb; border-radius: 8px; padding: 10px 28px; margin: 0 0 40px;&quot;&gt;
&lt;h3 style=&quot;margin-top: 0;&quot;&gt;TL;DR&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;cg-migrate&lt;/span&gt;&lt;/strong&gt; Claude Code plugin automates the Search &amp;amp; Navigation to Graph SDK migration.&lt;/strong&gt; It scans your .NET solution for every Find API usage, rewrites the code to use &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Optimizely.Graph.Cms.Query&lt;/span&gt;&lt;/strong&gt;, and validates the result by building the project and attributing compiler errors back to the specific transformation that caused them.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Five skills cover the full workflow:&lt;/strong&gt; &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt; runs the entire pipeline end-to-end, or use the individual skills for more control: &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; discovers all S&amp;amp;N usage and classifies complexity, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt; rewrites the code, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt; checks the build, and &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-map&lt;/span&gt;&lt;/strong&gt; handles one-off translations.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;It understands your codebase structure.&lt;/strong&gt; The scan traces dependency graphs through wrapper classes and DI registrations, so indirect consumers of Find are identified too.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;You keep control over the hard decisions.&lt;/strong&gt; When a pattern has no direct Graph equivalent (like &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;UnifiedSearch&lt;/span&gt;&lt;/strong&gt; or custom &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;FilterForVisitor&lt;/span&gt;&lt;/strong&gt; implementations), the plugin generates a decisions file and pauses for your input before continuing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Install with two commands&lt;/strong&gt; and the plugin loads on every Claude Code session automatically.&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;1. Why This Plugin Exists&lt;/h2&gt;
&lt;p&gt;The &lt;a href=&quot;/link/5ffa0c0d7b184f049358e62d7fcad94f.aspx&quot;&gt;Graph SDK blog post&lt;/a&gt; on Optimizely World covers how to write queries with &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Optimizely.Graph.Cms.Query&lt;/span&gt;&lt;/strong&gt;. If you have not read it yet, start there. It walks through &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Where()&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;SearchFor()&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Facet()&lt;/span&gt;&lt;/strong&gt;, and the rest of the API that replaces Search &amp;amp; Navigation.&lt;/p&gt;
&lt;p&gt;What the blog post does not cover is the mechanical work of actually migrating a real codebase. A typical Optimizely solution has Search &amp;amp; Navigation calls spread across dozens of files. Some are straightforward &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Search&amp;lt;T&amp;gt;().Filter().GetResult()&lt;/span&gt;&lt;/strong&gt; chains. Others are wrapped behind repository classes, injected through DI containers, or built up conditionally with &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.OrFilter()&lt;/span&gt;&lt;/strong&gt; composition. Finding all of that, understanding the dependency graph, and rewriting it file by file takes time that could be spent on the parts of a CMS 13 migration that genuinely require human judgment.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;cg-migrate&lt;/span&gt;&lt;/strong&gt; plugin handles the mechanical part. It is a set of Claude Code skills that scan your solution, apply the known API mappings from the Graph SDK blog post, flag the patterns that need human decisions, and validate the result against the compiler. You stay in control of architecture questions. The plugin handles the find-and-replace at scale.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;2. Getting Started&lt;/h2&gt;
&lt;h3&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;You need Claude Code installed and a .NET solution that currently uses the Search &amp;amp; Navigation (EPiServer Find) SDK.&lt;/p&gt;
&lt;p&gt;Before running the migration, check out a dedicated branch with no pending changes. The solution should build cleanly and all tests should pass. This gives the plugin a clean baseline so it can distinguish migration-introduced errors from pre-existing issues.&lt;/p&gt;
&lt;h3&gt;Installation&lt;/h3&gt;
&lt;p&gt;Run these two commands in Claude Code:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/plugin marketplace add episerver/content-graph-sdk-migrations
/plugin install cg-migrate@content-graph-sdk-migrations&lt;/pre&gt;
&lt;p&gt;The plugin loads automatically on every subsequent Claude Code session. No configuration files to edit.&lt;/p&gt;
&lt;h3&gt;What Gets Installed&lt;/h3&gt;
&lt;p&gt;The plugin adds five slash commands to your Claude Code session:&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Command&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Purpose&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Run the full migration pipeline end-to-end: scan, transform, validate, and fix&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Discover all S&amp;amp;N usage across the solution and produce a migration manifest&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-map&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Translate a single file or code snippet from S&amp;amp;N to Graph SDK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Apply transformations to all files identified by the scan&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Build the project and map each compiler error back to the transformation that caused it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Three Ways to Use the Plugin&lt;/h3&gt;
&lt;p&gt;You do not have to use all five commands. Pick the approach that fits where you are in your migration:&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Approach&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Commands&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;When to use&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;Full pipeline&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;You want to migrate the entire solution end-to-end in one run. The command handles scan, transform, validate, and build-fix phases automatically, pausing only for manual decisions.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;Step by step&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; &amp;rarr; &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt; &amp;rarr; &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;You want to review the scan report before transforming, re-run a single phase after making manual edits, or iterate on specific files without restarting the full pipeline.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;One-off translation&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-map&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;You want to translate a single file or code snippet, understand how a specific S&amp;amp;N pattern maps to the Graph SDK, or handle a file individually before or after a larger migration run.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;The rest of this post covers each approach in detail. If you just want to get started, skip to &lt;strong&gt;section 3&lt;/strong&gt; for the full pipeline or &lt;strong&gt;section 5&lt;/strong&gt; for one-off translations.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;3. Running the Full Migration&lt;/h2&gt;
&lt;p&gt;The fastest way to migrate is &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt;. It orchestrates the entire pipeline in a single invocation:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-all --project path/to/YourSolution.sln&lt;/pre&gt;
&lt;p&gt;If you omit &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;--project&lt;/span&gt;&lt;/strong&gt;, the plugin searches for &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.sln&lt;/span&gt;&lt;/strong&gt; files in the current directory.&lt;/p&gt;
&lt;h3&gt;What Happens&lt;/h3&gt;
&lt;p&gt;The command runs six phases sequentially:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1: Scan.&lt;/strong&gt; Invokes &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; to discover all Find SDK usage, trace dependency graphs, and classify each pattern by complexity. If no migration targets are found, the command stops early.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2: Confirm.&lt;/strong&gt; Presents a summary of what will be transformed automatically and what will require manual decisions, then pauses for your confirmation before making any changes.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3: Transform.&lt;/strong&gt; Invokes &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt; to apply all known API mappings, swap NuGet packages, and flag items for manual review.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 4: Validate.&lt;/strong&gt; Invokes &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt; to build the project and attribute compiler errors to specific transformation rules. If errors are found, it automatically retries the transformation on the failed files for a second pass.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 5: Build &amp;amp; Fix.&lt;/strong&gt; Rebuilds the project and iteratively fixes remaining compiler errors that have clear automated solutions, such as &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;CS0266&lt;/span&gt;&lt;/strong&gt; type mismatches, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;CS1061&lt;/span&gt;&lt;/strong&gt; missing members, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;CS0246&lt;/span&gt;&lt;/strong&gt; unknown types, and NuGet version conflicts. Errors that require business logic decisions are deferred for you to handle manually.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 6: Report.&lt;/strong&gt; Generates a comprehensive migration report at &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.cg-migrations/migrate-all/&lt;/span&gt;&lt;/strong&gt; that ties together the results from every phase: targets scanned, files transformed, errors fixed, and remaining manual items with prioritized next steps.&lt;/p&gt;
&lt;p&gt;The final report classifies the migration status as &lt;strong&gt;Complete&lt;/strong&gt; (all errors resolved), &lt;strong&gt;Partial&lt;/strong&gt; (some errors remain), or &lt;strong&gt;Nothing to migrate&lt;/strong&gt; (no targets found).&lt;/p&gt;
&lt;div style=&quot;border-left: 4px solid #2563eb; border-radius: 4px; padding: 16px 20px; margin: 20px 0; font-size: 0.93rem; background: #dbeafe;&quot;&gt;&lt;strong&gt;Tip&lt;/strong&gt;
&lt;p&gt;Use &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt; for the typical workflow. The individual skills (&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt;) are still available when you need to re-run a specific phase or want more control over the process.&lt;/p&gt;
&lt;/div&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;4. Scanning Your Codebase&lt;/h2&gt;
&lt;p&gt;If you want to inspect the migration scope before committing to a full run, or if you need to re-run just the scan phase, use &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; directly:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-scan --project path/to/YourSolution.sln&lt;/pre&gt;
&lt;p&gt;If you omit &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;--project&lt;/span&gt;&lt;/strong&gt;, the plugin searches for &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.sln&lt;/span&gt;&lt;/strong&gt; files in the current directory.&lt;/p&gt;
&lt;p&gt;The scan runs in four phases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1: NuGet Detection.&lt;/strong&gt; The scan parses &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.csproj&lt;/span&gt;&lt;/strong&gt; files to find which projects reference &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;EPiServer.Find&lt;/span&gt;&lt;/strong&gt; packages and what versions they use.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 2: Direct Reference Scan.&lt;/strong&gt; Using regex patterns from a built-in registry of 50+ S&amp;amp;N API patterns, the scan locates every file that calls into the Find SDK. Each match is categorized by type (filtering, facets, sorting, search, DI registration, etc.).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3: Dependency Graph Tracing.&lt;/strong&gt; This is where the scan goes beyond simple text search. It follows constructor injection, DI registrations, and wrapper class hierarchies up to 5 hops deep. If you have a &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;SearchService&lt;/span&gt;&lt;/strong&gt; that wraps &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;IClient&lt;/span&gt;&lt;/strong&gt; and a &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;SearchController&lt;/span&gt;&lt;/strong&gt; that injects &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;SearchService&lt;/span&gt;&lt;/strong&gt;, both get flagged as migration targets even though only &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;SearchService&lt;/span&gt;&lt;/strong&gt; contains direct Find API calls.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 4: Complexity Classification.&lt;/strong&gt; Every identified pattern gets one of three labels:&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Classification&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Meaning&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Example&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;direct-swap&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;1:1 Graph SDK equivalent exists&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Filter()&lt;/span&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Where()&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Take()&lt;/span&gt;&lt;/strong&gt; to &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Limit()&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;pattern-rewrite&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Needs restructuring but the approach is known&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.OrFilter()&lt;/span&gt;&lt;/strong&gt; composition to &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;BuildFilter&amp;lt;T&amp;gt;().Or()&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;manual&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;No automated equivalent, needs human decision&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;UnifiedSearch&lt;/span&gt;&lt;/strong&gt;, custom &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;FilterForVisitor&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Scan Output&lt;/h3&gt;
&lt;p&gt;The scan produces a console summary with statistics and a detailed markdown report at &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.cg-migrations/migrate-scan/scan-report.md&lt;/span&gt;&lt;/strong&gt;. The report includes every target file, the specific patterns found, the dependency tree, and the complexity breakdown.&lt;/p&gt;
&lt;div style=&quot;border-left: 4px solid #2563eb; border-radius: 4px; padding: 16px 20px; margin: 20px 0; font-size: 0.93rem; background: #dbeafe;&quot;&gt;&lt;strong&gt;Tip&lt;/strong&gt;
&lt;p&gt;Add &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.cg-migrations/&lt;/span&gt;&lt;/strong&gt; to your &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.gitignore&lt;/span&gt;&lt;/strong&gt;. This directory is for migration artifacts and should not be committed.&lt;/p&gt;
&lt;/div&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;5. Translating Individual Queries&lt;/h2&gt;
&lt;p&gt;For one-off translations or to understand how a specific pattern maps to the Graph SDK, use &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-map&lt;/span&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-map&lt;/pre&gt;
&lt;p&gt;Point it at a file or paste a code snippet. The skill applies 17 translation rules covering the full S&amp;amp;N API surface.&lt;/p&gt;
&lt;h3&gt;Before and After&lt;/h3&gt;
&lt;div style=&quot;margin: 16px 0;&quot;&gt;
&lt;div style=&quot;font-size: 0.75rem; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; padding: 6px 14px; border-radius: 8px 8px 0 0; color: #fff; background: #ef4444;&quot;&gt;Before - Search &amp;amp; Navigation&lt;/div&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 0px 0px 8px 8px; padding: 0.5rem; overflow-x: auto; margin: 0px 0px 16px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;&lt;span style=&quot;color: #000080;&quot;&gt;var&lt;/span&gt; result = searchClient.&lt;span style=&quot;color: #0000cc;&quot;&gt;Search&lt;/span&gt;&amp;lt;&lt;span style=&quot;color: #004d40;&quot;&gt;ArticlePage&lt;/span&gt;&amp;gt;()
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;For&lt;/span&gt;(&lt;span style=&quot;color: #a31515;&quot;&gt;&quot;chocolate cake&quot;&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;InField&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Title, &lt;span style=&quot;color: #800000;&quot;&gt;3.0&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;InField&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Summary, &lt;span style=&quot;color: #800000;&quot;&gt;2.0&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Filter&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Category.&lt;span style=&quot;color: #0000cc;&quot;&gt;Match&lt;/span&gt;(&lt;span style=&quot;color: #a31515;&quot;&gt;&quot;Dessert&quot;&lt;/span&gt;))
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Filter&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.IsPublished.&lt;span style=&quot;color: #0000cc;&quot;&gt;Match&lt;/span&gt;(&lt;span style=&quot;color: #000080;&quot;&gt;true&lt;/span&gt;))
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;TermsFacetFor&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Category)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;OrderByDescending&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.PublishDate)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Take&lt;/span&gt;(&lt;span style=&quot;color: #800000;&quot;&gt;10&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Skip&lt;/span&gt;(&lt;span style=&quot;color: #800000;&quot;&gt;20&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;GetResult&lt;/span&gt;();&lt;/pre&gt;
&lt;div style=&quot;font-size: 0.75rem; font-weight: bold; text-transform: uppercase; letter-spacing: 1px; padding: 6px 14px; border-radius: 8px 8px 0 0; color: #fff; background: #16a34a;&quot;&gt;After - Graph SDK&lt;/div&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 0px 0px 8px 8px; padding: 0.5rem; overflow-x: auto; margin: 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;&lt;span style=&quot;color: #000080;&quot;&gt;var&lt;/span&gt; result = &lt;span style=&quot;color: #000080;&quot;&gt;await&lt;/span&gt; &lt;span style=&quot;color: #660033;&quot;&gt;_graphClient&lt;/span&gt;
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;QueryContent&lt;/span&gt;&amp;lt;&lt;span style=&quot;color: #004d40;&quot;&gt;ArticlePage&lt;/span&gt;&amp;gt;()
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;SearchFor&lt;/span&gt;(&lt;span style=&quot;color: #a31515;&quot;&gt;&quot;chocolate cake&quot;&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;UsingField&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Title, boost: &lt;span style=&quot;color: #800000;&quot;&gt;3&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;UsingField&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Summary, boost: &lt;span style=&quot;color: #800000;&quot;&gt;2&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Where&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Category &lt;span style=&quot;color: #6b3a00;&quot;&gt;==&lt;/span&gt; &lt;span style=&quot;color: #a31515;&quot;&gt;&quot;Dessert&quot;&lt;/span&gt; &lt;span style=&quot;color: #6b3a00;&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; x.IsPublished)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Facet&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.Category)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;OrderBy&lt;/span&gt;(x &lt;span style=&quot;color: #6b3a00;&quot;&gt;=&amp;gt;&lt;/span&gt; x.PublishDate, &lt;span style=&quot;color: #004d40;&quot;&gt;OrderDirection&lt;/span&gt;.Descending)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Limit&lt;/span&gt;(&lt;span style=&quot;color: #800000;&quot;&gt;10&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;Skip&lt;/span&gt;(&lt;span style=&quot;color: #800000;&quot;&gt;20&lt;/span&gt;)
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;IncludeTotal&lt;/span&gt;()
    .&lt;span style=&quot;color: #0000cc;&quot;&gt;GetAsContentAsync&lt;/span&gt;();&lt;/pre&gt;
&lt;/div&gt;
&lt;p&gt;The &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-map&lt;/span&gt;&lt;/strong&gt; skill is useful for building intuition about the mapping rules before running a full transformation, and for handling files you want to review individually.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;6. Transforming the Full Codebase&lt;/h2&gt;
&lt;p&gt;Once you have reviewed the scan report and understand the scope, run the full transformation:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-transform --project path/to/YourSolution.sln&lt;/pre&gt;
&lt;p&gt;You can optionally pass the scan report path if you have already run &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt;:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-transform --project path/to/YourSolution.sln --scan-report .cg-migrations/migrate-scan/scan-report.md&lt;/pre&gt;
&lt;h3&gt;How the Transform Works&lt;/h3&gt;
&lt;p&gt;The transform runs in six phases:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 1: Decision Resolution.&lt;/strong&gt; For every pattern classified as &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;manual&lt;/span&gt;&lt;/strong&gt; in the scan, the transform generates a decisions file at &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.cg-migrations/migrate-decisions.md&lt;/span&gt;&lt;/strong&gt;. This file groups patterns and presents strategy options. The plugin pauses here and asks you to choose a strategy for each group before continuing.&lt;/p&gt;
&lt;p&gt;Example decision groups and strategies:&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Pattern Group&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Suggested Strategy&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;UnifiedSearch&lt;/span&gt;&lt;/strong&gt; (searches across multiple content types)&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;type-specific-queries&lt;/span&gt;&lt;/strong&gt; (create separate &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;QueryContent&amp;lt;T&amp;gt;()&lt;/span&gt;&lt;/strong&gt; per type)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;ContentIndexer&lt;/span&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Track()&lt;/span&gt;&lt;/strong&gt; calls&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;remove&lt;/span&gt;&lt;/strong&gt; (comment out, no Graph equivalent for direct indexing)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Custom site/visitor filters&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;custom-implementation&lt;/span&gt;&lt;/strong&gt; (you provide the replacement logic)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.UsingSynonyms()&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;per-filter-synonym&lt;/span&gt;&lt;/strong&gt; (move to &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.Match(&quot;value&quot;, SynonymSlot.One)&lt;/span&gt;&lt;/strong&gt;)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;strong&gt;Phase 2: NuGet Package Setup.&lt;/strong&gt; Adds &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;Optimizely.Graph.Cms.Query&lt;/span&gt;&lt;/strong&gt; to the relevant projects and tracks the S&amp;amp;N packages for removal.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 3: Code Transformation.&lt;/strong&gt; Each file gets 13 transformation steps applied in sequence: namespace updates, DI registration changes, query entry points, full-text search, filtering, sorting, pagination, facets, projections, execution (all made async), result access patterns, manual pattern strategies, and cleanup of orphaned &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;using&lt;/span&gt;&lt;/strong&gt; statements.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 4: Cleanup.&lt;/strong&gt; Removes &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;using EPiServer.Find&lt;/span&gt;&lt;/strong&gt; statements that are no longer needed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 5: Build Validation.&lt;/strong&gt; Runs &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;dotnet build&lt;/span&gt;&lt;/strong&gt; and auto-fixes common issues like NuGet conflicts and generic constraint mismatches (the Graph SDK requires &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;where T : class, IContentData&lt;/span&gt;&lt;/strong&gt; rather than just &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;IContentData&lt;/span&gt;&lt;/strong&gt;). Iterates up to 2 cycles.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Phase 6: Reporting.&lt;/strong&gt; Generates a transform report at &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;.cg-migrations/migrate-transform/transform-report.md&lt;/span&gt;&lt;/strong&gt; with per-file results.&lt;/p&gt;
&lt;div style=&quot;border-left: 4px solid #f59e0b; border-radius: 4px; padding: 16px 20px; margin: 20px 0; font-size: 0.93rem; background: #fef3c7;&quot;&gt;&lt;strong&gt;The decisions file persists across runs&lt;/strong&gt;
&lt;p&gt;If you run &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt; again, it reads your previous decisions. You can edit the file directly to change strategies for specific patterns or files.&lt;/p&gt;
&lt;/div&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;7. Validating the Result&lt;/h2&gt;
&lt;p&gt;After the transform completes, run validation:&lt;/p&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;/migrate-validate --project path/to/YourSolution.sln&lt;/pre&gt;
&lt;p&gt;The validation phase does more than just run &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;dotnet build&lt;/span&gt;&lt;/strong&gt;. It parses every compiler error, matches it against a built-in lookup table of known migration-related error signatures, and attributes each failure to the specific transformation rule that likely caused it.&lt;/p&gt;
&lt;h3&gt;Validation Output&lt;/h3&gt;
&lt;p&gt;The report separates errors into three buckets:&lt;/p&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Bucket&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Migration-caused (high confidence)&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;File was transformed AND error matches a known migration pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Possibly migration-related (medium confidence)&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Error matches a known cause but the file was not directly transformed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Pre-existing / out-of-scope&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Error does not match any migration pattern&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Each error includes the file path, line number, error code, message, and the likely cause with a suggested fix.&lt;/p&gt;
&lt;h3&gt;Example Error Attribution&lt;/h3&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;&lt;span style=&quot;color: #004d40;&quot;&gt;CS1061&lt;/span&gt; in &lt;span style=&quot;color: #660033;&quot;&gt;SearchService.cs&lt;/span&gt;:&lt;span style=&quot;color: #800000;&quot;&gt;42&lt;/span&gt;
  &lt;span style=&quot;color: #a31515;&quot;&gt;&#39;IContentQuery&amp;lt;ArticlePage&amp;gt;&#39; does not contain a definition for &#39;TotalMatching&#39;&lt;/span&gt;
  Likely cause: Rule 11 (Result Access)
  Suggested fix: Add &lt;span style=&quot;color: #0000cc;&quot;&gt;.IncludeTotal()&lt;/span&gt; to the query chain and access &lt;span style=&quot;color: #0000cc;&quot;&gt;result.Total&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;After reporting, the validation skill offers to re-run &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt; on just the failed files for a second pass (max 2 rounds). This catches cases where the first pass produced valid but incomplete transformations.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;8. Full Workflow at a Glance&lt;/h2&gt;
&lt;pre style=&quot;background: rgb(230, 228, 227); color: rgb(30, 41, 59); border-radius: 8px; padding: 0.5rem; overflow-x: auto; margin: 16px 0px; font-family: &#39;SF Mono&#39;, &#39;Cascadia Code&#39;, &#39;Fira Code&#39;, Consolas, &#39;Courier New&#39;, monospace; font-size: 0.85rem; line-height: 1.6;&quot;&gt;&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# 1. Check out a clean branch&lt;/em&gt;&lt;/span&gt;
git checkout -b feature/graph-migration

&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# 2. Run the full migration&lt;/em&gt;&lt;/span&gt;
/migrate-all --project src/MySolution.sln

&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# 3. Make decisions for manual patterns when prompted&lt;/em&gt;&lt;/span&gt;

&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# 4. Review the migration report&lt;/em&gt;&lt;/span&gt;
&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# (open .cg-migrations/migrate-all/*-migration-report.md)&lt;/em&gt;&lt;/span&gt;

&lt;span style=&quot;color: #2e2e2e;&quot;&gt;&lt;em&gt;# 5. Fix any remaining manual items and commit&lt;/em&gt;&lt;/span&gt;&lt;/pre&gt;
&lt;p&gt;That is the simplest path. If you need more control, the individual skills (&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-transform&lt;/span&gt;&lt;/strong&gt;, &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-validate&lt;/span&gt;&lt;/strong&gt;) can be run separately and repeated as needed. The decisions file and scan report persist between runs, so you can iterate without losing your choices.&lt;/p&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: 2px solid #e2e8f0;&quot;&gt;9. What the Plugin Handles vs. What You Handle&lt;/h2&gt;
&lt;table style=&quot;width: 100%; border-collapse: collapse; margin: 16px 0; font-size: 0.9rem;&quot;&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;The plugin handles&lt;/th&gt;
&lt;th style=&quot;background: #1e293b; color: #fff; font-weight: 600; text-align: left; padding: 10px 14px;&quot;&gt;You handle&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Finding every S&amp;amp;N API call across the solution&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Reviewing the scan report for completeness&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Tracing wrapper classes and DI dependency chains&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Deciding strategies for &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;manual&lt;/span&gt;&lt;/strong&gt; patterns&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Applying the 17 known API translation rules&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Custom filter/visitor logic that has no Graph equivalent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Making methods async when execution changes to &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;GetAsync()&lt;/span&gt;&lt;/strong&gt; / &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;GetAsContentAsync()&lt;/span&gt;&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Business logic changes (e.g., if &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;UnifiedSearch&lt;/span&gt;&lt;/strong&gt; was used to merge results, you decide how to restructure)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Adding generic constraints (&lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;class, IContentData&lt;/span&gt;&lt;/strong&gt;)&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Integration test updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Attributing compiler errors to specific transformation rules&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;Verifying that query results are functionally equivalent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;NuGet package additions&lt;/td&gt;
&lt;td style=&quot;padding: 9px 14px; border-bottom: 1px solid #e2e8f0; vertical-align: top;&quot;&gt;NuGet package removals (tracked but left for you to confirm)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;hr style=&quot;border: none; border-top: 1px solid #e2e8f0; margin: 40px 0;&quot; /&gt;
&lt;h2 style=&quot;font-size: 1.65rem; font-weight: bold; color: #0f172a; margin-top: 56px; margin-bottom: 16px; padding-bottom: 8px; border-bottom: none;&quot;&gt;Looking Ahead&lt;/h2&gt;
&lt;p&gt;The plugin&#39;s pattern registry will continue to grow as partners encounter additional S&amp;amp;N patterns during real-world migrations.&lt;/p&gt;
&lt;p&gt;If you run into a Search &amp;amp; Navigation pattern that the plugin does not handle, the validation report will call it out. File an issue on the GitHub repository at &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;episerver/content-graph-sdk-migrations&lt;/span&gt;&lt;/strong&gt; so the pattern can be added to the registry.&lt;/p&gt;
&lt;h3&gt;Next Steps&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;Install the plugin with &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/plugin marketplace add episerver/content-graph-sdk-migrations&lt;/span&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Run &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-all&lt;/span&gt;&lt;/strong&gt; on your solution to migrate end-to-end, or start with &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; to preview the scope first&lt;/li&gt;
&lt;li&gt;Review the migration report and fix any remaining manual items&lt;/li&gt;
&lt;li&gt;Read the &lt;a href=&quot;/link/5ffa0c0d7b184f049358e62d7fcad94f.aspx&quot;&gt;Graph SDK blog post&lt;/a&gt; to understand the API you are migrating to&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;strong&gt;Resources:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;/link/5ffa0c0d7b184f049358e62d7fcad94f.aspx&quot;&gt;Introducing the Optimizely CMS 13 Graph SDK&lt;/a&gt; (the companion blog post covering the Graph SDK API)&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://github.com/episerver/content-graph-sdk-migrations&quot;&gt;Plugin Repository: episerver/content-graph-sdk-migrations&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;div style=&quot;border-left: 4px solid #16a34a; border-radius: 4px; padding: 16px 20px; margin: 20px 0; font-size: 0.93rem; background: #dcfce7;&quot;&gt;&lt;strong&gt;Start with the scan&lt;/strong&gt;
&lt;p&gt;Running &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;/migrate-scan&lt;/span&gt;&lt;/strong&gt; is read-only. It does not modify any files. You can run it against any branch at any time to understand the scope of the migration before committing to the transformation.&lt;/p&gt;
&lt;/div&gt;
&lt;p style=&quot;margin-top: 32px; font-size: 0.85rem; color: #888; font-style: italic;&quot;&gt;This guide is based on the &lt;strong&gt;&lt;span style=&quot;color: #8b0000;&quot;&gt;cg-migrate&lt;/span&gt;&lt;/strong&gt; Claude Code plugin for migrating Search &amp;amp; Navigation to the Optimizely Graph SDK. The plugin is actively maintained and the pattern registry grows with each release.&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/connor-fortin/dates/2026/6/automated-search--navigation-to-graph-migration-with-claude-code/</guid>            <pubDate>Wed, 24 Jun 2026 17:58:56 GMT</pubDate>           <category>Blog post</category></item><item> <title>Migrating from Find to Graph: Lessons Learned from a Real CMS 13 Project</title>            <link>https://world.optimizely.com/blogs/binh-nguyen/dates/2026/6/some-found-issues-when-migrating-find-to-optimizely-graph/</link>            <description>&lt;p class=&quot;FirstParagraph&quot;&gt;While migrating a search solution from Optimizely Search &amp;amp; Navigation (Find) to Optimizely Graph in CMS 13, I encountered several issues that were not immediately obvious from the documentation.&lt;/p&gt;
&lt;p class=&quot;MsoBodyText&quot;&gt;Most of these issues were discovered through experimentation, debugging startup errors, investigating generated Graph schemas, and comparing behavior with Search &amp;amp; Navigation.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoBodyText&quot;&gt;Here are details about them:&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&lt;strong&gt;1. Graph Conventions Only Existing Starting from CMS 13.1.0&lt;/strong&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;isSelectedEnd&quot;&gt;It took me quite some time to figure out how to apply Graph Conventions based on the following documentation while working on a CMS 13.0.0 project:&lt;/p&gt;
&lt;p class=&quot;isSelectedEnd&quot;&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/indexing-conventions&quot;&gt;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/indexing-conventions&lt;/a&gt;&lt;/p&gt;
&lt;p class=&quot;isSelectedEnd&quot;&gt;The documentation describes Graph Conventions using APIs such as:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services.ConfigureGraphConventions(...)&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;OR&lt;br /&gt;&lt;br /&gt;&lt;code&gt;services.AddContentGraph(configureConventions: c =&amp;gt;
{
    //add conventions here
});&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;span class=&quot;OperatorTok&quot;&gt;However, I was unable to find this API in a CMS 13.0.0 implementation.&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;isSelectedEnd&quot;&gt;After further investigation, I discovered that the Graph Convention API was introduced in CMS 13.1.0 together with Optimizely.Graph.Cms 13.1.0 and is not available in earlier CMS 13 releases.&lt;/p&gt;
&lt;p&gt;This initially caused some confusion because the documentation is published under the CMS 13 documentation section without clearly indicating the minimum version required for the feature.&lt;/p&gt;
&lt;p&gt;My recommendation is to use CMS 13.1.0 or later if you plan to leverage Graph Conventions during your migration. And It would be helpful if the documentation included version-specific notes or minimum version requirements for Graph Convention APIs, as this could save developers a considerable amount of troubleshooting time during migration projects.&lt;/p&gt;
&lt;p class=&quot;MsoBodyText&quot;&gt;&lt;strong&gt;2. Extension Methods Work for Queries but Not for Facets&lt;span style=&quot;font-size: 12.0pt; font-family: &#39;Aptos&#39;,sans-serif; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: Aptos; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: &#39;Times New Roman&#39;; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA;&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;One of the first surprises I encountered was that extension methods included through Graph Conventions can be queried successfully but cannot be used for faceting.&lt;br /&gt;Here is sample code:&lt;br /&gt;&lt;br /&gt;- Configuration&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;NormalTok&quot;&gt;services&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;FunctionTok&quot;&gt;ConfigureGraphConventions&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt;conventions &lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;OperatorTok&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;NormalTok&quot;&gt;&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;conventions&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;NormalTok&quot;&gt;&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;FunctionTok&quot;&gt;ForInstancesOf&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt;StandardPage&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;NormalTok&quot;&gt;&lt;span style=&quot;mso-spacerun: yes;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;FunctionTok&quot;&gt;IncludeField&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt;x &lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; x&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;FunctionTok&quot;&gt;ContentTypeName&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;(),&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; IndexingType&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;FunctionTok&quot;&gt;Searchable&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;);&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;OperatorTok&quot;&gt;});&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;- Extension method:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public static string ContentTypeName(this ISitePageData sitePageData)
{
    return sitePageData.GetOriginalType().Name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;SourceCode&quot;&gt;However, when attempting to create a facet using the extension method:&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;code&gt;&lt;span class=&quot;NormalTok&quot;&gt;query&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;FunctionTok&quot;&gt;Facet&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt;x &lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;=&amp;gt;&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; x&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;FunctionTok&quot;&gt;ContentTypeName&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;());&lt;br /&gt;&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&lt;br /&gt;I saw this error&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&lt;img src=&quot;/link/52e5237e18cf42718fe3a17a10072ee9.aspx&quot; width=&quot;1029&quot; height=&quot;664&quot; /&gt;&lt;br /&gt;&lt;br /&gt;I tried running the same facet query directly in Graph Explorer, and it worked as expected. This leads me to believe that the issue may originate from the Optimizely Graph Client API when it builds the query from a lambda expression. However, I&#39;m not sure whether this behavior is intentional or if it should be considered a bug.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Existing Find implementations that rely on calculated fields for faceting may require redesign when migrating to Graph.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;3. Search By Base Type Works Differently Than Search &amp;amp; Navigation&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;In Search &amp;amp; Navigation, it is common to search across multiple content types by using a shared base class or marker interface.&lt;/p&gt;
&lt;p class=&quot;MsoBodyText&quot;&gt;Examples:&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;code&gt;&lt;span class=&quot;NormalTok&quot;&gt;Search&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt;SitePageData&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;or&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;code&gt;&lt;span class=&quot;NormalTok&quot;&gt;Search&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt;ISearchableContent&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&amp;gt;()&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;Many developers expect the same approach to work in Optimizely Graph. Unfortunately, Graph uses a different model and does not automatically support these patterns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;- What does not work&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;The following approaches do not create a shared Graph schema that can be queried across all implementing content types.&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;&lt;span style=&quot;mso-bookmark: what-does-not-work;&quot;&gt;Simple interfaces:&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;code&gt;&lt;span style=&quot;mso-bookmark: what-does-not-work;&quot;&gt;&lt;span class=&quot;KeywordTok&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;KeywordTok&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; ISearchableContent&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;OperatorTok&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;OperatorTok&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;&lt;span style=&quot;mso-bookmark: what-does-not-work;&quot;&gt;Abstract base classes:&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;code&gt;&lt;span style=&quot;mso-bookmark: what-does-not-work;&quot;&gt;&lt;span class=&quot;KeywordTok&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;KeywordTok&quot;&gt;abstract&lt;/span&gt; &lt;span class=&quot;KeywordTok&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; SearchablePage &lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; PageData&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;OperatorTok&quot;&gt;{&lt;/span&gt;&lt;br /&gt;&lt;span class=&quot;OperatorTok&quot;&gt;}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;Although these patterns work well in Search &amp;amp; Navigation, Optimizely Graph does not automatically generate a queryable Graph contract from them.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;- What works&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;To query multiple content types through a shared schema, Optimizely Graph requires a Graph Contract.&lt;/p&gt;
&lt;p class=&quot;MsoBodyText&quot;&gt;For example:&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;code&gt;&lt;span class=&quot;OperatorTok&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt;ContentType&lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;]&lt;/span&gt;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;KeywordTok&quot;&gt;public&lt;/span&gt; &lt;span class=&quot;KeywordTok&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; ISitePageData&lt;/span&gt;&lt;/code&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;The contract must then be implemented by each content type that should participate in the shared schema:&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;&lt;code&gt;&lt;span class=&quot;KeywordTok&quot;&gt;public class&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; ArticlePage &lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; ISitePageData&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;&lt;br /&gt;&lt;code&gt;&lt;span class=&quot;KeywordTok&quot;&gt;public class&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; NewsPage &lt;/span&gt;&lt;span class=&quot;OperatorTok&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;NormalTok&quot;&gt; ISitePageData&lt;/span&gt;&lt;/code&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;When content is synchronized to Graph, a shared Graph type is generated for the contract, allowing queries across all implementing content types.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Content Type Management UI Behavior&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;isSelectedEnd&quot;&gt;One side effect of using a Graph Contract is that the interface becomes visible in the CMS Content Type Management UI.&lt;/p&gt;
&lt;p class=&quot;isSelectedEnd&quot;&gt;For example, after adding the &lt;code&gt;&lt;span class=&quot;text-token-text-primary cursor-text rounded-sm&quot;&gt;[ContentType]&lt;/span&gt;&lt;/code&gt; attribute to the interface:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;&lt;span class=&quot;text-token-text-primary cursor-text rounded-sm&quot;&gt;[ContentType]&lt;/span&gt;
public interface ISitePageData
{
}&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;isSelectedEnd&quot;&gt;the contract appears as a content type in the CMS administration interface as following:&lt;br /&gt;&lt;img src=&quot;/link/abee47fc9c3149f891781f28a055797b.aspx&quot; width=&quot;1437&quot; height=&quot;414&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;This behavior can be surprising at first, especially since the interface is not intended to be created or edited by content editors. However, this is currently the mechanism Optimizely Graph uses to discover and generate shared schema contracts.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Key takeaway:&lt;/strong&gt; In Optimizely Graph, interfaces annotated with &lt;code&gt;[ContentType]&lt;/code&gt; enable cross-type queries. Base class inheritance does not.&lt;br /&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Search architectures based on inheritance hierarchies or marker interfaces must be redesigned using Graph Contracts. This can affect query models, schema design, and migration effort.&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;4. Using the Content Type Management UI to Change a Property&#39;s Indexing Type&lt;/strong&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;/link/0c261ffa36a241f09ab67bea6b4d32e6.aspx&quot; width=&quot;1147&quot; height=&quot;535&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; The indexing convention API cannot be used to exclude a field from Graph indexing. It only supports extension methods for calculated properties, not actual content type properties.&lt;/p&gt;
&lt;p&gt;I tried to add this below to disable an actual field:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;services.AddContentGraph(configureConventions: c =&amp;gt;
{
    c.ForInstancesOf&amp;lt;StandardPage&amp;gt;().IncludeField(x =&amp;gt; x.ContentAreaCssClass, IndexingType.Disabled);
});&lt;br /&gt;&lt;/code&gt;&lt;br /&gt;Here is the error when I try to disable a field from indexing via convention:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;/link/c483e294bb81491b89e2937c0d7b958e.aspx&quot; width=&quot;792&quot; height=&quot;268&quot; /&gt;&lt;/pre&gt;
&lt;p&gt;To disable indexing for a field, use the Content Type Management UI or apply the following attribute to the property in your content type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[IndexingType(IndexingType.Disabled)]
public virtual bool HideSiteFooter { get; set; }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;5. &lt;span style=&quot;font-size: 12.0pt; font-family: &#39;Aptos&#39;,sans-serif; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: Aptos; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: &#39;Times New Roman&#39;; mso-bidi-theme-font: minor-bidi; mso-ansi-language: EN-US; mso-fareast-language: EN-US; mso-bidi-language: AR-SA;&quot;&gt;Graph Contracts and Content Types Must Use the Same IndexingType&lt;br /&gt;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;When working with Graph Contracts, I discovered an unexpected validation rule that can prevent the application from starting.&lt;/p&gt;
&lt;p class=&quot;MsoBodyText&quot;&gt;Optimizely Graph validates property metadata across the entire contract hierarchy during startup. If the same property exists on both a Graph Contract and a content type, the IndexingType must be identical everywhere.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Example&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;Graph Contract:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;[ContentType]
public interface ISitePageData
{    
    string ContentTypeName { get; }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;Base content type:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public abstract class SitePageData : PageData, ISitePageData
{
    [GraphProperty(IndexingType.Queryable)]
    public virtual string ContentTypeName =&amp;gt;
    GetOriginalType().Name;
}&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;FirstParagraph&quot;&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&lt;br /&gt;Here is the error you will see if this happens:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;/link/2162fb9599484f8cb164cddc1b8897a3.aspx&quot; width=&quot;849&quot; height=&quot;535&quot; /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Inconsistent indexing metadata can prevent the application from starting. This validation rule becomes especially important when multiple teams maintain shared contracts and content models.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&lt;strong&gt;6.&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;&lt;strong&gt;Getter-only/fallback properties are included in the Graph schema, but their indexed values are null&lt;br /&gt;&lt;/strong&gt;&lt;span class=&quot;OperatorTok&quot;&gt;&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;For example:&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;public string ContentAreaCssClass =&amp;gt; &quot;teaserblock&quot;;&lt;/code&gt;&lt;/pre&gt;
&lt;pre&gt;&lt;code&gt;public virtual string TeaserText
{
    get
    {
        var teaserText = this.GetPropertyValue(p =&amp;gt; p.TeaserText);

        // Use explicitly set teaser text, otherwise fall back to description
        return !string.IsNullOrWhiteSpace(teaserText)
            ? teaserText
            : MetaDescription;
    }
    set =&amp;gt; this.SetPropertyValue(p =&amp;gt; p.TeaserText, value);
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Here are the their value when indexing:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;/link/f52a342aacf54f4c9cad1852c93e61dd.aspx&quot; width=&quot;935&quot; height=&quot;461&quot; /&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Impact: &lt;/strong&gt;Properties that appear to work correctly in CMS may produce unexpected Graph results. Search queries, filters, and facets relying on computed values may silently return incorrect data.&lt;strong&gt;&lt;br /&gt;&lt;br /&gt;7. Extension Methods Cannot Be Added to a Graph Contract as Calculated Fields&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;SourceCode&quot;&gt;&lt;span class=&quot;OperatorTok&quot;&gt;When using a Graph Contract, extension methods cannot be added as calculated fields on the contract itself.&lt;br /&gt;Here is the error that I got when trying to do this:&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;/link/12b8f476d6424d569475e365043348c1.aspx&quot; width=&quot;779&quot; height=&quot;264&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Impact:&lt;/strong&gt; Shared Graph Contracts cannot be enriched with convention-based calculated fields. Developers may need to duplicate calculated properties across content types or redesign their schema strategy.&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h3&gt;
&lt;p&gt;Optimizely Graph provides a powerful and flexible search platform, but it differs significantly from Search &amp;amp; Navigation in several areas.&lt;/p&gt;
&lt;p&gt;When migrating existing Find implementations, pay particular attention to:&lt;/p&gt;
&lt;p&gt;- Graph Contracts&lt;br /&gt;- Graph Convention limitations&lt;br /&gt;- Faceting behavior&lt;br /&gt;- Property indexing rules&lt;br /&gt;- Calculated fields&lt;/p&gt;
&lt;p&gt;Understanding these differences early can save significant debugging and migration effort.&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/binh-nguyen/dates/2026/6/some-found-issues-when-migrating-find-to-optimizely-graph/</guid>            <pubDate>Wed, 24 Jun 2026 11:26:37 GMT</pubDate>           <category>Blog post</category></item><item> <title>Optimizely: Upgrade Opti-ID and .NET 10 in CMS 12</title>            <link>https://madhuanbalagan.com/?p=5000</link>            <description>&lt;p&gt;Many Optimizely customers are planning their roadmap around a future migration to Optimizely CMS 13. As a result, upgrades such as Opti ID adoption and&amp;#46;&amp;#46;&amp;#46;&lt;/p&gt;
&lt;p&gt;The post &lt;a href=&quot;https://madhuanbalagan.com/optimizely-upgrade-opti-id-and-net-10-in-cms-12&quot;&gt;Optimizely: Upgrade Opti-ID and .NET 10 in CMS 12&lt;/a&gt; appeared first on &lt;a href=&quot;https://madhuanbalagan.com&quot;&gt;Madhu Anbalagan&amp;#039;s Blog&lt;/a&gt;.&lt;/p&gt;
</description>            <guid>https://madhuanbalagan.com/?p=5000</guid>            <pubDate>Tue, 23 Jun 2026 16:22:29 GMT</pubDate>           <category>Blog post</category></item><item> <title>Understanding Optimizely Graph: Caching, Webhooks &amp; Avoiding Stale Content (Optimizely SaaS CMS)</title>            <link>https://kpbasics.com/?p=8321</link>            <description>&amp;#x1f4cc; Scope: This post covers Optimizely CMS (SaaS) only — using the official @optimizely/cms-sdk and @optimizely/cms-cli packages with Next.js 15. If you&amp;#8217;re on Optimizely CMS 12 (PaaS/DXP), the caching architecture and tooling are different. See the DXP ISR docs for that path. Your editor hit Publish. Five minutes later the page still shows the old [&amp;#8230;]</description>            <guid>https://kpbasics.com/?p=8321</guid>            <pubDate>Tue, 23 Jun 2026 04:28:27 GMT</pubDate>           <category>Blog post</category></item><item> <title>Optimizely Content APIs: the Setup the Docs Don&#39;t Walk You Through</title>            <link>https://world.optimizely.com/blogs/andre-gabriel-coetzee/dates/2026/6/optimizely-content-apis-the-setup-the-docs-dont-walk-you-through/</link>            <description>&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;CMS 13 is pushing things firmly in the direction of Optimizely Graph, but plenty of teams are still running on older CMS versions, or have good reasons to stick with the Content Delivery, Content Definitions, or Content Management APIs regardless of what version they&#39;re on. This guide is for those teams.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;What follows is a step-by-step walkthrough to get any of the content APIs up and running, tested locally, and fully understood, in one place. No jumping between API reference pages, no piecing together fragments from several different resources. Just the things the documentation doesn&#39;t make obvious, learned the hard way.&lt;/p&gt;
&lt;hr class=&quot;border-border-200 border-t-0.5 my-3 mx-1.5&quot; /&gt;
&lt;h3 class=&quot;text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold&quot;&gt;&lt;strong&gt;The mental model first&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Optimizely uses OpenID Connect (via a library called OpenIddict under the hood) to issue JWT bearer tokens. When you want a system to be able to call one of the content APIs, you define it as an OpenID Connect application, either in code, in the CMS Admin UI, or both. We&#39;ll cover the specifics of each in the steps below.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&quot;Application&quot; in this context is not referring to your CMS instance or front-end site, it refers to discrete client identities registered specifically for machine-to-machine communication. Your CMS can have as many of these as you need.&lt;/p&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&lt;strong&gt;Why grant_type=client_credentials and not something else&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;OAuth 2.0 has several grant types: different flows for getting a token, each suited to a different kind of requester or use case.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;strong&gt;authorization_code&lt;/strong&gt;&amp;nbsp;is for interactive users: a person clicks login, gets redirected, enters their credentials, and the app receives a token on their behalf.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;strong&gt;client_credentials&lt;/strong&gt;&amp;nbsp;is for machine-to-machine communication. Your service acts as itself, not on behalf of a user. There are no redirects, it simply exchanges its credentials directly for a token.&lt;/p&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&lt;strong&gt;Why the token endpoint is at /connect/token&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;This is OpenIddict&#39;s default endpoint path, and OpenIddict is the OpenID Connect server library Optimizely uses under the hood. Optimizely didn&#39;t invent this URL, it&#39;s baked into the library. The &lt;strong&gt;/api/episerver&lt;/strong&gt;&amp;nbsp;prefix in front of it is the actual Optimizely part of the route, sitting in the same legacy episerver namespace you&#39;ll see across the older API paths.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;The flow from here is straightforward: you request an access token for one of these applications, then pass that token in subsequent requests to the content APIs. Importantly, the access rights you configure in the CMS are tied to the application identity itself, so when a request comes in using that token, content access is evaluated against whatever permissions that application has been granted.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;/link/97584b3856524d738de8085f065eccdb.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-6axZYk-gPv/0d7f2a7de1e85c0b2044c8e8f0f8d8592c1549a00a4746a00110d39d57f2a00ea426e35a907df27fefe33102d25f33b8158227cf15f4e51bef79f26d202ef1f636a7da0e82114cb5dc624aaddad115be213b1da5054a9af57d4bfbf223a6c0f0f6565710?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;em&gt;The Add User/Group dropdown showing the Applications section with two OpenID applications listed&lt;/em&gt;&lt;/p&gt;
&lt;hr class=&quot;border-border-200 border-t-0.5 my-3 mx-1.5&quot; /&gt;
&lt;h3 class=&quot;text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold&quot;&gt;&lt;strong&gt;Let&#39;s set it all up&lt;/strong&gt;&lt;/h3&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&lt;strong&gt;Step 1: Install the required NuGet packages&lt;/strong&gt;&lt;/h4&gt;
&lt;div class=&quot;relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100&quot;&gt;
&lt;div class=&quot;overflow-x-auto&quot;&gt;
&lt;pre class=&quot;code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5&quot;&gt;&lt;code&gt;dotnet add package EPiServer.OpenIDConnect
dotnet add package EPiServer.OpenIDConnect.UI # Optional&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;You&#39;ll also need the API package for whichever API you&#39;re securing:&lt;/p&gt;
&lt;ul class=&quot;[li_&amp;amp;]:mb-0 [li_&amp;amp;]:mt-1 [li_&amp;amp;]:gap-1 [&amp;amp;:not(:last-child)_ul]:pb-1 [&amp;amp;:not(:last-child)_ol]:pb-1 list-disc flex flex-col gap-1 pl-8 mb-3&quot;&gt;
&lt;li class=&quot;font-claude-response-body whitespace-normal break-words pl-2&quot;&gt;Content Delivery API: &lt;strong&gt;EPiServer.ContentDeliveryApi.Cms&lt;/strong&gt;&lt;/li&gt;
&lt;li class=&quot;font-claude-response-body whitespace-normal break-words pl-2&quot;&gt;Content Management API: &lt;strong&gt;EPiServer.ContentManagementApi&lt;/strong&gt;&lt;/li&gt;
&lt;li class=&quot;font-claude-response-body whitespace-normal break-words pl-2&quot;&gt;Content Definitions API: &lt;strong&gt;EPiServer.ContentDefinitionsApi&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;strong&gt;Version gotcha:&lt;/strong&gt; Make sure your &lt;strong&gt;EPiServer.OpenIDConnect &lt;/strong&gt;version is compatible with your CMS version. Mismatched versions are a common source of silent failures at startup.&lt;/p&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&lt;strong&gt;Step 2: Wire up the configuration in code&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;In your &lt;strong&gt;Startup.cs&lt;/strong&gt;, you need to configure OpenID Connect and register whichever content APIs you need:&lt;/p&gt;
&lt;div class=&quot;relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100&quot;&gt;
&lt;div class=&quot;overflow-x-auto&quot;&gt;
&lt;pre class=&quot;code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5&quot;&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
{
    // ASP.NET Identity must be configured before OpenID Connect
    services.AddCmsAspNetIdentity&amp;lt;ApplicationUser&amp;gt;();

    services.AddOpenIDConnect&amp;lt;ApplicationUser&amp;gt;(
        useDevelopmentCertificate: _webHostingEnvironment.IsDevelopment(),
        createSchema: true,
        options =&amp;gt;
        {
            // Seeding an application here is optional: see note below
            options.Applications.Add(new OpenIDConnectApplication
            {
                ClientId = &quot;your-client-id&quot;,
                ClientSecret = &quot;your-client-secret&quot;,
                Scopes =
                {
                    &quot;epi_content_delivery&quot;,
                    &quot;epi_content_management&quot;,
                    &quot;epi_content_definitions&quot;
                }
            });
        });

    services.AddOpenIDConnectUI(); // Optional: adds the OpenID Connect panel in CMS Admin

    services.AddContentDeliveryApi(OpenIDConnectOptionsDefaults.AuthenticationScheme);
    services.AddContentDefinitionsApi(OpenIDConnectOptionsDefaults.AuthenticationScheme);
    services.AddContentManagementApi(OpenIDConnectOptionsDefaults.AuthenticationScheme);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;A few things worth noting here:&lt;/p&gt;
&lt;ul class=&quot;[li_&amp;amp;]:mb-0 [li_&amp;amp;]:mt-1 [li_&amp;amp;]:gap-1 [&amp;amp;:not(:last-child)_ul]:pb-1 [&amp;amp;:not(:last-child)_ol]:pb-1 list-disc flex flex-col gap-1 pl-8 mb-3&quot;&gt;
&lt;li class=&quot;font-claude-response-body whitespace-normal break-words pl-2&quot;&gt;Each API registration method accepts an authentication scheme parameter, don&#39;t leave it out. Without it, the API has no way to validate incoming Bearer tokens and will return a &lt;strong&gt;401&lt;/strong&gt; regardless of whether your token is valid. Pass &lt;strong&gt;OpenIDConnectOptionsDefaults.AuthenticationScheme&lt;/strong&gt; to wire them up correctly.&lt;/li&gt;
&lt;li class=&quot;font-claude-response-body whitespace-normal break-words pl-2&quot;&gt;&lt;strong&gt;useDevelopmentCertificate &lt;/strong&gt;: tying this to &lt;strong&gt;IsDevelopment() &lt;/strong&gt;means it uses a local dev certificate in your local environment and expects a real one in production. On DXP, certificates are provided automatically via &lt;strong&gt;EPiServer.CloudPlatform.Cms&lt;/strong&gt; 1.6.1 or later.&lt;/li&gt;
&lt;li class=&quot;font-claude-response-body whitespace-normal break-words pl-2&quot;&gt;Scopes: each scope string controls which API that client is permitted to call, and must match the scope you pass when requesting a token. There are constants available if you&#39;d prefer not to use raw strings: &lt;strong&gt;ContentDeliveryOptionsDefaults.Scope&lt;/strong&gt;, &lt;strong&gt;ContentDefinitionsApiOptionsDefaults.Scope&lt;/strong&gt;, and &lt;strong&gt;ContentManagementApiOptionsDefaults.Scope&lt;/strong&gt;.&lt;/li&gt;
&lt;li class=&quot;font-claude-response-body whitespace-normal break-words pl-2&quot;&gt;Seeding applications in code is optional. The &lt;strong&gt;options.Applications.Add(...)&lt;/strong&gt; block pre-creates the client on startup, which is convenient for local development. If you&#39;d rather manage clients entirely through the UI, you can omit it, that&#39;s what the &lt;strong&gt;AddOpenIDConnectUI()&lt;/strong&gt; line enables. It adds an OpenID Connect section under Settings in CMS Admin where you can create and manage applications directly.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-oki8fxiyA7/5cd57dd6794f296df6654bc4c7aa473b1171a4d8575e67bd58ded795e9c955eead6210f9123ca6f85e7f93ea9de301c69d838208b36c8325f6744862c30110e55fd837c8291ec1448d6c817c7bd3e8ff859e13f6e235447f2ac3d73256f2466a0dfb76c4?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;em&gt;The &quot;OpenID Connect&quot; settings panel can be seen in the screenshot above.&lt;/em&gt;&lt;/p&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&lt;strong&gt;Step 3: Request a token&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Once you have an application configured, either in code or the UI, you first need to request an access token for the application before calls to any of the content APIs can be made.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Using curl:&lt;/p&gt;
&lt;div class=&quot;relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100&quot;&gt;
&lt;div class=&quot;overflow-x-auto&quot;&gt;
&lt;pre class=&quot;code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5&quot;&gt;&lt;code&gt;curl -X POST https://your-site.com/api/episerver/connect/token \
  -H &quot;Content-Type: application/x-www-form-urlencoded&quot; \
  -d &quot;grant_type=client_credentials&amp;amp;client_id=your-client-id&amp;amp;client_secret=your-client-secret&amp;amp;scope=epi_content_management&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Using Postman:&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-gPVIKzvOJE/f7bf91e744372274b5dccfdc85dd0dbc9baa8eb91fdee7b93a4b8c26793ee8898b698a77b9c5aa805a5fc3934d04b8642cbc3a6059ffaa92136afd1eaa2eb5f17688bd706702a0fc3613ac6f7c6d74fb7898db17dbd5b35368fd65fae32753032b11c7e6?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Set the request to POST, the URL to your token endpoint, and under the Body tab select &lt;strong&gt;x-www-form-urlencoded&lt;/strong&gt;. Add the four key-value pairs: &lt;strong&gt;grant_type, client_id, client_secret, scope&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;A successful response looks like this:&lt;/p&gt;
&lt;div class=&quot;relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100&quot;&gt;
&lt;div class=&quot;overflow-x-auto&quot;&gt;
&lt;pre class=&quot;code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5&quot;&gt;&lt;code&gt;{
  &quot;access_token&quot;: &quot;eyJhbGci...&quot;,
  &quot;expires_in&quot;: 3599,
  &quot;token_type&quot;: &quot;Bearer&quot;
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Copy the &lt;strong&gt;access_token&lt;/strong&gt; value, you&#39;ll use it in Step 5.&lt;/p&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&lt;strong&gt;Step 4: Assign CMS access rights to the client&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;This is the most commonly missed step, and it causes some of the most confusing symptoms, you have a valid token, your requests aren&#39;t getting &lt;strong&gt;401s&lt;/strong&gt;, but you&#39;re getting empty results or unexpected &lt;strong&gt;403s&lt;/strong&gt;.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;The API client you created is effectively a user in the CMS. Like any user, it needs to be granted access rights to the content it&#39;s trying to read or write. There are different levels you could configure access rights, let&#39;s get into them below.&lt;/p&gt;
&lt;h5 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&amp;nbsp;&lt;/h5&gt;
&lt;h5 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&lt;strong&gt;Global access rights&lt;/strong&gt;&lt;/h5&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Global access rights apply at the page or section level in your content tree and cascade down to every item beneath. For instance, if you want to deny a specific OpenID application Read access to a sensitive area, say, an &quot;Admin&quot; page or a &quot;Members Only&quot; section, you set the restriction at that page, and the cascade ensures every sub-page inherits the same rule automatically. You don&#39;t have to configure each one individually.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-wHVz_SRQT6/9a2b8822c3e7ca4442dfc503adbbff00f14ed9b74eedbd81d1487dec35f33061b21d46266513d0c1e8ecbc519ea9c4fe60e0db4cdf5c8676fc955aad580be95add7cc628e35c54434f4363ddf43a528a0c579d79c3413007238721d09e47b0710261574c?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;em&gt;On this level, either all content is returned, or none of it. Either 200-OK, or 403-Forbidden&lt;/em&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Navigate to Settings &amp;rarr; Set Access Rights, select the page or section you want the client to access, and add it using Add User/Group. Your registered applications (from either the code or created in the CMS on the OpenID Connect settings panel) will appear under the Applications group in the dropdown.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Grant it the appropriate permissions: Read is sufficient for Content Delivery, while Content Management will need Read, Change, and Publish depending on what operations you need to perform. Check Apply settings for all subitems to cascade the rights down the content tree.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-G7Oqc_d9dv/65f22110078ca502ef75b1a83a1ec3652580830c21791120f685a2cfde53b42d62737429b8ba88f183d645b66eb5160468ef90752518b2e807fd94ba6fff3b580442c4c65a742453a0e8a73515650aa577db9adad1b41ccb824c0997d8618475f3621c33?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;em&gt;alloy-client application granted Read access on the Start page, cascading to all subitems.&lt;/em&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;strong&gt;Why this matters:&lt;/strong&gt; Skipping this step produces one of two outcomes depending on your setup: either the API returns a &lt;strong&gt;403&lt;/strong&gt; Forbidden response, or it returns content that was never actually restricted to begin with, because the Everyone group already has read access. In the latter case everything appears to be working, but your access rights configuration isn&#39;t doing anything. If you ever tighten down content permissions, your client will silently lose access.&lt;/p&gt;
&lt;h5 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&amp;nbsp;&lt;/h5&gt;
&lt;h5 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&lt;strong&gt;Content-level access rights (per page/block instance in the tree)&lt;/strong&gt;&lt;/h5&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Content-level access rights give you more granular control than the global settings screen, you can restrict access to specific pages or blocks directly in the content tree rather than applying a blanket rule across everything.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;A practical example: imagine you have a pricing page that should only be visible to authenticated partners. Rather than locking down your entire content tree, you can grant your API client access to everything by default and then explicitly restrict access on those specific items, or invert it entirely, grant no global access, and only open up the specific content the client needs to see.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-KagMkB0nHI/84fd374988f4ffa674e61c110c8dd272a70b53a3aaac9b9e69a3c7a2f7904af1773ebb6a4731948214519ccbc5ec37577bafd38a338a450b09e5e0eba3bb6fa71cdd6284c0442e856b1467f4de13af0e9fd093cf7735eb69e73f71e0c32465a8cf3f00c1?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;em&gt;Same request, different response. The restricted client&#39;s &quot;Pricing&quot; entry isn&#39;t returned as a 403 error, it&#39;s simply omitted from the response. This is what makes content-level access rights powerful: the client doesn&#39;t need to know what they can&#39;t see, and the API does the filtering server-side.&lt;/em&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;The result isn&#39;t binary. It&#39;s not just 200 or 403, you can build quite precise access models by combining global and content-level rights.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Content-level access rights are set directly on a specific page or block in the edit interface. To access them, right-click the item in the content area or page tree and select Edit, then look for the Visible to panel at the top of the properties view. If access is unrestricted it will show as Everyone. Click Manage to open the Access Rights dialog and configure it the same way as the global screen.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-qR4ivN8SRr/b1a50ba1bf085a982d94ee754c078da101225a16e25244fc5d9c8cbc736292fe097f308e83577c3f01d0fae8184840d72d542e812eb4618722716dc813d7e5abb3de10c714b93db366a20b4bd0b3c5b580d83a9ddbd9f031491b687fa4d36d3d1d50f4ca?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;em&gt;Right-clicking a content item in the page tree to access its properties&lt;/em&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-WSEoq3HxlV/50e6bbbae79aa96c3d964669a0a78de6d46fef1b38a276d48351652090e0cf572a26a24277995b9aac202280dd6e1a98f69eb35f29ab8c264b53d408910f12febb1db17a875ab48629dde4cf5385c47fd04443d133025250ed1f71e4beddb28d649acdcf?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;em&gt;The &quot;Visible to&quot; panel showing the current access restriction status for a content item, with the Manage link to open the Access Rights dialog&lt;/em&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-gRug85CPa2/a655f207b12969e892ee42f18c06fe4559edc2458edd8eac4fdba97ca66f1b57940a77f4656e4e94deb5d320983ab7ce7b56f93992910a7c1f502243c1294c8c8349eb52f165b0cbd6caddda4cbe605aaf827322729400de2e1d68bc28f44516d684351c?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;em&gt;The Access Rights dialog for a specific content item, with alloy-client granted Read access and &quot;Inherit settings from parent item&quot; unchecked to override the global defaults&lt;/em&gt;&lt;/p&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&amp;nbsp;&lt;/h4&gt;
&lt;h4 class=&quot;text-text-100 mt-2 -mb-1 text-base font-bold&quot;&gt;&lt;strong&gt;Step 5: Make your first authenticated request&lt;/strong&gt;&lt;/h4&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;With your token in hand (from Step 3) and access rights set, you can now call the API. Pass the token as a Bearer token in the &lt;strong&gt;Authorization&lt;/strong&gt; header.&lt;/p&gt;
&lt;div class=&quot;relative group/copy bg-bg-000/50 border-0.5 border-border-400 rounded-lg focus:outline-none focus-visible:ring-2 focus-visible:ring-accent-100&quot;&gt;
&lt;div class=&quot;overflow-x-auto&quot;&gt;
&lt;pre class=&quot;code-block__code !my-0 !rounded-lg !text-sm !leading-relaxed p-3.5&quot;&gt;&lt;code&gt;curl -X GET https://your-site.com/api/episerver/v3.0/content/{contentGuid} \
  -H &quot;Authorization: Bearer eyJhbGci...&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-FU_Ev1Aesh/e10d121a20a2164e0dae719606c8455da4b0249791f5133404aa422e9e1305da7a25b2c0c706bad935e45143206bb1573e2b9cc0d2ba6bd276a2b647b477549c2853b76b35191888168aaa288e0c1580f4596e7bf7d5c0283f5f076a95e09b06e0cebea2?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-NXSO-5LtU5/e6aa4fcd051b0c43b89b8c85ad1dce2c781e14eb93a6f63afb206b3780777bf8e57bab1dadce5aa8e54b7a205305f2ba10bfb1a792846708e43936e9ae6a37e80ab382f0de3587e031b5aaa2dc4a88bf2655eece10f86e21527fd89bd1e5f87d155ff6b0?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;em&gt;Success response from the Content Delivery API (200 - OK)&lt;/em&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;However, if I revoke read access from the OpenId Application, I get the following:&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-qxuy8jsqAm/3bb819b8f43ca3a5307fb37c86c495da49bb3b98fede2645dcb989df111a4d3581549553ca3323489dbc9c169cdfbba8cfcf395c34c048d66d598408810c86281c422c293e4bed5605e2a0e7099c49380d8c3bbc2d3725707840509617be42aa044340b0?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;img src=&quot;https://codaio.imgix.net/docs/-XvL0D-nmX/blobs/bl-4bM8czjC1c/1f9f13813cdbbf1744799c9aa89168fde0b36192909142daf589b5707d800ec9b9c91de53a2dfe3bf26c28d318cf550e9cedf3f32a18daea6b22f5dd0f884ca723c2ec77b1a9270724da6dc853706a241ee58975287d316102a1a095bef86ee8849e61bb?fit=max&amp;amp;fm=webp&amp;amp;lossless=true&quot; alt=&quot;image.png&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;em&gt;Forbidden response from Content Delivery API (403 - Forbidden)&lt;/em&gt;&lt;/p&gt;
&lt;hr class=&quot;border-border-200 border-t-0.5 my-3 mx-1.5&quot; /&gt;
&lt;h3 class=&quot;text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold&quot;&gt;&lt;strong&gt;Common errors and what they actually mean&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;For the last example, the &lt;strong&gt;403 &lt;/strong&gt;is exactly what we&#39;d expect, but it&#39;s worth understanding the difference between a &lt;strong&gt;401&lt;/strong&gt; and a &lt;strong&gt;403&lt;/strong&gt;, since they&#39;re easy to confuse and point to very different problems.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;strong&gt;401 Unauthorized&lt;/strong&gt; means the API doesn&#39;t recognise or can&#39;t validate the token itself. Either it&#39;s malformed, it&#39;s expired, or the API isn&#39;t configured to accept it. Check that you&#39;re passing &lt;strong&gt;OpenIDConnectOptionsDefaults.AuthenticationScheme &lt;/strong&gt;into your API registrations in &lt;strong&gt;Startup.cs&lt;/strong&gt;, that your token hasn&#39;t expired (3599 seconds), and that your &lt;strong&gt;client_id&lt;/strong&gt; and &lt;strong&gt;client_secret&lt;/strong&gt; match exactly what&#39;s registered in CMS Admin.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;strong&gt;403 Forbidden&lt;/strong&gt; means the token is valid and recognised, but the application it belongs to doesn&#39;t have permission to access that content. This is the access rights problem covered in the previous step, the API knows who you are, it just won&#39;t let you in.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;strong&gt;Token endpoint returns 404.&lt;/strong&gt; The OpenID Connect middleware isn&#39;t registered, or the package isn&#39;t installed. Confirm the NuGet package is installed and correctly configured in &lt;strong&gt;Startup.cs&lt;/strong&gt;.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;strong&gt;invalid_client error from the token endpoint.&lt;/strong&gt; The &lt;strong&gt;client_id&lt;/strong&gt; or &lt;strong&gt;client_secret&lt;/strong&gt; doesn&#39;t match what&#39;s registered in CMS Admin (or code). These must be identical, including case.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;strong&gt;invalid_scope error from the token endpoint.&lt;/strong&gt; The scope you&#39;re requesting (&lt;strong&gt;epi_content_management&lt;/strong&gt;, etc.) doesn&#39;t match what was registered for the client in CMS Admin.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;&lt;strong&gt;unsupported_grant_type from the token endpoint.&lt;/strong&gt; The client was not registered with the &lt;strong&gt;client_credentials&lt;/strong&gt; grant type. Check the application configuration in CMS Admin and ensure Client Credentials is selected as a permitted grant type.&lt;/p&gt;
&lt;hr class=&quot;border-border-200 border-t-0.5 my-3 mx-1.5&quot; /&gt;
&lt;h3 class=&quot;text-text-100 mt-3 -mb-1 text-[1.125rem] font-bold&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;Getting the Optimizely content APIs working for the first time involves piecing together information from several different sources, the official docs, community posts, and a fair amount of trial and error. Hopefully this post brings it all into one place and saves someone the same legwork.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal&quot;&gt;If you&#39;re already on CMS 13 or considering the move, Optimizely Graph changes the delivery layer significantly and much of the authentication setup described here won&#39;t apply in the same way. But for teams on CMS 12 or those still needing to use any of the content APIs, this remains the path.&lt;/p&gt;</description>            <guid>https://world.optimizely.com/blogs/andre-gabriel-coetzee/dates/2026/6/optimizely-content-apis-the-setup-the-docs-dont-walk-you-through/</guid>            <pubDate>Mon, 22 Jun 2026 13:31:38 GMT</pubDate>           <category>Blog post</category></item></channel>
</rss>