<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blogs</title><link href="http://world.optimizely.com" /><updated>2026-03-12T02:21:00.0000000Z</updated><id>https://world.optimizely.com/blogs/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Optimizely Commerce vs Composable Commerce: What Should You Do with CMS 13?</title><link href="https://world.optimizely.com/blogs/aniket-gadre/dates/2026/3/my-pov-on-optimizely-cms-13-/" /><id>&lt;p&gt;As organizations modernize their digital experience platforms, a common architectural question emerges:&amp;nbsp;Should we continue using Optimizely Commerce with CMS 13, or move to a composable commerce platform?&lt;/p&gt;
&lt;p&gt;This decision is becoming increasingly important as companies adopt headless frontends, API-driven architectures, and AI-powered content workflows. While Optimizely continues to provide a strong enterprise CMS platform, the broader commerce ecosystem has evolved significantly in recent years.&lt;/p&gt;
&lt;p&gt;In this post, I&#39;ll break down the two primary approaches, the trade-offs between them, and how to determine which model is right for your organization.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Traditional Optimizely Stack: CMS + Commerce&lt;/h2&gt;
&lt;p&gt;Historically, most enterprise Optimizely implementations used a tightly integrated stack combining CMS and Commerce.&lt;/p&gt;
&lt;h3&gt;Typical Architecture&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Frontend (MVC / Next.js) -&amp;gt; Optimizely CMS -&amp;gt; Optimizely Commerce Connect 14 -&amp;gt; Catalog / Cart /Orders
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CMS manages content, pages, and marketing experiences.&lt;/li&gt;
&lt;li&gt;Commerce manages the product catalog, pricing, cart, checkout, and orders.&lt;/li&gt;
&lt;li&gt;Both systems run within the same application environment.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Advantages&lt;/h3&gt;
&lt;p&gt;The integrated approach offers several benefits:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Strong content-commerce integration&lt;/strong&gt;&lt;br /&gt;Editors can easily blend marketing content with product experiences.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Built-in commerce functionality&lt;/strong&gt;&lt;br /&gt;Commerce includes catalog management, promotions, pricing, carts, and order management.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Mature enterprise platform&lt;/strong&gt;&lt;br /&gt;Optimizely Commerce has powered many large-scale digital commerce implementations.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Unified editorial experience&lt;/strong&gt;&lt;br /&gt;Marketing and merchandising teams operate within a single system.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Challenges&lt;/h3&gt;
&lt;p&gt;However, this architecture can introduce limitations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Scaling commerce independently from CMS can be difficult.&lt;/li&gt;
&lt;li&gt;Deployments and releases are often tightly coupled.&lt;/li&gt;
&lt;li&gt;Customization can become complex over time.&lt;/li&gt;
&lt;li&gt;Innovation cycles may lag behind newer SaaS commerce platforms.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These challenges are one reason many organizations are exploring a different approach.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Rise of Composable Commerce&lt;/h2&gt;
&lt;p&gt;In recent years, many companies have shifted toward composable commerce architectures, where content and commerce platforms are separated and integrated through APIs.&lt;/p&gt;
&lt;h3&gt;Typical Architecture&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Frontend (Next.js / React) -&amp;gt; Optimizely CMS 13 -&amp;gt; GraphQL / APIs -&amp;gt; Composable Commerce Platform
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Examples of composable commerce platforms include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;commercetools&lt;/li&gt;
&lt;li&gt;Shopify&lt;/li&gt;
&lt;li&gt;Elastic Path&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In this model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CMS focuses on content and experience&lt;/li&gt;
&lt;li&gt;Commerce platforms handle transactions, catalogs, pricing, and orders&lt;/li&gt;
&lt;li&gt;The frontend integrates both systems via APIs.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Benefits&lt;/h3&gt;
&lt;p&gt;Composable commerce introduces several architectural advantages.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Independent scalability&lt;/strong&gt;&lt;br /&gt;Commerce services can scale separately from content platforms.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Faster innovation&lt;/strong&gt;&lt;br /&gt;Modern SaaS commerce vendors release features rapidly.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Best-of-breed architecture&lt;/strong&gt;&lt;br /&gt;Organizations can choose specialized platforms for each capability.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Better alignment with headless development&lt;/strong&gt;&lt;br /&gt;API-first commerce platforms integrate seamlessly with frameworks like Next.js and React.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Trade offs&lt;/strong&gt;:&lt;/p&gt;
&lt;p&gt;However, composable commerce also introduces complexity.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Integration work increases.&lt;/li&gt;
&lt;li&gt;Architecture governance becomes more important.&lt;/li&gt;
&lt;li&gt;Editorial experiences may require additional tooling to replicate traditional CMS-commerce workflows.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Why This Conversation Is Happening Now&lt;/h2&gt;
&lt;p&gt;Three major industry trends are driving this architectural shift.&lt;/p&gt;
&lt;h3&gt;1. Headless Frontends&lt;/h3&gt;
&lt;p&gt;Many organizations are moving to modern frontend frameworks such as Next.js and React.&lt;/p&gt;
&lt;p&gt;These frameworks work best with API-first services, making composable commerce platforms a natural fit.&lt;/p&gt;
&lt;h3&gt;2. Rapid Innovation in Commerce Platforms&lt;/h3&gt;
&lt;p&gt;Commerce vendors like commercetools and Elastic Path are delivering rapid innovation in areas such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;subscription commerce&lt;/li&gt;
&lt;li&gt;marketplace models&lt;/li&gt;
&lt;li&gt;advanced promotions&lt;/li&gt;
&lt;li&gt;global scaling capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;3. Optimizely&amp;rsquo;s Strategic Focus&lt;/h3&gt;
&lt;p&gt;Optimizely has been heavily investing in:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;content management&lt;/li&gt;
&lt;li&gt;experimentation&lt;/li&gt;
&lt;li&gt;personalization&lt;/li&gt;
&lt;li&gt;AI workflows through Opal&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Commerce remains part of the ecosystem, but many organizations are evaluating whether external commerce platforms better align with modern architecture strategies.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;When Optimizely Commerce Still Makes Sense&lt;/h2&gt;
&lt;p&gt;For many existing customers, staying with Optimizely Commerce remains the most practical choice.&lt;/p&gt;
&lt;p&gt;Continuing with Commerce Connect is typically ideal when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You already operate an Optimizely Commerce implementation&lt;/li&gt;
&lt;li&gt;Catalog complexity is moderate&lt;/li&gt;
&lt;li&gt;Editorial and merchandising teams rely on tight CMS integration&lt;/li&gt;
&lt;li&gt;Replatforming costs would be significant&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For these organizations, CMS 13 paired with Commerce 14 remains a stable and proven architecture.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;When Composable Commerce Is the Better Choice&lt;/h2&gt;
&lt;p&gt;Composable commerce may be the better option when:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Building a new commerce platform&lt;/li&gt;
&lt;li&gt;Operating at global scale&lt;/li&gt;
&lt;li&gt;Supporting marketplaces or subscription models&lt;/li&gt;
&lt;li&gt;Adopting microservices-based architectures&lt;/li&gt;
&lt;li&gt;Delivering experiences across multiple channels (web, mobile, kiosks, apps)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In these scenarios, separating the experience layer from the transaction engine can offer significant flexibility.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;The Hybrid Model Many Enterprises Are Adopting&lt;/h2&gt;
&lt;p&gt;Interestingly, many organizations are landing somewhere in the middle.&lt;/p&gt;
&lt;p&gt;Instead of replacing Optimizely CMS, they use it as the experience orchestration layer, while delegating commerce operations to a composable platform.&lt;/p&gt;
&lt;h3&gt;Hybrid Architecture&lt;/h3&gt;
&lt;pre&gt;&lt;code&gt;Next.js Frontend -&amp;gt; Optimizely CMS -&amp;gt; Composable Commerce API -&amp;gt; ERP / PIM / Payment Services
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In this approach:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;CMS manages content and experience orchestration&lt;/li&gt;
&lt;li&gt;Commerce platforms handle transactions and catalog services&lt;/li&gt;
&lt;li&gt;Frontend applications unify the experience&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;There is no universal answer to the Optimizely Commerce vs composable commerce question.&lt;/li&gt;
&lt;li&gt;For existing Optimizely customers, continuing with Commerce 14 is often the most pragmatic choice.&lt;/li&gt;
&lt;li&gt;For new digital commerce initiatives, however, many organizations are evaluating composable commerce platforms alongside Optimizely CMS to build more flexible architectures.&lt;/li&gt;
&lt;li&gt;The key is understanding your organization&amp;rsquo;s priorities: editorial workflows, architectural flexibility, innovation velocity, and long-term platform strategy.&lt;/li&gt;
&lt;li&gt;Optimizely CMS remains a powerful enterprise content platform. The real question is simply how commerce fits into the future architecture around it.&lt;/li&gt;
&lt;/ul&gt;</id><updated>2026-03-12T02:21:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Missing Properties tool for Optimizely CMS</title><link href="https://world.optimizely.com/blogs/Per-Nergard/Dates/2026/3/missing-properties-tool-for-optimizely-cms/" /><id>&lt;p&gt;If you have been working with Optimizely CMS for a while you have probably accumulated some technical debt in your property definitions. When you refactor your models removing properties, renaming content types, or cleaning up after a migration&amp;nbsp;the old property definitions often stick around in the database. They are harmless for the most part, but they add noise and can be confusing when inspecting content types.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; I actually built a tool for this like 10 years ago and I recently had a need to revisit it during a large migration project where we ended up with quite a few orphaned properties that &amp;nbsp;&amp;nbsp;&lt;br /&gt;&amp;nbsp; needed cleaning up.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;strong&gt; What it does&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; The tool scans all your code-defined content types (PageTypes and BlockTypes) and looks for property definitions in the database that no longer have a corresponding attribute in code. Manually created content types are intentionally skipped it&amp;nbsp; only checks types backed by a C# model.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; The results are grouped by content type so you can see exactly what is affected. From there you have a few options:&lt;/p&gt;
&lt;p&gt;&amp;nbsp; - Select individual properties and delete them&lt;br /&gt;&amp;nbsp; - Select all properties for a specific content type&lt;br /&gt;&amp;nbsp; - Delete everything at once&lt;/p&gt;
&lt;p&gt;&amp;nbsp; Both deletion paths require a confirmation dialog because this operation is permanent and cannot be undone.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; There is also a Rescan button if you want to re-check after deploying model changes.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &lt;strong&gt;Installation&lt;br /&gt;&lt;/strong&gt;&lt;br /&gt;&amp;nbsp; Configure blazor and decide on how you want to render the component. I just created a content type specific for the tool. Example layout included on github.&lt;/p&gt;
&lt;p&gt;&amp;nbsp; Add the tool to your project and register it in Startup.cs:&lt;/p&gt;
&lt;p&gt;&amp;nbsp; services.AddMissingProperties();&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &lt;img src=&quot;/link/bbd1f90ab6bc4b6cacc86984dd1a48ea.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;861&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; The source code is on &lt;a href=&quot;https://github.com/PNergard/Nergard.MissingProperties&quot;&gt;https://github.com/pernergard/NergardToolsAndUtilities&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</id><updated>2026-03-10T21:18:57.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>AI Generated Optimizely Developer Newsletter</title><link href="https://www.codeart.dk/blog/2026/3/ai-generated-optimizely-developer-newsletter/" /><id>Updates in the Optimizely ecosystem are everywhere: blog posts, forums, release notes, NuGet packages, and documentation changes. This newsletter brings the important ones together in one place.</id><updated>2026-03-10T19:51:35.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Lessons from Building Production-Ready Opal Tools</title><link href="https://world.optimizely.com/blogs/pjangid/dates/2026/3/lessons-from-building-production-ready-opal-tools/" /><id>&lt;p&gt;AI tools are becoming a normal part of modern digital platforms. With&amp;nbsp;&lt;strong&gt;Optimizely Opal&lt;/strong&gt;, teams can build tools that automate real tasks across the &lt;strong&gt;Optimizely&lt;/strong&gt; platform.&lt;/p&gt;
&lt;p&gt;Creating a basic Opal tool is fairly straightforward. You define a tool, connect it to an API or some business logic, and allow an agent to call it. Many tutorials stop there.&lt;/p&gt;
&lt;p&gt;But in real projects, things are rarely that simple.&lt;/p&gt;
&lt;p&gt;External APIs fail. Data might be incomplete. Requests might take longer than expected. If these situations are not handled properly, your Opal workflows can break or produce incorrect results.&lt;/p&gt;
&lt;p&gt;In this article, we will look at a few important practices that help you build &lt;strong&gt;production-ready Opal tools&lt;/strong&gt;. These include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Proper error handling&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Logging and observability&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Structured responses&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Performance considerations&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Security practices&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These are the same things we normally think about when building enterprise applications.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Understanding How an Opal Tool Works&lt;/h1&gt;
&lt;p&gt;Before going deeper, it helps to understand the typical flow of an Opal tool.&lt;/p&gt;
&lt;p&gt;A simplified flow usually looks like this:&lt;/p&gt;
&lt;pre&gt;User Request
     &amp;darr;
Opal Agent
     &amp;darr;
Opal Tool
     &amp;darr;
External Service or API
     &amp;darr;
Response returned to the Agent&lt;br /&gt;
&lt;/pre&gt;
&lt;p&gt;For example, imagine a marketer asking Opal:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&quot;Check if the price updates for the latest products are correctly applied.&quot;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The agent might call a &lt;strong&gt;Price Validation Tool&lt;/strong&gt;, which then:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Reads the expected price data&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Calls a product API&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compares the values&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Returns the result&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This looks simple, but many things can go wrong along the way. That&amp;rsquo;s why good design is important.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Handling Errors Properly&lt;/h1&gt;
&lt;p&gt;One of the most common issues in production systems is &lt;strong&gt;unhandled errors&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Let&amp;rsquo;s say your tool calls a product API. What happens if:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;the API is temporarily unavailable&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the response takes too long&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the product does not exist&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;the returned data is incomplete&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your tool simply crashes or returns a generic error, the agent will not know what to do.&lt;/p&gt;
&lt;p&gt;A better approach is to return &lt;strong&gt;clear and structured error information&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Example response:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;status&quot;: &quot;error&quot;,
  &quot;errorType&quot;: &quot;API_TIMEOUT&quot;,
  &quot;message&quot;: &quot;The product service did not respond within 5 seconds.&quot;,
  &quot;suggestedAction&quot;: &quot;Retry the request.&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This helps the agent understand what happened and possibly retry or suggest another action.&lt;/p&gt;
&lt;h3&gt;Example Scenario&lt;/h3&gt;
&lt;p&gt;Imagine a tool that checks whether a product exists in the system.&lt;/p&gt;
&lt;p&gt;Instead of returning something vague like:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Error occurred
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Return something useful:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;productId&quot;: &quot;P12345&quot;,
  &quot;status&quot;: &quot;not_found&quot;,
  &quot;message&quot;: &quot;Product does not exist in the catalog.&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This makes troubleshooting much easier.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Returning Structured Data&lt;/h1&gt;
&lt;p&gt;AI agents work much better when the tool returns &lt;strong&gt;structured data instead of plain text&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;For example, consider a tool that verifies product prices.&lt;/p&gt;
&lt;p&gt;Bad example:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;The price seems different from what we expected.
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Better example:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;sku&quot;: &quot;SKU-234&quot;,
  &quot;expectedPrice&quot;: 19.99,
  &quot;currentPrice&quot;: 21.49,
  &quot;status&quot;: &quot;price_mismatch&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This format allows the agent to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;detect mismatches automatically&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;trigger additional checks&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;generate useful reports.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Structured responses also make it easier to reuse the tool in different workflows.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Logging and Observability&lt;/h1&gt;
&lt;p&gt;When something goes wrong in an AI workflow, debugging can be difficult if you do not have good logs.&lt;/p&gt;
&lt;p&gt;Logging helps you answer questions like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Which tool was executed?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;What input was provided?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;How long did it take?&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Did the API call succeed?&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A simple logging format might look like this:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Timestamp: 2026-03-07 10:12:04
Agent: ProductValidationAgent
Tool: PriceValidationTool
ExecutionTime: 2.4 seconds
Status: Success
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If an error occurs:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Timestamp: 2026-03-07 10:15:10
Agent: ProductValidationAgent
Tool: PriceValidationTool
ExecutionTime: 5.1 seconds
Status: Failed
Error: API Timeout
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This information becomes extremely helpful when diagnosing problems in production.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Example: SKU Price Validation Tool&lt;/h1&gt;
&lt;p&gt;Let&amp;rsquo;s look at a simple but practical example.&lt;/p&gt;
&lt;p&gt;Suppose a team updates product prices in bulk and wants to verify that the updates were applied correctly.&lt;/p&gt;
&lt;p&gt;A &lt;strong&gt;Price Validation Tool&lt;/strong&gt; could follow these steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Receive a SKU number&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Fetch the expected price from a spreadsheet or internal system&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Call the product API&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compare the values&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Return the result&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Example response:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;sku&quot;: &quot;SKU-987&quot;,
  &quot;expectedPrice&quot;: 24.99,
  &quot;systemPrice&quot;: 24.99,
  &quot;status&quot;: &quot;verified&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;If there is a mismatch:&lt;/p&gt;
&lt;pre&gt;&lt;code class=&quot;language-json&quot;&gt;{
  &quot;sku&quot;: &quot;SKU-987&quot;,
  &quot;expectedPrice&quot;: 24.99,
  &quot;systemPrice&quot;: 26.99,
  &quot;status&quot;: &quot;mismatch&quot;
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An Opal agent could then generate a report for the operations team.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Improving Performance&lt;/h1&gt;
&lt;p&gt;When AI agents run workflows, they may call multiple tools in sequence.&lt;/p&gt;
&lt;p&gt;If each tool takes several seconds, the entire workflow could become slow.&lt;/p&gt;
&lt;p&gt;Here are a few simple ways to improve performance.&lt;/p&gt;
&lt;h3&gt;Use caching&lt;/h3&gt;
&lt;p&gt;If the same data is requested multiple times, cache it temporarily instead of calling the API repeatedly.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;p&gt;If the tool checks the same product data multiple times during a workflow, store the response for a few minutes.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Reduce unnecessary API calls&lt;/h3&gt;
&lt;p&gt;If possible, fetch multiple items in a single request.&lt;/p&gt;
&lt;p&gt;Instead of:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Call API for Product A
Call API for Product B
Call API for Product C
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Try:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Call API once for Products A, B, and C
&lt;/code&gt;&lt;/pre&gt;
&lt;hr /&gt;
&lt;h3&gt;Run independent tools in parallel&lt;/h3&gt;
&lt;p&gt;Some checks can happen at the same time.&lt;/p&gt;
&lt;p&gt;Example product validation workflow:&lt;/p&gt;
&lt;pre&gt;&lt;code&gt;Product Validation Workflow
 ├─ Price Validation Tool
 ├─ Inventory Check Tool
 └─ Search Index Check Tool
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since these checks are independent, they can run in parallel, reducing overall execution time.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Security Considerations&lt;/h1&gt;
&lt;p&gt;Security is always important when tools interact with external systems.&lt;/p&gt;
&lt;p&gt;A few basic practices can help avoid common problems.&lt;/p&gt;
&lt;h3&gt;Protect API credentials&lt;/h3&gt;
&lt;p&gt;Never hardcode credentials in the tool code. Instead, use environment variables or secure configuration systems.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Validate inputs&lt;/h3&gt;
&lt;p&gt;Agents may pass unexpected inputs. Always validate parameters before calling external services.&lt;/p&gt;
&lt;p&gt;Example validation:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Check if SKU format is valid&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure price values are numeric&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Prevent empty inputs&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;Limit tool permissions&lt;/h3&gt;
&lt;p&gt;Each tool should only access the resources it needs.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;A &lt;strong&gt;content validation tool&lt;/strong&gt; should not modify content.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;A &lt;strong&gt;reporting tool&lt;/strong&gt; should not update product data.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This reduces the risk of accidental changes.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Monitoring and Continuous Improvement&lt;/h1&gt;
&lt;p&gt;Once tools are running in production, it is useful to track their performance over time.&lt;/p&gt;
&lt;p&gt;Some helpful metrics include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;tool execution time&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;success vs failure rate&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;number of API errors&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;most frequently used tools&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These metrics can highlight areas where improvements are needed.&lt;/p&gt;
&lt;p&gt;For example:&lt;/p&gt;
&lt;p&gt;If a tool frequently fails due to timeouts, you might need to improve the API performance or add retry logic.&lt;/p&gt;
&lt;hr /&gt;
&lt;h1&gt;Final Thoughts&lt;/h1&gt;
&lt;p&gt;As AI becomes more integrated into enterprise platforms, the quality of the underlying tools becomes increasingly important.&lt;/p&gt;
&lt;p&gt;A well-designed tool should not only complete its task but also:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;handle failures gracefully&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;provide clear responses&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;log useful information&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;perform efficiently&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;follow security best practices&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By applying these practices while building tools for &lt;strong&gt;Optimizely Opal&lt;/strong&gt;, teams can create AI workflows that are reliable enough for real business operations.&lt;/p&gt;
&lt;p&gt;Feel free to share your thought as an outcome of yout experience with implementing the &lt;strong&gt;Optimizely Opal Tools.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</id><updated>2026-03-07T16:46:02.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>My Takeaway from Optimizely Opal Agents in Action 2026 - What Agentic AI Means for the Future of Digital Marketing</title><link href="https://world.optimizely.com/blogs/opti-chronicles/dates/2026/3/optimizely-opal-agents-in-action-2026---what-agentic-ai-means-for-the-future-of-digital-marketing/" /><id>&lt;p class=&quot;MsoNormal&quot;&gt;I would like to share with you what stayed in my head after this amazing virtual event organized by Optimizely. &lt;strong&gt;Agents in Action 2026&lt;/strong&gt;, a live demonstration of Optimizely&#39;s AI assistant platform, Opal. The session showcased how AI agents embedded across the Optimizely ecosystem can conduct research, analyze documents, orchestrate tools, and automate operational workflows for marketing teams.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Artificial intelligence in marketing is entering a new phase. For the past two years, the focus has largely been on generative AI&amp;mdash;tools that produce copy, images, summaries, and marketing ideas. But as organizations begin integrating these technologies into their workflows, a more powerful model is emerging:&amp;nbsp;&lt;strong&gt;agentic AI&lt;/strong&gt;.&amp;nbsp;Agentic systems go beyond answering questions. They can plan tasks, call tools, retrieve data, analyze information, and execute multi-step workflows.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Optimizely&#39;s demonstration highlighted a shift that is beginning to reshape digital marketing operations: the move from isolated AI features to AI agents that perform work inside enterprise platforms.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Industry research suggests the timing is not accidental. Organizations are rapidly experimenting with AI but still struggle to integrate it deeply into operational workflows. According to McKinsey&amp;rsquo;s latest global survey on AI adoption, many companies have begun using AI widely but have not yet embedded it deeply enough into processes to generate full enterprise value (&lt;a href=&quot;https://www.mckinsey.com/capabilities/quantumblack/our-insights/the-state-of-ai&quot;&gt;McKinsey&lt;/a&gt;).&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;What Optimizely showed with Opal agents points toward the next stage of AI maturity&amp;mdash;where marketing teams work alongside AI agents that automate research, analysis, and operational tasks.&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;h2 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;The Rise of Agentic AI in Marketing&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Most early generative AI tools behaved like conversational assistants. You ask a question, yhe system produces an answer.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;That model has proven useful for content generation, brainstorming, and summarization, but enterprise environments require more than output generation. They require systems that can execute processes.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Agentic AI systems are designed for that purpose. Instead of generating a single response, they can:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0in;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l2 level1 lfo1; tab-stops: list .5in;&quot;&gt;Execute multi-step research&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l2 level1 lfo1; tab-stops: list .5in;&quot;&gt;Retrieve external information&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l2 level1 lfo1; tab-stops: list .5in;&quot;&gt;Call APIs or tools&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l2 level1 lfo1; tab-stops: list .5in;&quot;&gt;Analyze documents&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l2 level1 lfo1; tab-stops: list .5in;&quot;&gt;Trigger workflows&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l2 level1 lfo1; tab-stops: list .5in;&quot;&gt;Coordinate multiple systems&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This shift reflects a broader trend in enterprise AI adoption.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;McKinsey research shows that AI is increasingly used across multiple business functions&amp;mdash;including marketing and sales&amp;mdash;where generative AI can support activities such as knowledge synthesis, content generation, and strategic analysis (&lt;a href=&quot;https://www.mckinsey.com/capabilities/quantumblack/our-insights/the-state-of-ai-2024&quot;&gt;McKinsey&lt;/a&gt;&lt;a href=&quot;https://www.mckinsey.com/capabilities/quantumblack/our-insights/the-state-of-ai-2024)&quot;&gt;)&lt;/a&gt;. But many organizations still struggle to scale these capabilities across their workflows.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The opportunity lies not in adding more AI tools, but in redesigning operational processes so AI becomes embedded within them. This is where agentic platforms begin to matter, instead of interacting with AI occasionally, teams interact with systems that &lt;strong&gt;continuously assist, automate, and coordinate operational tasks&lt;/strong&gt;.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The Optimizely Opal demonstration illustrated how such systems might work in a marketing technology environment.&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;h2 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;What Optimizely Demonstrated at Opal Agents in Action 2026&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The event focused on Opal, Optimizely&amp;rsquo;s AI assistant platform integrated across its product suite, including CMS, experimentation tools, analytics capabilities, and content marketing workflows.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;At its core, Opal operates as a conversational AI interface embedded directly inside the Optimizely ecosystem. Users interact with the system through a chat interface that maintains persistent conversation history and contextual awareness.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Before each interaction with the underlying language model, the platform executes a multi-step enrichment process.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This pipeline loads contextual information such as:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0in;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo2; tab-stops: list .5in;&quot;&gt;organizational instructions and brand guidelines&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo2; tab-stops: list .5in;&quot;&gt;available agents and tools&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l0 level1 lfo2; tab-stops: list .5in;&quot;&gt;operational prompts or system rules&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Organizations can configure these instructions at multiple levels.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Instance-level instructions apply across the entire organization&amp;mdash;for example, defining brand voice or communication guidelines. Personal instructions allow individual users to tailor how the system responds to their requests.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Role-based permissions control who can modify these instructions, which helps maintain governance in enterprise environments.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The demonstration showed how this contextual layer ensures AI interactions remain aligned with organizational policies and brand requirements.&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;h2 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Key Capabilities of Opal Agents&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The most interesting aspect of the event was not the conversational interface. It was the demonstration of &lt;strong&gt;specialized AI agents capable of executing complex operations&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Specialized agents&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Agents in Opal are created with defined roles, instructions, and tool access. When an agent runs, it operates in an isolated context. This prevents large multi-step processes from overwhelming the main conversation.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;During the demonstration, a research agent was configured to analyze companies. The agent accepted a topic parameter and automatically executed multiple research passes.&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In another example, the agent performed several research queries about Toyota, gathering information about company background, news, and financial performance. The system automatically executed a chain of operations:&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;search &amp;rarr; scrape &amp;rarr; analyze &amp;rarr; summarize&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;The process generated a detailed report after approximately 234 seconds and involved roughly 44,000 tokens across multiple tool calls.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Execution logs displayed the reasoning cycle in real time, including predicted tool calls and returned outputs.&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The demonstration highlighted how AI agents can handle research tasks that typically require multiple manual steps.&lt;/p&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Tools and extensibility&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;A second important capability is Opal&amp;rsquo;s tool framework. Developers can create custom tools using the Opal Tools SDK, which supports Python and FastAPI. Functions can be exposed as tools through simple annotations, allowing the AI system to invoke them during task execution. The demonstration included a simple tool that generated random numbers based on user parameters. While trivial in itself, the example illustrated how tools return structured responses that can render as interactive user interface elements. More advanced tools are provided directly by Optimizely product teams.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Examples demonstrated during the session included:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0in;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo3; tab-stops: list .5in;&quot;&gt;Web search integration that performs Google searches and scrapes relevant websites&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo3; tab-stops: list .5in;&quot;&gt;PowerPoint processing that converts slides into analyzable formats&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l1 level1 lfo3; tab-stops: list .5in;&quot;&gt;Product-specific tools for CMS and experimentation features&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The system determines when to call these tools based on their descriptions and parameter schemas. The result is an AI system capable of chaining together multiple operations without manual intervention.&lt;/p&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Enterprise document analysis&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In the event it was also demonstrated document processing capabilities.&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;PowerPoint files can be uploaded and converted into a structured Canvas format, allowing the system to analyze slides individually.&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;A code execution tool&amp;mdash;similar to those used in other advanced AI systems&amp;mdash;will enable analysis of spreadsheets and other Office documents through generated Python scripts.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This allows agents to read, manipulate, and extract information from enterprise files, so organizations can also attach reference documents or knowledge sources to agents. These materials become searchable through retrieval-augmented generation workflows using Optimizely&amp;rsquo;s content graph.&lt;/p&gt;
&lt;h3 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Workflow automation&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;For me the most operationally significant feature demonstrated during the event was multi-agent workflow orchestration. Agents can be chained together sequentially, passing outputs and parameters between steps.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Workflows can be triggered in several ways:&lt;/p&gt;
&lt;ul style=&quot;margin-top: 0in;&quot;&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo4; tab-stops: list .5in;&quot;&gt;Direct chat input&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo4; tab-stops: list .5in;&quot;&gt;Email-based triggers&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo4; tab-stops: list .5in;&quot;&gt;Webhook integrations&lt;/li&gt;
&lt;li class=&quot;MsoNormal&quot; style=&quot;mso-list: l3 level1 lfo4; tab-stops: list .5in;&quot;&gt;Scheduled automation&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;One demonstration showed a research agent analyzing a topic and passing its results to an email agent. The second agent transformed the research findings into a formatted HTML email and automatically delivered it to recipients. Other enterprise&amp;nbsp;use cases discussed during the event included automated market research, competitive intelligence monitoring, and recurring insight reports.&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 Agentic Marketing Matters for Digital Teams&lt;/strong&gt;&lt;/h3&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;For marketing teams, the operational implications of agentic AI could be substantial. Modern digital marketing involves a constant flow of analysis, reporting, and information gathering. Many tasks follow similar patterns:&lt;/p&gt;
&lt;ul&gt;
&lt;li class=&quot;MsoNormal&quot;&gt;Collect information &amp;rarr; Analyze it &amp;rarr; Generate output &amp;rarr; Share results&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI agents can automate much of this process instead of manually conducting research or assembling reports, teams can initiate workflows where agents gather information, analyze it, and deliver structured insights. This does not remove human involvement, instead, it shifts where humans spend their time.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;MIT Sloan research suggests that AI is most effective when it complements human work rather than replacing it, enabling people to focus on higher-value tasks such as interpretation and decision-making (&lt;a href=&quot;https://mitsloan.mit.edu/ideas-made-to-matter/when-humans-and-ai-work-best-together-and-when-each-better-alone&quot;&gt;MIT Sloan Management Review&lt;/a&gt;&lt;a href=&quot;https://mitsloan.mit.edu/ideas-made-to-matter/when-humans-and-ai-work-best-together-and-when-each-better-alone)&quot;&gt;)&lt;/a&gt;. For marketing organizations, that means less time spent on operational preparation and more time spent on strategy.&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;h2 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Industry Validation&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Several industry studies reinforce the potential impact of AI in marketing operations.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;McKinsey estimates that generative AI could generate significant economic value across industries, with marketing and sales among the functions that stand to benefit the most from productivity improvements (&lt;a href=&quot;https://www.mckinsey.com/capabilities/growth-marketing-and-sales/our-insights/how-generative-ai-can-boost-consumer-marketing&quot;&gt;McKinsey&lt;/a&gt;). The firm&amp;rsquo;s research suggests that generative AI could increase marketing productivity up to 15 percent of total marketing spend through improvements in content creation, personalization, and knowledge synthesis.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;At the same time, organizations are still learning how to operationalize AI effectively. McKinsey&amp;rsquo;s latest global AI survey notes that many companies have adopted AI tools but have not yet embedded them deeply into their workflows or processes (&lt;a href=&quot;https://www.mckinsey.com/capabilities/quantumblack/our-insights/the-state-of-ai-2024&quot;&gt;McKinsey&lt;/a&gt;). This gap between experimentation and operational integration is precisely where agentic platforms may deliver value.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;By embedding AI into enterprise systems and allowing agents to execute tasks, organizations can move from isolated experiments to operational transformation.&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;h2 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Strategic Implications for CMOs and Digital Leaders&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;For marketing leaders evaluating AI platforms, several strategic considerations emerge from the Opal demonstration.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;First, governance becomes critical. AI systems embedded in operational workflows must operate within brand, legal, and compliance boundaries. Opal&amp;rsquo;s instruction framework illustrates how organizations can define these constraints.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Second, the ecosystem around AI matters as much as the AI itself. Platforms that support tool integration, APIs, and workflow orchestration will likely deliver more long-term value than standalone assistants.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Third, marketing operating models may evolve. As agent-driven workflows mature, teams may increasingly focus on oversight, strategy, and decision-making rather than manual research or analysis.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Finally, human supervision remains essential. The demonstration itself acknowledged that large language models can occasionally drift off topic during complex research tasks, requiring prompt refinement and oversight. Agentic systems should therefore be viewed as collaborators, not replacements.&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;h2 class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;My Final Takeaways&lt;/strong&gt;&lt;/h2&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The Optimizely Opal Agents in Action event offered an early look at how AI agents might reshape marketing operations. Rather than presenting AI simply as a content generator, the demonstrations positioned Opal as a system capable of executing research, analyzing documents, orchestrating tools, and automating workflows across marketing platforms. This approach reflects a broader industry shift. As organizations move beyond isolated AI experiments, the focus is shifting toward operational integration&amp;mdash;embedding AI into everyday workflows. For digital marketing teams, this may represent the next stage of platform evolution, not just tools, not just assistants, but ecosystems of AI agents working alongside human teams to execute the operational layer of marketing.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&amp;nbsp;&lt;/p&gt;</id><updated>2026-03-06T15:48:32.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>From Vision to Velocity: Introducing the Optimizely MVP Technical Roundtable</title><link href="https://world.optimizely.com/blogs/patrick-lam/dates/2026/3/from-vision-to-velocity-introducing-the-optimizely-mvp-technical-roundtable/" /><id>&lt;p&gt;Digital transformation is a two-sided coin. On one side, you have the high-level strategy, the business cases, the customer journeys, and the operational shifts. On the other, you have the technical architecture, the code, the integrations, and the infrastructure that bring those ideas to life.&lt;/p&gt;
&lt;p&gt;Last month, we explored the strategic side with our &lt;strong&gt;Strategy OMVPs&lt;/strong&gt; (&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;a class=&quot;ng-star-inserted&quot; href=&quot;https://academy.optimizely.com/student/catalog/list?category_ids=43056-optimizely-unfiltered&quot;&gt;catch up on those episodes here&lt;/a&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;&lt;!----&gt;). But today, we&amp;rsquo;re opening the hood.&lt;/p&gt;
&lt;p&gt;We are thrilled to release our latest&amp;nbsp;&lt;strong&gt;Technical OMVP Roundtable&lt;/strong&gt;. This two-part deep dive features the architects and engineers who are on the front lines of the Optimizely ecosystem, solving the most complex implementation challenges in the industry.&lt;/p&gt;
&lt;h3&gt;Why This Matters (The Strategy-Tech Handover)&lt;/h3&gt;
&lt;p&gt;If the Strategy Roundtable was about &lt;em&gt;what&lt;/em&gt; we should build, the Technical Roundtable is about &lt;em&gt;how&lt;/em&gt; we build it to last. Optimizely Most Valuable Professionals (OMVPs) are divided into these two categories to ensure that every angle of a project is covered:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Strategy OMVPs:&lt;/strong&gt; Focus on the GTM landscape, change management, business outcomes, and more.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Technical OMVPs:&lt;/strong&gt; Focus on technical migrations, SaaS CMS architecture, API-first integrations, developer experience, and more&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Technical Roundtable: What&amp;rsquo;s Under the Hood?&lt;/h3&gt;
&lt;p&gt;In this new two-part series, our technical experts pull no punches. They discuss the &quot;messy&quot; reality of enterprise builds and share the shortcuts they&amp;rsquo;ve discovered.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Part 1: &lt;a href=&quot;https://academy.optimizely.com/student/activity/3227165-optimizely-technical-roundtable-ep-1-part-1-post-implementation-technical-challenges?sid=56654085-071a-49fb-bb31-550fd0879f8e&amp;amp;sid_i=5&quot;&gt;The Modern Stack &amp;amp; Migrations&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;CMS 12 &amp;amp; .NET Core:&lt;/strong&gt; Real-world advice on moving from older versions to the modern, high-performance stack.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The &quot;Breaking Change&quot; Survival Guide:&lt;/strong&gt; How to handle upgrades without disrupting the business.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Part 2: &lt;a href=&quot;https://academy.optimizely.com/student/activity/3227202-optimizely-technical-roundtable-ep-1-part-2-post-implementation-technical-challenges?sid=56654085-071a-49fb-bb31-550fd0879f8e&amp;amp;sid_i=6&quot;&gt;Scalability, Experimentation &amp;amp; The Future&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SaaS CMS &amp;amp; Visual Builder:&lt;/strong&gt; The group&amp;rsquo;s take on Optimizely&amp;rsquo;s shift toward SaaS and what it means for back-end developers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Power of Graph:&lt;/strong&gt; Leveraging Optimizely Graph and ODP (Optimizely Data Platform) for sub-second personalization.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Or you can listen to the &lt;a href=&quot;https://open.spotify.com/episode/3a3MGwdtS6emPBWZN327kE?si=-x3j4JSGTN2s5Ah6qN65aQ&amp;amp;nd=1&amp;amp;dlsi=691a4ffd75424c7f&quot;&gt;full episode as a podcast.&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Meet the Architects&lt;/h3&gt;
&lt;p&gt;These OMVPs aren&#39;t just experts, they are mentors. They are the ones writing the documentation, contributing to open-source plugins, and answering the toughest questions in the community forums. When you watch these episodes, you aren&amp;rsquo;t just getting &quot;best practices&quot;, you&amp;rsquo;re getting a peek into the playbooks of the world&amp;rsquo;s top Optimizely partners.&lt;/p&gt;</id><updated>2026-03-06T02:48:58.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Commerce 14.45.0 is incompatible with CMS 12.34.2 (but that&#39;s an easy fix!)</title><link href="https://world.optimizely.com/blogs/Quan-Mai/Dates/2026/3/commerce-14.45.0-is-incompatible-with-cms-12.34.2" /><id>&lt;p&gt;Incompatible is a strong word, but that is to get your attention. This is one of the small thing that can be overlooked, but if you run into it, it could waste many hours figuring out what&#39;s wrong.&lt;/p&gt;
&lt;p&gt;There is a strange yet weird bug in Commerce 14.45 when you upgrade to CMS 12.34.2, your Catalog UI will keep flickering. If you open browser console, there are a lot of requests to /contentstructure and the CatalogContentList component just keeps refreshing.&lt;/p&gt;
&lt;p&gt;Good thing is that the problem is fixed on Commerce 14.45.1, so you can just upgrade to get your site working again!&lt;/p&gt;
&lt;p&gt;Happy upgrading.&amp;nbsp;&lt;/p&gt;</id><updated>2026-03-05T11:06:19.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Announcing Stott Security Version 5.0</title><link href="https://world.optimizely.com/blogs/mark-stott/dates/2026/3/announcing-stott-security-version-5.0" /><id>&lt;p&gt;March 2026 marks the release of Stott Security v5, a significant update to the popular web security add-on for Optimizely CMS 12+, with more than 115,000 downloads across nuget.org and nuget.optimizely.com. Below is a high-level overview of what&amp;rsquo;s new in this release.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Custom Header Management&lt;/li&gt;
&lt;li&gt;Audit Record Clean Up&lt;/li&gt;
&lt;li&gt;Audit Record Search&lt;/li&gt;
&lt;li&gt;Granular Settings Import&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Before we get into the details, we all know that the release of Optimizely CMS 13 is imminent. A CMS 13 compatible version of Stott Security has already been developed and will be updated as we see more previews of CMS 13. It is my intention to have a day 1 release of this add-on.&lt;/p&gt;
&lt;h2&gt;Custom Headers&lt;/h2&gt;
&lt;p&gt;I have had multiple requests to add functionality that allows users to add or remove custom headers from the response. The data storage and UI for the existing&amp;nbsp;&lt;strong&gt;Response Headers&lt;/strong&gt;&amp;nbsp;UI was inflexible, therefore I have rebuilt this feature from the ground up.&lt;/p&gt;
&lt;p&gt;Users can add new headers with any valid header name structure and define a value and a behaviour. The three behaviours are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Add&lt;/strong&gt;: This will add the header to the response and will require a value to be specified.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Remove&lt;/strong&gt;: This will remove the header from the response.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Disabled&lt;/strong&gt;: No action will be performed for this header.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.stott.pro/assets/StottSecurityCustomHeaders.png&quot; alt=&quot;Custom Headers Interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For traditional / in-process websites:&lt;/strong&gt; the order of your middlewares and the point in time where the header is added will impact the success rate for removal of headers. The server header for example is not present in the Response object while middlewares are processed and as such will not be impacted. Also headers added after the response has been served will not be affected, this means headers added by CloudFlare for example will not be removed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;For Headless websites:&lt;/strong&gt; the Header Listing API has been updated so that all configured headers now have an &amp;ldquo;isRemoval&amp;rdquo; property that highlights if the header should be removed or not.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Headless API Examples:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/stott.security.optimizely/api/compiled-headers/list/&lt;/li&gt;
&lt;li&gt;/stott.security.optimizely/api/compiled-headers/list/?pageId=123&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Example Response:&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[
    {
        &quot;key&quot;: &quot;a-custom-header&quot;,
        &quot;value&quot;: &quot;a-value&quot;,
        &quot;isRemoval&quot;: false
    },
    {
        &quot;key&quot;: &quot;Content-Security-Policy&quot;,
        &quot;value&quot;: &quot;default-src \u0027self\u0027;...&quot;, // Full CSP will be included
        &quot;isRemoval&quot;: false
    },
    {
        &quot;key&quot;: &quot;server&quot;,
        &quot;value&quot;: &quot;&quot;,
        &quot;isRemoval&quot;: true
    },
    {
        &quot;key&quot;: &quot;X-Content-Type-Options&quot;,
        &quot;value&quot;: &quot;nosniff&quot;,
        &quot;isRemoval&quot;: false
    },
    {
        &quot;key&quot;: &quot;X-Xss-Protection&quot;,
        &quot;value&quot;: &quot;0&quot;,
        &quot;isRemoval&quot;: false
    }
]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;⚠️&amp;nbsp;&lt;strong&gt;Migration warning:&lt;/strong&gt; Any configuration on the old Response Headers interface will need to be recreated. Response Headers that were previously managed through the old interface will appear as Disabled and the edit modal will present the same friendly options that were available in the previous UI.&amp;nbsp; The headers that need re-configuring are limited to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Cross-Origin-Embedder-Policy&lt;/li&gt;
&lt;li&gt;Cross-Origin-Opener-Policy&lt;/li&gt;
&lt;li&gt;Cross-Origin-Resource-Policy&lt;/li&gt;
&lt;li&gt;X-Content-Type-Options&lt;/li&gt;
&lt;li&gt;X-XSS-Protection&lt;/li&gt;
&lt;li&gt;X-Frame-Options&lt;/li&gt;
&lt;li&gt;Referrer-Policy&lt;/li&gt;
&lt;li&gt;Strict-Transport-Security (HSTS)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Audit Record Clean Up&lt;/h2&gt;
&lt;p&gt;Stott Security has long had the ability to Audit changes to the configuration settings, but there has not been any means to clean up the audit records. A new scheduled job called&amp;nbsp;&lt;strong&gt;[Stott Security] Audit Record Clean Up&lt;/strong&gt;&amp;nbsp;has been created that will remove audit records that exceed a configured retention period. By default this period is set to 2 years, but can be altered during the Add-On configuration by specifying the&amp;nbsp;&lt;strong&gt;AuditRetentionPeriod&lt;/strong&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddStottSecurity(options =&amp;gt;
{
  options.ConnectionStringName = &quot;EPiServerDB&quot;;
  options.NonceHashExclusionPaths.Add(&quot;/exclude-me&quot;);
  options.AuditRetentionPeriod = TimeSpan.FromDays(730); 
},
authorization =&amp;gt;
{
  authorization.AddPolicy(CspConstants.AuthorizationPolicy, policy =&amp;gt;
  {
    policy.RequireRole(&quot;WebAdmins&quot;);
  });
});&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Audit Record Search&lt;/h2&gt;
&lt;p&gt;Filtering of audit records has always been present within the system, however it was limited to simple filters for user, operation, record and date range. Looking for very specific changes was a time consuming exercise. This change adds a text filter which will be used to find matches within the following fields:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Indicator
&lt;ul&gt;
&lt;li&gt;Source for Content Security Policy Sources&lt;/li&gt;
&lt;li&gt;Directive for Permission Policy directives&lt;/li&gt;
&lt;li&gt;Header Name for Custom Headers&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Old Value&lt;/li&gt;
&lt;li&gt;New Value&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;https://www.stott.pro/assets/StottSecurityAuditWithFreeTextFilter.png&quot; alt=&quot;Audit Interface&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&#128591;&amp;nbsp;&lt;strong&gt;Thank you&lt;/strong&gt;&amp;nbsp;to&amp;nbsp;&lt;a href=&quot;https://github.com/SamuelJoseph23&quot;&gt;Samuel Joseph&lt;/a&gt;&amp;nbsp;for delivering&amp;nbsp;&lt;a href=&quot;https://github.com/GeekInTheNorth/Stott.Security.Optimizely/issues/347&quot;&gt;Add a free text filter to the Audit Screen&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Granular Settings Import&lt;/h2&gt;
&lt;p&gt;The ability to import and export settings was introduced back in version 2.6.0 but was straight forwards in terms of options. Over time this functionality was updated to support partial imports by ignoring root settings that were null. As part of this release, users now have the ability to choose specifically which settings they want to import.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://www.stott.pro/assets/StottSecurityImportSettingsModal.png&quot; alt=&quot;Import Settings Modal&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&#128591;&amp;nbsp;&lt;strong&gt;Thank you&lt;/strong&gt;&amp;nbsp;to&amp;nbsp;&lt;a href=&quot;https://github.com/SamuelJoseph23&quot;&gt;Samuel Joseph&lt;/a&gt;&amp;nbsp;for providing the initial implementation of&amp;nbsp;&lt;a href=&quot;https://github.com/GeekInTheNorth/Stott.Security.Optimizely/issues/346&quot;&gt;Enhance Settings Import Tool&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;Stott Security is a free, open-source add-on for Optimizely CMS 12+, designed from the ground up to be accessible to both technical and non-technical users, with built-in audit functionality to provide clear accountability. The add-on supports both PaaS-based traditional headed and headless solutions.&lt;/p&gt;
&lt;p&gt;Version 5 delivers a major update featuring a rebuilt&amp;nbsp;&lt;strong&gt;Response Headers&lt;/strong&gt;&amp;nbsp;functionality with enhanced support for custom headers; enhanced&amp;nbsp;&lt;strong&gt;Audit Management&lt;/strong&gt;&amp;nbsp;with configurable retention periods and new free-text audit search, and a more granular&amp;nbsp;&lt;strong&gt;Settings Import&lt;/strong&gt; tool that allows selective configuration.&lt;/p&gt;
&lt;hr /&gt;
&lt;p&gt;I am an OMVP and the author and maintainer of&amp;nbsp;&lt;a title=&quot;Stott Security&quot; href=&quot;https://github.com/GeekInTheNorth/Stott.Security.Optimizely&quot;&gt;Stott Security&lt;/a&gt;&amp;nbsp;and&amp;nbsp;&lt;a title=&quot;Stott Robots Handler&quot; href=&quot;https://github.com/GeekInTheNorth/Stott.Optimizely.RobotsHandler&quot;&gt;Stott Robots Handler&lt;/a&gt;&amp;nbsp;for Optimizely CMS 12. You can find all of my content collated on&amp;nbsp;&lt;a title=&quot;The blog website for Mark Stott.&quot; href=&quot;https://www.stott.pro/&quot;&gt;https://www.stott.pro/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;</id><updated>2026-03-05T09:17:42.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Is Opal the Enterprise-Ready Evolution of OpenClaw?</title><link href="https://hristo.vercel.app/blogs/is-opal-the-enterprise-ready-evolution-of-openclaw" /><id>From OpenClaw experiments to enterprise AI agents: exploring the journey from my personal automation to governed execution at scale with Optimizely Opal.</id><updated>2026-03-05T00:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Optimizely CMS SaaS Migration Tool</title><link href="https://world.optimizely.com/blogs/hieu-nguyen/dates/2026/3/optimizely-cms-saas-migration-tool/" /><id>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;Migrating and synchronizing environments in &lt;strong&gt;Optimizely CMS SaaS&lt;/strong&gt; can be challenging, especially when working with multiple environments such as development, staging, and production.&lt;/p&gt;
&lt;p&gt;Currently, CMS SaaS provides &lt;strong&gt;export/import functionality&lt;/strong&gt;, but it does &lt;strong&gt;not yet include built-in tools for comparing or migrating entities between environments&lt;/strong&gt;. As a result, developers often need to manually verify whether content types, display templates, or other entities exist in another environment before performing imports. This process can be time-consuming and error-prone.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;Optimizely CMS SaaS Migration Tool&lt;/strong&gt; aims to help address this gap by providing a lightweight interface to compare environments and assist with migration tasks.&lt;/p&gt;
&lt;h2&gt;Key Capabilities&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Connect to multiple CMS SaaS environments using OAuth2 (Client Credentials) + CMS APIs&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Compare &lt;strong&gt;content types&lt;/strong&gt; and &lt;strong&gt;display templates&lt;/strong&gt; between source and target environments&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;View structured differences to quickly identify missing or mismatched entities&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Export comparison results as JSON for reference or automation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Track environment parity before performing export/import operations&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This makes the tool particularly useful for &lt;strong&gt;tracking down differences in content types and display templates&lt;/strong&gt; across environments, something that currently requires manual investigation when using the native SaaS tooling.&lt;/p&gt;
&lt;h2&gt;Current Status&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; Content comparison and migration functionality is still under active development. At the moment, the tool should primarily be used to check whether a content item (with the same ID) exists in the target environment rather than relying on it for full content synchronization.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;Access the Tool&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GitHub Repository&lt;/strong&gt;&lt;br /&gt;&lt;a href=&quot;https://github.com/chrno1209/optimizely-cms-saas-migration-tool&quot;&gt;https://github.com/chrno1209/optimizely-cms-saas-migration-tool&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Live Deployment (Vercel)&lt;/strong&gt; &amp;ndash; use instantly in the browser&lt;br /&gt;&lt;a href=&quot;https://optimizely-cms-saas-migration-tool.vercel.app/&quot;&gt;https://optimizely-cms-saas-migration-tool.vercel.app/&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Why This Tool Matters&lt;/h2&gt;
&lt;p&gt;As members of the &lt;strong&gt;Optimizely community (&amp;ldquo;Optimizers&amp;rdquo;)&lt;/strong&gt;, many of us are looking forward to &lt;strong&gt;official built-in capabilities for environment comparison and migration&lt;/strong&gt; within CMS SaaS. While those features are being developed, tools like this can serve as a helpful interim solution.&lt;/p&gt;
&lt;p&gt;This project provides an &lt;strong&gt;alternative approach to visualize differences and verify environment parity&lt;/strong&gt;, helping developers reduce manual checks and better manage schema consistency across environments.&lt;/p&gt;
&lt;p&gt;If you are working with &lt;strong&gt;Optimizely CMS SaaS today&lt;/strong&gt;, this tool may help simplify part of your workflow while we wait for the official platform features to arrive.&lt;/p&gt;
&lt;h2&gt;Screenshots&lt;/h2&gt;
&lt;p&gt;&lt;img class=&quot;clickable&quot; style=&quot;width: 100%; height: auto;&quot; src=&quot;/link/69d8728032d8498fb8a1f0ff48fb277f.aspx&quot; alt=&quot;&quot; width=&quot;2560&quot; height=&quot;1353&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;clickable&quot; style=&quot;width: 100%; height: auto;&quot; src=&quot;/link/3e4fe90153c64ce195a78dc5c148bb48.aspx&quot; alt=&quot;&quot; width=&quot;2560&quot; height=&quot;1353&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img class=&quot;clickable&quot; style=&quot;width: 100%; height: auto;&quot; src=&quot;/link/0998194709744c829bb9695128255ce1.aspx&quot; alt=&quot;&quot; width=&quot;2560&quot; height=&quot;1353&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</id><updated>2026-03-04T09:38:12.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Alloy Aspire Scaffold, or how to simulate the Optimizely DXP setup on your dev machine</title><link href="https://www.avantibit.com/blog/avantibit-alloy-aspire-scaffold" /><id>Alloy Aspire Scaffold is a .NET template for Optimizely CMS 13 PaaS (Preview) that runs the standard Alloy site on .NET Aspire 13 in a DXP-like local topology (multiple app instances, YARP, Azurite, a queue, and SQL Server), so you catch distributed bugs before production does.</id><updated>2026-03-04T00:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>OpenAI-Driven AI Assistant for TinyMCE in Optimizely CMS 12</title><link href="https://www.adnanzameer.com/2026/03/openai-driven-ai-assistant-for-tinymce.html" /><id>&lt;p&gt;The &lt;b&gt;&lt;a href=&quot;https://nuget.optimizely.com/packages/a2z.optimizely.tiny.ai/&quot; target=&quot;_blank&quot;&gt;Tiny.AI&lt;/a&gt;&lt;/b&gt; add-on enhances Optimizely CMS 12 by seamlessly integrating OpenAI directly into the TinyMCE editor. It empowers editors to rewrite, improve, summarize, expand, or translate selected content without leaving the CMS. Instead of copying content into external AI tools and risking formatting issues, Tiny.AI processes HTML safely and returns clean, CMS-ready output.&lt;/p&gt;&lt;a href=&quot;https://www.adnanzameer.com/2026/03/openai-driven-ai-assistant-for-tinymce.html#more&quot;&gt;Read more&lt;/a&gt;</id><updated>2026-03-03T16:41:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Your first SAAS Project -- Setup</title><link href="https://world.optimizely.com/blogs/puneetgarg/dates/2026/3/your-first-saas-project----setup/" /><id>&lt;p&gt;Hey everyone,&lt;/p&gt;
&lt;p&gt;When I first started Remko&#39;s StarterKit, I honestly had no idea what I was doing. After spending a couple of months working through it, I&amp;rsquo;ve learned quite a bit.&lt;/p&gt;
&lt;p&gt;I&amp;rsquo;d like to share some insights and information that might help others who are just getting started. It may seem basic to some of you, but it could be really helpful for someone who&amp;rsquo;s completely new.&lt;/p&gt;
&lt;p&gt;Hope this helps someone on their journey!&lt;/p&gt;
&lt;h2 class=&quot;heading-element&quot;&gt;Prerequisites&lt;/h2&gt;
&lt;p&gt;Before you begin, ensure you have the following installed on your system:&lt;/p&gt;
&lt;div class=&quot;markdown-heading&quot;&gt;
&lt;h3 class=&quot;heading-element&quot;&gt;Required Software&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Node.js 18+&lt;/strong&gt;&amp;nbsp;-&amp;nbsp;&lt;a href=&quot;https://nodejs.org/&quot;&gt;Download from nodejs.org&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Yarn 4.5.0+&lt;/strong&gt;&amp;nbsp;- Package manager (comes with Node.js or install separately)&lt;/li&gt;
&lt;/ul&gt;
&lt;div class=&quot;markdown-heading&quot;&gt;
&lt;h3 class=&quot;heading-element&quot;&gt;Required Accounts &amp;amp; Access&lt;/h3&gt;
&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Optimizely CMS SaaS Instance&lt;/strong&gt;&amp;nbsp;-&amp;nbsp;&lt;a href=&quot;https://www.optimizely.com/saas-core-waitlist/&quot;&gt;Sign up for the program&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GitHub Account&lt;/strong&gt;&amp;nbsp;- For repository access&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Vercel Account&lt;/strong&gt; (optional) - For deployment and environment variable management&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2 class=&quot;heading-element&quot;&gt;Quick Start&lt;/h2&gt;
&lt;h3 class=&quot;heading-element&quot;&gt;1. Clone the Repository&lt;/h3&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;# Clone the repository
git clone https://github.com/remkoj/optimizely-saas-starter.git
cd optimizely-saas-velocity&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 class=&quot;heading-element&quot;&gt;2. Install Dependencies&lt;/h3&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;# Install root dependencies
yarn install

# Install frontend dependencies
cd apps/frontend
yarn install&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 class=&quot;heading-element&quot;&gt;3. Environment Configuration&lt;/h3&gt;
&lt;p&gt;Create a&amp;nbsp;&lt;code&gt;.env.local&lt;/code&gt;&amp;nbsp;file in the&amp;nbsp;&lt;code&gt;apps/frontend&lt;/code&gt; directory:&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;# Navigate to frontend directory
cd apps/frontend

# Create the sample environment file
 .env.local&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Edit&amp;nbsp;&lt;code&gt;.env.local&lt;/code&gt; and fill in your actual values for each variable.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;All required environment variables&lt;/li&gt;
&lt;li&gt;Descriptions and examples for each variable&lt;/li&gt;
&lt;li&gt;Default values where applicable&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 class=&quot;heading-element&quot;&gt;4. Get Your Optimizely Credentials&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;CMS URL&lt;/strong&gt;: Your Optimizely CMS instance URL&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;GraphQL Keys&lt;/strong&gt;: From CMS Dashboard &amp;rarr; Settings &amp;rarr; Render Content
&lt;ul&gt;
&lt;li&gt;App Key&lt;/li&gt;
&lt;li&gt;Secret&lt;/li&gt;
&lt;li&gt;Single Key&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;REST API Credentials&lt;/strong&gt;: From CMS Dashboard &amp;rarr; Settings &amp;rarr; Applications
&lt;ul&gt;
&lt;li&gt;Client ID&lt;/li&gt;
&lt;li&gt;Client Secret&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3 class=&quot;heading-element&quot;&gt;5. Start Development Server&lt;/h3&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;# From the root directory
yarn dev

# Or from the frontend directory
cd apps/frontend
yarn dev&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The development server will start at&amp;nbsp;&lt;strong&gt;&lt;a href=&quot;http://localhost:3000/&quot;&gt;http://localhost:3000/&lt;/a&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h3 class=&quot;heading-element&quot;&gt;Available Development Commands&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;1. Create content type in CMS -  Define the new content type in Optimizely CMS SaaS (via Admin UI or API). 
2. Generate Next.js components 
        yarn opti-cms nextjs:components 
		1. Generates scaffolded Next.js components for the new content type. 
		2. &amp;lt;Component folder&amp;gt;/ index.ts 
3. Pull .Json from CMS 
         yarn opti-cms types:pull 
		1. Pulls the latest .JSON type definitions from the CMS into your project. 
4. Create GraphQL fragment 
        yarn opti-cms nextjs:fragments 
		1. Generates a GraphQL fragment file for querying the content type. 

                                                    OR

2. Instead of line 2 to 4 you can just run this command  Yarn opti-cms nextjs:create 

5. Compile project 
 yarn compile  - Compiles updated TypeScript and GraphQL code to ensure everything is synced. 
yarn run build  - build your solution
ran run dev - run your project

&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Note :- I&amp;rsquo;d recommend to use &amp;lsquo;yarn upgrade-interactive&amp;rsquo; as that&amp;rsquo;ll show all packages that can be updated and allows you to select the ones that you want to update.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Regards,&lt;/p&gt;</id><updated>2026-03-03T12:07:17.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Catalog Traversal with Hangfire. Part 3: Advanced Job Management</title><link href="https://szolkowski.github.io/2026/03/03/Catalog-Traversal-with-Hangfire-Part-3-Advanced-Job-Management" /><id>In Part 1, I showed how to build a memory-efficient catalog traversal service, and in Part 2, I demonstrated practical patterns using Optimizely’s built-in scheduled jobs.</id><updated>2026-03-03T08:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Bypassing WAF Blocking in Optimizely CMS 11 with Custom Base64 Properties</title><link href="https://world.optimizely.com/blogs/amit-mittal/dates/2026/3/bypassing-waf-blocking-in-optimizely-cms-11-with-custom-base64-properties/" /><id>&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;As Optimizely developers, we frequently encounter requirements to allow editors to inject third-party scripts into the &lt;code&gt;head&lt;/code&gt; or &lt;code&gt;body&lt;/code&gt; of a site. Typical examples include Google Tag Manager (GTM), Facebook Messenger chatbots, or specialized analytics trackers. We usually implement this using a standard &lt;code&gt;String&lt;/code&gt; or &lt;code&gt;LongString&lt;/code&gt; property on a &quot;Site Settings&quot; page.&lt;/p&gt;
&lt;p&gt;However, in high-security environments, there is a catch. Modern security architecture usually places a Security Gateway or Web Application Firewall (WAF) (like Cloudflare, Azure Front Door, or Imperva) in front of the application. These gateways inspect the &lt;code&gt;POST&lt;/code&gt; body of incoming requests.&lt;/p&gt;
&lt;p&gt;If an editor tries to publish a script, the gateway flags the raw &lt;code&gt;&amp;lt;script&amp;gt;&lt;/code&gt; tags as a potential XSS (Cross-Site Scripting) attack and blocks the request. The editor receives a vague network error, and their changes are lost.&lt;/p&gt;
&lt;p&gt;In this blog post, I will walk you through a solid, end-to-end solution that bypasses WAF blocking without lowering security standards, ensuring a seamless experience for your editors.&lt;/p&gt;
&lt;h2&gt;Requirement&lt;/h2&gt;
&lt;p&gt;The core requirement is to allow editors to store and manage raw script configurations in Site Settings, using either standard multiline text areas or single-line text boxes, while ensuring that the site remains behind a strict WAF that blocks requests containing raw HTML tags in the payload.&lt;/p&gt;
&lt;h2&gt;The Problem&lt;/h2&gt;
&lt;p&gt;Optimizely CMS Edit Mode is a single-page application that communicates with the server via REST APIs. When an editor clicks &quot;Publish,&quot; the CMS sends a &lt;code&gt;POST&lt;/code&gt; or &lt;code&gt;PUT&lt;/code&gt; request containing the property data.&lt;/p&gt;
&lt;p&gt;If a gateway inspects a request body and finds this...&lt;/p&gt;
&lt;p&gt;&lt;code&gt;{&lt;/code&gt;&lt;br /&gt;&lt;code&gt;&amp;nbsp; &amp;nbsp; &quot;GtmScriptHeader&quot;: &quot;&amp;lt;script&amp;gt;(function(w,d,s,l,i)...&quot;&lt;/code&gt;&lt;br /&gt;&lt;code&gt;}&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;...it blocks it.&lt;/p&gt;
&lt;p&gt;We need a way to transport this data through the firewall without using HTML entities or special characters that might trigger the WAF rules, while also solving the common &quot;Autosave Loop&quot; issue, where the editor UI displays the encoded data instead of readable code during standard autosave events.&lt;/p&gt;
&lt;h2&gt;The Solution: Client-Side Base64 Encoding&lt;/h2&gt;
&lt;p&gt;The architecture we designed involves three main components:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Client-Side (Dojo Mixin):&lt;/strong&gt; Encodes raw script to Base64 &lt;em&gt;before&lt;/em&gt; it leaves the browser on save. It also decodes returning Base64 &lt;em&gt;immediately&lt;/em&gt; onautosave events so the editor always sees readable code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Server-Side (Custom Property):&lt;/strong&gt; Acts as the transparent translation layer. It handles storage formatting in the database and ensures the frontend View always receives decoded raw HTML.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Visual Wrappers (Widgets &amp;amp; Descriptors):&lt;/strong&gt; Allow developers to easily choose between a multiline Textarea or a single-line TextBox via standard &lt;code&gt;[UIHint]&lt;/code&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;We use a &quot;Marker&quot; protocol (&lt;code&gt;SAFE:&lt;/code&gt;) so the system knows exactly when the data came from the UI editor vs. direct C# API calls.&lt;/p&gt;
&lt;h3&gt;Step 1: Client-Side Logic (The Base64 Mixin)&lt;/h3&gt;
&lt;p&gt;Instead of duplicating code, we use a Dojo Mixin to encapsulate the bidirectional encoding logic. This uses standard, modern &lt;code&gt;TextEncoder&lt;/code&gt; and &lt;code&gt;TextDecoder&lt;/code&gt; APIs to ensure all UTF-8 characters (like localized text or emojis) survive the Base64 transformation.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;~/[ProjectRoot]/ClientResources/Scripts/Editors/Base64Mixin.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;define([
    &quot;dojo/_base/declare&quot;
], function (declare) {
    // We return a declared class rather than a plain object to 
    // ensure Dojo can correctly mix it into other constructors.
    return declare(null, {

        // OUTBOUND: Raw Code -&amp;gt; Base64 (Intercepted before saving)
        _getValueAttr: function () {
            // Get the standard value from the parent TextBox/TextArea widget
            var rawValue = this.inherited(arguments);

            if (rawValue &amp;amp;&amp;amp; typeof rawValue === &quot;string&quot;) {
                try {
                    // Standard, modern UTF-8 safe encoding
                    var utf8Bytes = new TextEncoder().encode(rawValue);
                    var binaryString = Array.from(utf8Bytes, function (b) { 
                        return String.fromCharCode(b); 
                    }).join(&quot;&quot;);
                    var base64 = window.btoa(binaryString);

                    // Add the &#39;SAFE:&#39; prefix so the server knows it is encoded.
                    // This bypasses WAF inspection because it is alphanumeric.
                    return &quot;SAFE:&quot; + base64;
                } catch (e) {
                    console.error(&quot;Base64 Encoding failed&quot;, e);
                    // Fallback to raw value if encoding fails
                    return rawValue; 
                }
            }
            return &quot;&quot;;
        },

        // INBOUND: Base64 -&amp;gt; Raw Code (Intercepted during autosave echo/load)
        // This solves the bug where editors see &quot;Massey&quot; data in the box.
        _setValueAttr: function (val) {
            
            // Check if the value is &quot;poisoned&quot; with the SAFE marker
            if (val &amp;amp;&amp;amp; typeof val === &quot;string&quot; &amp;amp;&amp;amp; val.indexOf(&quot;SAFE:&quot;) === 0) {
                try {
                    // Strip the &quot;SAFE:&quot; prefix
                    var base64 = val.substring(5);

                    // Decode Base64 -&amp;gt; Binary String
                    var binaryString = window.atob(base64);

                    // Decode Binary String -&amp;gt; UTF-8 Raw Script
                    var bytes = new Uint8Array(binaryString.length);
                    for (var i = 0; i &amp;lt; binaryString.length; i++) {
                        bytes[i] = binaryString.charCodeAt(i);
                    }
                    val = new TextDecoder().decode(bytes);

                } catch (e) {
                    console.warn(&quot;Decoding failed in UI&quot;, e);
                }
            }

            // Pass the decoded, readable script to the standard Textbox logic
            this.inherited(arguments, [val]);
        }
    });
});&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 2: Visual Wrappers (Textarea &amp;amp; TextBox)&lt;/h3&gt;
&lt;p&gt;Now we create two small Dojo wrappers that combine standard standard Optimizely widgets with your new Mixin.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;~/[ProjectRoot]/ClientResources/Scripts/Editors/Base64Textarea.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;define([
    &quot;dojo/_base/declare&quot;,
    &quot;dijit/form/Textarea&quot;,
    &quot;app/editors/Base64Mixin&quot; // Logical path from module.config
], function (declare, Textarea, Base64Mixin) {
    return declare(&quot;app.editors.Base64Textarea&quot;, [Textarea, Base64Mixin], {});
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;~/[ProjectRoot]/ClientResources/Scripts/Editors/Base64TextBox.js&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;define([
    &quot;dojo/_base/declare&quot;,
    &quot;dijit/form/ValidationTextBox&quot;,
    &quot;app/editors/Base64Mixin&quot;       
], function (declare, TextBox, Base64Mixin) {
    return declare(&quot;app.editors.Base64TextBox&quot;, [TextBox, Base64Mixin], {});
});&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 3: Server-Side Property (The Custom Backing Type)&lt;/h3&gt;
&lt;p&gt;This C# class encapsulates the logic entirely. This adheres to &lt;strong&gt;SOLID&lt;/strong&gt; principles because the Page Model remains clean, while this single class handles all data transformation.&lt;/p&gt;
&lt;p&gt;We ensure Liskov Substitution: the getter always returns a &lt;code&gt;string&lt;/code&gt;, meaning the view doesn&#39;t need to change.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;~/[ProjectRoot]/Business/Properties/PropertyBase64String.cs&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using EPiServer.Core;
using EPiServer.Framework.DataAnnotations;
using EPiServer.PlugIn;
using System;
using System.Text;

namespace MyApp.Business.Properties
{
    // Register this as a custom property definition type in Optimizely
    [PropertyDefinitionTypePlugIn]
    public class PropertyBase64String : PropertyLongString
    {
        private const string TransportPrefix = &quot;SAFE:&quot;;

        public override object Value
        {
            get
            {
                var storedValue = base.Value as string;
                if (string.IsNullOrWhiteSpace(storedValue)) return null;

                // DECODE: Transform DB (Base64) -&amp;gt; View (Raw HTML String)
                try
                {
                    // Fail-safe: Handle legacy data that might be raw HTML
                    if (storedValue.Trim().StartsWith(&quot;&amp;lt;&quot;)) return storedValue;

                    var bytes = Convert.FromBase64String(storedValue);
                    return Encoding.UTF8.GetString(bytes);
                }
                catch
                {
                    return storedValue; // Fail-safe
                }
            }
            set
            {
                if (value is string inputString)
                {
                    // CASE A: Input from Dojo Editor (Has marker)
                    // The WAF let this through because it looked like &quot;SAFE:PGh0...&quot;
                    if (inputString.StartsWith(TransportPrefix))
                    {
                        // Strip marker, store only the pure Base64 in the DB
                        base.Value = inputString.Substring(TransportPrefix.Length);
                    }
                    // CASE B: Input from C# Code (Developer did: page.Script = &quot;&amp;lt;script&amp;gt;...&quot;)
                    else
                    {
                        // We must manually encode it before saving so the format matches Storage
                        var bytes = Encoding.UTF8.GetBytes(inputString);
                        base.Value = Convert.ToBase64String(bytes);
                    }
                }
                else
                {
                    base.Value = value;
                }
            }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Step 4: Editor Descriptors &amp;amp; Usage&lt;/h3&gt;
&lt;p&gt;Finally, we link the UIHints and implement it in a model.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;File:&lt;/strong&gt; &lt;code&gt;~/[ProjectRoot]/Business/EditorDescriptors/Base64Editors.cs&lt;/code&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using EPiServer.Shell.ObjectEditing.EditorDescriptors;

namespace MyApp.Business.EditorDescriptors
{
    [EditorDescriptorRegistration(TargetType = typeof(string), UIHint = &quot;Base64TextArea&quot;)]
    public class Base64TextAreaDescriptor : EditorDescriptor
    {
        public Base64TextAreaDescriptor()
        {
            ClientEditingClass = &quot;app/editors/Base64Textarea&quot;;
        }
    }

    [EditorDescriptorRegistration(TargetType = typeof(string), UIHint = &quot;Base64TextBox&quot;)]
    public class Base64TextBoxDescriptor : EditorDescriptor
    {
        public Base64TextBoxDescriptor()
        {
            ClientEditingClass = &quot;app/editors/Base64TextBox&quot;;
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Implementation in Page Model:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[Display(Name = &quot;GTM Header Script&quot;)]
[UIHint(&quot;Base64TextArea&quot;)]                  // Multiline Visual
[BackingType(typeof(PropertyBase64String))] // Back-end Logic
public virtual string GtmScriptHeader { get; set; }

[Display(Name = &quot;Messenger Chat Script&quot;)]
[UIHint(&quot;Base64TextBox&quot;)]                   // Single-line Visual
[BackingType(typeof(PropertyBase64String))] // Back-end Logic
public virtual string ChatScript { get; set; }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Implementation in Razor View:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Since the property logic always decodes the value back to raw script tags, usage is standard. Remember to use &lt;code&gt;Html.Raw&lt;/code&gt; to prevent Razor from HTML encoding the script tags.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;head&amp;gt;
    @Html.Raw(Model.CurrentPage.GtmScriptHeader)
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;A Note on Handling Existing Properties&lt;/h3&gt;
&lt;p&gt;A common pitfall is applying this logic to an existing property. Optimizely locks Property Definitions in the database. When you run this code, Optimizely might ignore the &lt;code&gt;[BackingType]&lt;/code&gt; attribute and continue treating the existing property as a normal string.&lt;/p&gt;
&lt;p&gt;This results in the &lt;code&gt;SAFE:Base64...&lt;/code&gt; string being saved literally and rendered on the frontend.&lt;/p&gt;
&lt;h4&gt;Crucial Admin Mode Step&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go to &lt;strong&gt;Admin Mode&lt;/strong&gt; -&amp;gt; &lt;strong&gt;Content Types&lt;/strong&gt; -&amp;gt; Find your Page Type -&amp;gt; Select the Property.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If the &lt;strong&gt;Type&lt;/strong&gt; still says &lt;code&gt;Long string&lt;/code&gt; or &lt;code&gt;String&lt;/code&gt; instead of &lt;code&gt;PropertyBase64String&lt;/code&gt;, you must click &lt;strong&gt;&quot;Revert to Default&quot;&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If that button is grayed out, your fastest solution is to &lt;strong&gt;rename the C# property&lt;/strong&gt; in the model (e.g., from &lt;code&gt;ChatScript&lt;/code&gt; to &lt;code&gt;ChatScript_Secure&lt;/code&gt;). Optimizely will see this as a brand new property and apply the custom logic perfectly.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;This custom Base64 Property architecture provides a robust, expert-level solution for bypassing WAF restrictions in Optimizely CMS 11. It preserves the strict security gateway rules required by the organization while maintaining an exceptional experience for editors, who can continue working with the raw code they are familiar with.&lt;/p&gt;
&lt;p&gt;By encapsulating the complexity inside Dojo Mixins and custom Property Types, the implementation adheres to SOLID principles, ensuring your Page Models remain clean and the solution is easy to maintain and scale.&lt;/p&gt;</id><updated>2026-03-02T08:12:59.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Inspect SaaS CMS Packages Without Losing Your Sanity (Package Explorer Update)</title><link href="https://www.codeart.dk/blog/2026/3/packageexplorer-support-for-visual-builder-and-nested-items/" /><id>Optimizely export packages have quietly become more complex. Inline (nested) blocks in CMS 12 and PaaS solutions weren’t always displayed clearly, and with SaaS CMS—and soon CMS 13—Visual Builder introduces compositions, layout hierarchies, and display templates on top. This update to the Optimizely Package Explorer improves support across these scenarios, making it far easier to inspect and understand what’s actually inside your packages.</id><updated>2026-03-01T19:47:18.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Unstoppable: Insights from Optimizely’s 2026 UK Partner day</title><link href="https://world.optimizely.com/blogs/not-another-developer-blog/dates/2026/2/unstoppable-insights-from-optimizelys-2026-uk-partner-day/" /><id>&lt;p&gt;Over 150 Optimizely partners met in Shoreditch for the 2026 London Partner Kick Off. The theme was very much Opal with a side order of Optimizely&#39;s Simon Chapman bringing the &quot;sexy back&quot; to (the forthcoming) CMS 13.&lt;/p&gt;
&lt;p&gt;Here&#39;s my 5 hot takes from the event:&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;&lt;strong&gt;&lt;img src=&quot;/link/2937abdee9af455bb62769f63d4bcd51.aspx&quot; /&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;&lt;strong&gt;1. Opal is No Longer Your Assistant. It&amp;rsquo;s Your New Co-worker&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The most fundamental shift in the 2026 roadmap is the transition of Opal from a &quot;sidekick&quot; into a fully integrated &quot;co-worker.&quot; We are moving beyond simple prompt-based AI and into the era of Agent Orchestration. These are autonomous workflows where agents, triggered by events or schedules, handle end-to-end tasks without constant human prodding.&lt;/p&gt;
&lt;p&gt;As Optimizely CIO Peter Yeung put it: &quot;Opal&#39;s not like a sidekick anymore; it&#39;s not your buddy. This is your co-worker who really helps you at every stage of what you do.&quot;&lt;/p&gt;
&lt;p&gt;This agentic shift represents the &quot;third rising tide&quot; of technology, on par with the arrival of the internet and the explosion of smartphones. It allows your team to move from manual execution to a state of continuous, automated growth.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/b5c7f62d2ef543ce81115af6640cbf58.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;&lt;strong&gt;2. CMS 13 is Making the Agentic CMS Mandatory&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Optimizely is reinventing its flagship product with CMS 13 and the technical bedrock is shifting. The philosophy is now &quot;CMS Core,&quot; where features are built once to serve both SaaS and PaaS users simultaneously. With this update comes some significant steps forward. Key insider details for the CMS 13 rollout include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Technical Foundation: &lt;/strong&gt;Full support for .NET 10 and the implementation of Opti ID for centralised reporting, user rights, and audit trails.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Power of Graph: &lt;/strong&gt;Transitioning to Optimizely Graph is no longer optional. It is the mandatory engine for semantic search and AI-driven content delivery.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Visual Builder:&lt;/strong&gt; To keep marketers &quot;in the flow,&quot; the new Visual Builder provides interactive previews and drag-and-drop orchestration, officially sunsetting the Dojo interface.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SaaS &quot;Growing Up&quot;:&lt;/strong&gt; Optimizely is bridging the gap for enterprise-grade requirements by allowing SaaS to connect to any external source, PIMs, ERPs, CommerceTools, or Bynder via the Optimizely Connect Platform (OCP).&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;3. The &#39;Crawl-to-Refer&#39; Metric. Why SEO is Evolving into GEO&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;In 2026, marketing is no longer just about attracting human clicks. It&amp;rsquo;s a battleground on two-fronts between human engagement and how AI agents &quot;read&quot; your value. This is the era of Generative Engine Optimisation (GEO).&lt;/p&gt;
&lt;p&gt;As Mark Wakelin, Optimizely&#39;s Global Director of Value Consulting, said the roadmap revealed a vital new benchmark. Customers using GDO (Generative Discovery Optimisation) agents have seen a 44% increase in the crawl-to-refer ratio from LLMs. This metric is the difference between an AI &#39;scraping&#39; your data to answer a query on its own platform and that AI &#39;referring&#39; a human visitor to your site to complete a transaction.&lt;/p&gt;
&lt;p&gt;To navigate this, the GEO Recommendations Agent is now a roadmap priority. This tool audits your site for AI-readiness, identifying how well your content performs for search topics and generative schemas and can even auto-generate the .llms.txt files required for modern AI discovery.&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;&lt;strong&gt;4. The Secret Weapon for Devs. Production-Ready Code from Figma&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The friction between marketing requests and developer capacity has long been a bottleneck in MarTech. CMS 13 addresses this with the Front-end Component Generator Agent.&lt;/p&gt;
&lt;p&gt;This isn&#39;t just a code-snippet tool. It allows developers to pull information directly out of Figma frames to automatically create React components and content structures. The workflow is a structural change to the DevOps lifecycle. Agents generate production-ready code and push it directly to GitHub for review. By reducing development cycles from weeks to minutes, organisations can finally achieve true speed-to-market.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/47ea195a49354a83b156a9366df9ffa6.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;5. Transforming the Economics of Growth with Proven ROI&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;AI is not about replacing people. It&amp;rsquo;s about reclaiming time. The 10,000+ hours of GEO-optimisation backlog that many enterprise teams currently face but can never hope to clear. The 2026 strategy focuses on transforming these economics of growth by enabling teams to deliver more value with fewer constraints.&lt;/p&gt;
&lt;p&gt;The data from the 2025 AI Benchmark Report and the New Content Operating Model provide the hard evidence for this shift:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;+78.66%&lt;/strong&gt; in created experiments.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;-53.75%&lt;/strong&gt; in time per campaign.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;+26%&lt;/strong&gt; in content engagement.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;+9.26%&lt;/strong&gt; in win rates for experimentation teams.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;+44%&lt;/strong&gt; increase in the Crawl-to-Refer ratio.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;By using agentic workflows to handle the heavy lifting. The compliance checks, metadata tagging, and reporting teams can finally reclaim their time for the creative tasks they were actually hired for.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/15fddedf3b5b4106b70fe3dfe83a8c55.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-size: 14pt;&quot;&gt;&lt;strong&gt;Conclusion: The Rising Tide of 2026&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;As we enter this third rising tide of technology, the roadmap is set and the agentic ecosystem is ready. Is your team steering their AI program into the safe passage of open water or onto the rocky shoreline?&lt;/p&gt;
&lt;p&gt;To join the unstoppable journey, now is the time to get certified and specialised in the agentic future.&lt;/p&gt;</id><updated>2026-02-27T17:54:32.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>What you need to run better experiments today</title><link href="https://hristo.vercel.app/blogs/what-you-need-to-run-better-experiments-today" /><id>A practical, end-to-end playbook for higher quality A/B tests: conditional activation, targeting, metrics, power, SRM, and decision discipline.</id><updated>2026-02-27T00:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Catalog Traversal in Action. Part 2: Real-World Scheduled Job Patterns</title><link href="https://szolkowski.github.io/2026/02/24/Catalog-Traversal-in-Action-Part-2-Real-World-Scheduled-Job-Patterns" /><id>In my previous post, I showed how to build a memory-efficient catalog traversal service for Optimizely Commerce. The service uses streaming to process large catalogs without loading everything into memory at once.</id><updated>2026-02-24T08:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Resource Editor - A localization management tool for Optimizely CMS</title><link href="https://world.optimizely.com/blogs/Per-Nergard/Dates/2026/2/resource-editor---a-localization-management-tool-for-optimizely-cms/" /><id>&lt;div&gt;If you have worked with Optimizely CMS for any amount of time you know that managing localization through XML files can be tedious. Content type names, property captions, tab names, editor hints - they all need translations, and keeping those XML files organized across multiple languages is not fun.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;I am a firm believer that translations should be owned by the partner and managed in source control. That said, I fully understand the need to fix localization quickly in a DXP environment without having to deploy code. The Resource Editor was built to handle both scenarios - edit and save to XML files during development, and apply runtime overrides via DDS (Dynamic Data Store) when you need a quick fix in production.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;This tool started as a smaller idea but grew quite a bit as I kept adding features. It is built with Blazor Server and MudBlazor, packaged as a Razor Class Library that you can reference in your Optimizely project.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;TL;DR: The Resource Editor is a Blazor-based admin tool for Optimizely CMS that replaces manual XML editing for localization. It provides visual editors for content type &amp;nbsp; names, properties, tabs, display channels, editor hints, and frontend translations &amp;mdash; all with multi-language support. Features include a completeness dashboard, runtime &amp;nbsp;overrides via DDS (no deploy needed), DeepL-powered automated translation at field/item/bulk level, CSV import/export, and a guided migration from legacy XML formats.&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2&gt;Getting started&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;The Resource Editor is distributed as a Razor Class Library. Add a project reference and register the services in your `Startup.cs`:&lt;br /&gt;&lt;br /&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
{
    services.AddServerSideBlazor();
    services.AddMudServices();

    // Optional: Add DeepL translation (must be registered before AddResourceEditor)
    services.AddDeepLTranslation(_configuration);

    // Register Resource Editor services
    services.AddResourceEditor(_configuration);
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;Configuration is done through `appsettings.json`:&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{
  &quot;ResourceEditor&quot;: {
    &quot;TranslationFolder&quot;: &quot;Resources/Translations&quot;,
    &quot;EnableFileSaving&quot;: true,
    &quot;EnableOverrides&quot;: true,
    &quot;ShowOverridesUI&quot;: true,
    &quot;EnableAutomatedTranslation&quot;: true,
    &quot;DeepL&quot;: {
      &quot;ApiKey&quot;: &quot;your-api-key&quot;,
      &quot;UseFreeApi&quot;: true
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;Depending on how you want to render the tool you also need a CSHTML page to host the Blazor component. The tool runs as a full-page Blazor application without the standard Optimizely layout:&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;@using Nergard.ResourceEditor.Components
@using Microsoft.AspNetCore.Components.Web
@model PageViewModel&amp;lt;BlazorToolResourceEditor&amp;gt;

@{ Layout = null; }

&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html lang=&quot;en&quot;&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;meta charset=&quot;UTF-8&quot; /&amp;gt;
    &amp;lt;meta name=&quot;viewport&quot; content=&quot;width=device-width, initial-scale=1&quot; /&amp;gt;
    &amp;lt;base href=&quot;~/&quot; /&amp;gt;
    &amp;lt;title&amp;gt;Resource Editor&amp;lt;/title&amp;gt;
    &amp;lt;link href=&quot;https://fonts.googleapis.com/css?family=Roboto:300,400,500,700&amp;amp;display=swap&quot;
          rel=&quot;stylesheet&quot; /&amp;gt;
    &amp;lt;link href=&quot;_content/MudBlazor/MudBlazor.min.css&quot; rel=&quot;stylesheet&quot; /&amp;gt;
    &amp;lt;component type=&quot;typeof(HeadOutlet)&quot; render-mode=&quot;Server&quot; /&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    @Html.AntiForgeryToken()

    &amp;lt;component type=&quot;typeof(ResourceEditorHost)&quot;
               render-mode=&quot;Server&quot;
               param-IsDarkMode=&quot;false&quot; /&amp;gt;

    &amp;lt;script src=&quot;_framework/blazor.server.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
    &amp;lt;script src=&quot;_content/MudBlazor/MudBlazor.min.js&quot;&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;Create a page type in Optimizely, set up a controller and view, and you are good to go.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2&gt;Dashboard&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;When you open the Resource Editor you land on the dashboard. It gives you an overview of translation completeness across all your configured languages. Each language card shows progress for content types, properties and tabs so you can quickly see where translations are missing.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;The dashboard also shows your view/frontend translation files with their own completion status.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;Clicking a language card takes you directly to the Language Overview for that language. More on that further down in the post.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/705a63ef3c6c42adaa31b3bd0fc1efa1.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;651&quot; /&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2&gt;Content type editor&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;This is where you probably will spend most of your time. The editor lets you manage translations for all your content types, organized in three sections: Pages, Blocks and Media.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;For each content type you can edit the name and description across all languages. Expand a content type and you get access to all its properties where you can edit both the caption (label) and help text.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;The editor detects shared properties - properties that exist on multiple content types - and highlights them. This is useful because shared properties in Optimizely use a fallback mechanism through `icontentdata`, so changing a shared property translation can affect multiple content types. The base type in the saved xml-files will be icontentdata since I believe that same named properties should be consistent throughout the solution.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;You can filter by language if you only want to focus on one language at a time. The tool has support for automatic translations but not for the master language which must be managed manually.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/8e91301e30924d8ebdc05c1594c4c79e.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;500&quot; /&gt;&lt;/div&gt;
&lt;h2&gt;&lt;strong&gt;Tab editor&lt;/strong&gt;&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;The Tab Editor handles localization of property group names (tabs). These are the tab labels editors see in the content editing UI.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;It works the same way as the content type editor - select a tab, edit the name across all configured languages, save.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/1cbb177b94214c149fb719ed71fb2e4b.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;455&quot; /&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;h2&gt;Display Channels and Editor Hints&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;Two smaller editors handle display channel names and editor hint names. Same pattern - select an item, edit translations, save. These are less commonly needed but nice to have covered.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/69a222d0653144c88840df08ccdf1abf.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;484&quot; /&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;h2&gt;&lt;strong&gt;View / Frontend Translations&lt;/strong&gt;&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;The Resource Editor also handles view translation files. &amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;These files use a multi-language format where all languages are in a single XML file. The editor presents them as a navigable tree structure where you can edit values per language, add new sections and add new keys.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;The file pattern is configurable via the `ViewFilePattern` option (defaults to `views_*.xml`).&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/2f9b109aeadc43d8a6714fe984a2205a.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;477&quot; /&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2&gt;Language overview&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;The Language Overview gives you a focused view of a single language. It shows all content types and their properties with translation status indicators so you can work through missing translations systematically.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;This is also where the bulk translate button lives - translate all incomplete fields for a language in one click.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;Note! The automatic translations are only for the non master languages. So put in the effort for good localization texts for the master language you can reap the benefits for the other languages.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/5dcdfcb88976474ab7071cc50d8ba0c1.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;557&quot; /&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2&gt;Overrides&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;This is the feature that makes the Resource Editor work well in DXP environments. Overrides are stored in the Dynamic Data Store and take precedence over XML translations at runtime - no deployment needed.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;The override system works through a custom `LocalizationProvider` that is automatically registered at position 0 in the provider chain. When Optimizely resolves a localization key, the override provider checks DDS first. If no override exists, it falls through to the standard XML-based providers.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&lt;em&gt;**Known issue:** There is currently a known issue where overridden content type captions (names) may not be picked up correctly by Optimizely, while help text overrides work as expected. I have an ongoing support ticket with Optimizely for investigation.&lt;/em&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h3&gt;Inline overrides&lt;/h3&gt;
&lt;div&gt;
&lt;div&gt;When `ShowOverridesUI` is enabled, every text field in the editors gets a small override button. Click it and you can create an override for that specific field and language. The override is stored in DDS and takes effect immediately.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/cace30955a8f4c108bb4b53060c428f5.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;479&quot; /&gt;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;Override manager&lt;/h3&gt;
&lt;div&gt;- View all active overrides with language and value&lt;/div&gt;
&lt;div&gt;- Filter by language and search by property name&lt;/div&gt;
&lt;div&gt;- Add, edit and delete individual overrides&lt;/div&gt;
&lt;div&gt;- **Export to CSV** for documentation or backup&lt;/div&gt;
&lt;div&gt;- **Import from CSV** for bulk operations&lt;/div&gt;
&lt;div&gt;- **Save to XML** to migrate an override into a permanent translation file&lt;/div&gt;
&lt;div&gt;- Clear all overrides&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/102e96bc602444a39dbeff5f6b6800ab.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;435&quot; /&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2&gt;Automated translations with DeepL&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;If you enable automated translation and register the DeepL service, the Resource Editor gives you translation assistance at three levels:&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;1. **Field level** - Each text field gets a translate button that translates from the default language&lt;/div&gt;
&lt;div&gt;2. **Item level** - A &quot;Translate Missing&quot; button in each editor header translates all empty fields for the current item&lt;/div&gt;
&lt;div&gt;3. **Bulk level** - In the Language Overview, translate all incomplete fields for an entire language&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;The translations populate the fields but are not saved automatically - you review and save when you are happy with the results.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;To enable it, signup for the free tier of DeepL and then register the DeepL service before the Resource Editor:&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddDeepLTranslation(_configuration);
services.AddResourceEditor(_configuration);&lt;/code&gt;&lt;/pre&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;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;div&gt;The translation service is pluggable. If you want to use a different provider than DeepL, implement `ITranslationService` and register it before calling `AddResourceEditor()`.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/e26f1f3099774d7faa4a1046fe6a6c14.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;281&quot; /&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;
&lt;h2&gt;XML Migration&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;If you have an existing site with translations in the classic Alloy XML format (separate files like `ContentTypeNames.xml`, `PropertyNames.xml`, `GroupNames.xml`), the Resource Editor detects this automatically and offers a guided migration to its own format. The migration runs step by step with progress tracking and error reporting.&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&lt;img src=&quot;/link/9a7c8780c3824bd6a8933176e7e5e6cc.aspx&quot; alt=&quot;&quot; width=&quot;818&quot; height=&quot;654&quot; /&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2&gt;Configuration options&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;Here is a quick overview of all the configuration options:&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;| Option | Default | Description |
|--------|---------|-------------|
| `TranslationFolder` | `Resources/Translations` | Path to translation XML files |
| `EnableFileSaving` | `true` | Allow saving to XML files. Set to `false` on DXP |
| `EnableOverrides` | `true` | Enable DDS-based runtime overrides |
| `ShowOverridesUI` | `true` | Show inline override buttons in editors |
| `EnableAutomatedTranslation` | `false` | Enable automated translation features |
| `ViewFilePattern` | `views_*.xml` | Glob pattern for view translation files |&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;
&lt;div&gt;
&lt;div&gt;A typical DXP configuration would look like this:&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;{
  &quot;ResourceEditor&quot;: {
    &quot;EnableFileSaving&quot;: false,
    &quot;EnableOverrides&quot;: true,
    &quot;ShowOverridesUI&quot;: true
  }
}&lt;/code&gt;&lt;/pre&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;h2&gt;Source code and license&lt;/h2&gt;
&lt;div&gt;
&lt;div&gt;The full source code is available on GitHub: &lt;a href=&quot;https://github.com/PNergard/Resource-Editor&quot;&gt;Resource Editor GitHub&lt;/a&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;
&lt;div&gt;This tool grew organically and while I have been testing it using a Alloy demo template, I would still recommend using it with some care - especially the save operations. Back up your XML files before making large changes. I am happy to receive feedback, bug reports and pull requests.&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;div&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;/div&gt;
&lt;div&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;&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;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2026-02-23T06:58:46.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>