<?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-05-07T22:55:12.0000000Z</updated><id>https://world.optimizely.com/blogs/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Commerce 15 and CMS 13: Optimizely’s Next Step Toward AI-Powered, Graph-First Commerce</title><link href="https://world.optimizely.com/blogs/opti-chronicles/dates/2026/4/commerce-15-and-cms-13-optimizelys-next-step-toward-ai-powered-graph-first-commerce/" /><id>&lt;p&gt;Optimizely is preparing to release &lt;strong&gt;Commerce 15 in mid-May 2026&lt;/strong&gt;, positioning this as a foundational shift&amp;mdash;not just an upgrade. The direction is clear: move from fragmented tooling and isolated AI features toward a&lt;strong&gt; &lt;/strong&gt;graph-first, AI-embedded commerce platform where search, content, and operations are unified.&lt;/p&gt;
&lt;p&gt;The headline changes are not cosmetic. Visual Builder replaces legacy editing paradigms, OptiGraph becomes the default search and data layer, and Opal evolves from a set of tools into a core operational interface for commerce teams. At the same time, the upgrade path introduces real architectural considerations&amp;mdash;especially for organizations still dependent on Find, legacy APIs, or external service layers.&lt;/p&gt;
&lt;p&gt;For decision-makers, the implication is straightforward: Commerce 15 is where Optimizely is investing future innovation, particularly around AI agents and automation. The question is less &amp;ldquo;should we upgrade?&amp;rdquo; and more &amp;ldquo;how do we prepare to adopt a fundamentally different operating model?&amp;rdquo;&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Market Context: Commerce Is Moving from Systems to Systems of Intelligence&lt;/h2&gt;
&lt;p&gt;Modern commerce platforms are no longer judged solely on catalog management, checkout performance, or integration flexibility. The competitive frontier has shifted toward:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Speed of content and campaign execution&lt;/li&gt;
&lt;li&gt;Search and discovery quality (increasingly semantic and AI-driven)&lt;/li&gt;
&lt;li&gt;Operational efficiency for merchandisers and marketers&lt;/li&gt;
&lt;li&gt;Embedded intelligence across workflows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;What&amp;rsquo;s often missed is that most commerce stacks still operate as systems of record, not systems of intelligence. Data exists&amp;mdash;but it isn&amp;rsquo;t continuously activated.&lt;/p&gt;
&lt;p&gt;Commerce 15 reflects a broader industry trend:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;moving from &amp;ldquo;tools that support workflows&amp;rdquo; to &amp;ldquo;platforms that participate in workflows.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;The Optimizely Perspective: Commerce 15 as a Graph-First, AI-Embedded Platform&lt;/h2&gt;
&lt;p&gt;Commerce 15 is being framed as a&lt;strong&gt; &lt;/strong&gt;modern, AI-powered, graph-first commerce platform&lt;/p&gt;
&lt;p&gt;Three structural shifts define this positioning:&lt;/p&gt;
&lt;h3&gt;1. Graph as the foundation (not an add-on)&lt;/h3&gt;
&lt;p&gt;OptiGraph replaces Find as the default search and data layer, enabling unified indexing across CMS, commerce, DAM, and CMP.&lt;/p&gt;
&lt;h3&gt;2. AI embedded into workflows&lt;/h3&gt;
&lt;p&gt;Opal is no longer a side feature. It becomes part of day-to-day commerce operations, from product management to promotions.&lt;/p&gt;
&lt;h3&gt;3. Experience creation without developer bottlenecks&lt;/h3&gt;
&lt;p&gt;Visual Builder and integrated tooling shift control toward business users&amp;mdash;particularly merchandisers.&lt;/p&gt;
&lt;p&gt;This combination is what makes Commerce 15 feel less like a version upgrade and more like a platform reset.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;What&amp;rsquo;s New (and Why It Matters)&lt;/h2&gt;
&lt;h3&gt;Visual Builder: Merchandiser-Led Experience Creation&lt;/h3&gt;
&lt;p&gt;Visual Builder replaces the traditional on-page editor and is now embedded directly into commerce workflows.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Build PDPs, category pages, and promotions visually&lt;/li&gt;
&lt;li&gt;Access all blocks, templates, and components in one interface&lt;/li&gt;
&lt;li&gt;Reduce dependency on developer tickets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The practical impact is significant:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Faster campaign launches&lt;/li&gt;
&lt;li&gt;Lower backlog pressure on engineering&lt;/li&gt;
&lt;li&gt;More experimentation at the merchandising level&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Or, as framed in April 28th Optimizely session Introduction to Commerce 15:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Visual Builder gives your developers their time back.&amp;rdquo;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h3&gt;External Content: Breaking Down System Silos&lt;/h3&gt;
&lt;p&gt;Commerce 15 introduces stronger support for pulling data from external systems (ERP, PIM, etc.) into CMS.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Centralized product and content management&lt;/li&gt;
&lt;li&gt;Reduced need for custom integration layers&lt;/li&gt;
&lt;li&gt;Single UI for merchandisers&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is less about convenience and more about operational coherence.&lt;br /&gt;When product data, content, and customer context live together, personalization and campaign execution become materially easier.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;Embedded DAM: Content Operations at Scale&lt;/h3&gt;
&lt;p&gt;The embedded DAM brings:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AI-powered tagging&lt;/li&gt;
&lt;li&gt;Automated renditions&lt;/li&gt;
&lt;li&gt;Integrated asset workflows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For SKU-heavy organizations, this addresses a persistent bottleneck: managing media at scale without introducing content chaos.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;CMP-to-CMS Publishing: Closing the Campaign Gap&lt;/h3&gt;
&lt;p&gt;Campaign workflows now connect directly to CMS:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Content moves from planning to publishing without manual handoffs&lt;/li&gt;
&lt;li&gt;Templates and previews streamline execution&lt;/li&gt;
&lt;li&gt;Alignment between marketing and web teams improves&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This is a subtle but important shift&amp;mdash;reducing the friction between strategy and execution.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;OptiGraph: The Shift from Search Engine to Experience Layer&lt;/h3&gt;
&lt;p&gt;OptiGraph replaces Find as the default search and navigation engine.&lt;/p&gt;
&lt;p&gt;Key capabilities include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Unified indexing across platforms&lt;/li&gt;
&lt;li&gt;Semantic, intent-aware search&lt;/li&gt;
&lt;li&gt;Support for AI-driven context (Opal)&lt;/li&gt;
&lt;/ul&gt;
&lt;blockquote&gt;
&lt;p&gt;&amp;ldquo;Graph is now acting as the de facto experience/discovery layer and internal search provider instead of Find.&amp;rdquo;&amp;nbsp;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This matters because search is no longer just about retrieval&amp;mdash;it&amp;rsquo;s about interpretation and relevance in context.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Opal: From Feature to Operating Model&lt;/h2&gt;
&lt;p&gt;The most strategic change in Commerce 15 is how AI is positioned.&lt;/p&gt;
&lt;h3&gt;Available now:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Opal Chat for content and optimization&lt;/li&gt;
&lt;li&gt;Product catalog translations&lt;/li&gt;
&lt;li&gt;Promotions agent&lt;/li&gt;
&lt;li&gt;Data-fetching tools via Graph&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Expected next:&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Product catalog management agent (bulk operations)&lt;/li&gt;
&lt;li&gt;Expanded Opal Chat for commerce workflows&lt;/li&gt;
&lt;li&gt;Google AI Search (leveraging vector-based retrieval)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The narrative is clear:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;AI is moving from isolated capabilities into&lt;strong&gt; &lt;/strong&gt;embedded commerce workflows.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In practice, this means:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Merchandisers can generate and optimize content in context&lt;/li&gt;
&lt;li&gt;Promotions can be created via natural language&lt;/li&gt;
&lt;li&gt;Catalog operations can be automated at scale&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Commerce 14 vs Commerce 15: A Strategic Decision Point&lt;/h2&gt;
&lt;p&gt;One of the more important signals from the announcement:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Commerce 14 will receive limited future out-of-the-box agent support&lt;/li&gt;
&lt;li&gt;Commerce 15 becomes the primary platform for all future AI innovation&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This creates a clear fork in the road:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stay on Commerce 14 &amp;rarr; maintain stability, rely on custom solutions&lt;/li&gt;
&lt;li&gt;Move to Commerce 15 &amp;rarr; access future Opal agents and platform capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For most organizations, this isn&amp;rsquo;t just a technical upgrade&amp;mdash;it&amp;rsquo;s a roadmap decision.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;What Merchants and Teams Gain&lt;/h2&gt;
&lt;h3&gt;For Merchandisers&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Greater autonomy (Visual Builder, Opal agents)&lt;/li&gt;
&lt;li&gt;Faster campaign execution&lt;/li&gt;
&lt;li&gt;Less reliance on dev cycles&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;For Marketing Teams&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Direct CMP-to-CMS workflows&lt;/li&gt;
&lt;li&gt;Better alignment between planning and publishing&lt;/li&gt;
&lt;li&gt;Improved personalization potential&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;For Engineering&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Reduced content-related workload&lt;/li&gt;
&lt;li&gt;Opportunity to focus on higher-value architecture and integrations&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;For Leadership&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Faster time-to-market&lt;/li&gt;
&lt;li&gt;Improved operational efficiency&lt;/li&gt;
&lt;li&gt;Platform aligned with AI-driven future capabilities&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Migration Reality: What You Need to Plan For&lt;/h2&gt;
&lt;p&gt;This is where many organizations underestimate the effort.&lt;/p&gt;
&lt;h3&gt;1. Find &amp;rarr; OptiGraph Migration&lt;/h3&gt;
&lt;p&gt;This is not optional.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Search logic must be re-implemented&lt;/li&gt;
&lt;li&gt;Indexing strategies must be redesigned&lt;/li&gt;
&lt;li&gt;Category and content rendering may need refactoring&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;2. API and Architecture Changes&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Deprecated APIs require review&lt;/li&gt;
&lt;li&gt;Content Delivery APIs are &lt;strong&gt;migration-only&lt;/strong&gt; (not future-facing)&lt;/li&gt;
&lt;li&gt;New development must align with a &lt;strong&gt;Graph-first approach&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;3. OptiID Becomes Mandatory&lt;/h3&gt;
&lt;p&gt;OptiID is required for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Content Manager&lt;/li&gt;
&lt;li&gt;DAM&lt;/li&gt;
&lt;li&gt;Opal&lt;/li&gt;
&lt;li&gt;Connect Platform&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Organizations not already using it must plan for identity and access transitions.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;4. Service API Timing&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Not available at launch (mid-May)&lt;/li&gt;
&lt;li&gt;Expected later in Q2 2026&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your implementation depends on Service API or PIM connectors, timing your upgrade becomes critical.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;Risks and Trade-offs (Pragmatic View)&lt;/h2&gt;
&lt;p&gt;Even with a strong platform direction, there are real considerations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Migration complexity (especially search and indexing)&lt;/li&gt;
&lt;li&gt;Dependency alignment (Service API, connectors)&lt;/li&gt;
&lt;li&gt;Organizational readiness (AI adoption, workflow changes)&lt;/li&gt;
&lt;li&gt;Learning curve for new tooling (Graph, Opal, Visual Builder)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That said, these are not unusual for a major platform evolution&amp;mdash;they&amp;rsquo;re the cost of moving to a more modern architecture.&lt;/p&gt;
&lt;hr /&gt;
&lt;h2&gt;What&amp;rsquo;s Often Missed&lt;/h2&gt;
&lt;p&gt;Most discussions will focus on features. The more interesting shift is operational:&lt;/p&gt;
&lt;p&gt;Commerce 15 is designed to make merchandisers more self-sufficient and AI part of daily execution, not strategy decks.&lt;/p&gt;
&lt;p&gt;That changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How teams work&lt;/li&gt;
&lt;li&gt;How fast they move&lt;/li&gt;
&lt;li&gt;How value is created&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h2&gt;Conclusion: A Platform Shift Worth Planning For Now&lt;/h2&gt;
&lt;p&gt;Commerce 15 represents a decisive move by Optimizely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;From search engine &amp;rarr; experience graph&lt;/li&gt;
&lt;li&gt;From tools &amp;rarr; embedded intelligence&lt;/li&gt;
&lt;li&gt;From developer-led workflows &amp;rarr; merchandiser-led execution&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For decision-makers, the takeaway is not just &amp;ldquo;this is a new version.&amp;rdquo;&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Commerce 15 defines where Optimizely is going&amp;mdash;and where your commerce capabilities can go if you align early.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;hr /&gt;
&lt;h2&gt;Next Steps for Leaders&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Assess your current dependencies&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Find usage&lt;/li&gt;
&lt;li&gt;Service API reliance&lt;/li&gt;
&lt;li&gt;Identity model (OptiID readiness)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Engage your implementation partner early&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Review upgrade complexity&lt;/li&gt;
&lt;li&gt;Validate timelines against Q2 dependencies&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Explore preview packages&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Understand Graph and Visual Builder in practice&lt;/li&gt;
&lt;li&gt;Evaluate Opal use cases relevant to your business&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Align internal teams&lt;/strong&gt;
&lt;ul&gt;
&lt;li&gt;Prepare merchandisers for new workflows&lt;/li&gt;
&lt;li&gt;Define governance for AI usage (human-in-the-loop, approvals, auditing)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;</id><updated>2026-05-07T22:55:12.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>The future of Content: Introducing Optimizely CMS 13</title><link href="https://world.optimizely.com/blogs/aniket-gadre/dates/2026/3/the-future-of-content-introducing-optimizely-cms-13/" /><id>&lt;div class=&quot;markdown markdown-main-panel tutor-markdown-rendering enable-updated-hr-color&quot;&gt;
&lt;p&gt;Optimizely In the rapidly evolving landscape of digital experience, the &quot;monolithic vs. headless&quot; debate is being replaced by a more sophisticated demand: the need for an AI-powered, composable content engine&lt;strong&gt;.&lt;/strong&gt; Optimizely has officially stepped into this future with the announcement of CMS 13.&lt;/p&gt;
&lt;p&gt;More than just a version update, CMS 13 represents a fundamental shift in how organizations will create, manage, and deliver digital experiences.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;What is Optimizely CMS 13?&lt;/h3&gt;
&lt;p&gt;Optimizely CMS 13 is an AI-powered, composable CMS designed to give marketing teams total autonomy while enabling developers to build scalable, API-driven digital experiences. It bridges the gap between structured content and visual creativity.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;An AI-First Content Platform&lt;/h3&gt;
&lt;p&gt;We are moving past the era where AI is a &quot;plugin&quot; or an external tool. In CMS 13, AI is woven into the very fabric of the workflow through Optimizely Opal AI agents.&lt;/p&gt;
&lt;p&gt;Rather than jumping between tabs to generate copy or optimize SEO, content teams can leverage AI directly within the interface for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Drafting and refining copy on the fly.&lt;/li&gt;
&lt;li&gt;Real-time suggestions to improve engagement and performance.&lt;/li&gt;
&lt;li&gt;Quickly repurposing content for different channels and formats.&lt;/li&gt;
&lt;li&gt;Enhancing how users discover content through smarter, intent-based search.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;The Bottom Line:&lt;/strong&gt; AI is a requirement for scaling content operations. CMS 13 embeds intelligence into the creator&amp;rsquo;s daily routine.&lt;/p&gt;
&lt;h3&gt;Composable, API-Driven, and Built for GraphQL&lt;/h3&gt;
&lt;p&gt;The modern enterprise needs content as structured data, not just as static pages. CMS 13 is built on a modern .NET foundation and centers its delivery around Optimizely Graph.&lt;/p&gt;
&lt;p&gt;By moving toward a GraphQL-first architecture, CMS 13 enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;True Hybrid Headless: Choose between traditional server-side rendering or a headless approach for modern frameworks like Next.js and React.&lt;/li&gt;
&lt;li&gt;Cross-Channel Reuse: Write content once and deliver it via API to mobile apps, IoT devices, or web storefronts.&lt;/li&gt;
&lt;li&gt;External Integration: Seamlessly pull in content from third-party sources to create a unified experience.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Maximum Marketing Autonomy&lt;/h3&gt;
&lt;p&gt;For years, marketers have been tethered to engineering schedules for simple layout changes. CMS 13 breaks this cycle with the Visual Builder.&lt;/p&gt;
&lt;p&gt;Key features empowering the marketing team include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Visual Builder: A high-fidelity, drag-and-drop experience for building pages.&lt;/li&gt;
&lt;li&gt;Real-Time Preview: See exactly how content looks across devices before hitting publish.&lt;/li&gt;
&lt;li&gt;Embedded DAM: Direct access to assets without leaving the editor.&lt;/li&gt;
&lt;li&gt;Workflow Automation: Streamlined approvals that keep the content engine running smoothly.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Part of the &quot;Optimizely One&quot; Operating System&lt;/h3&gt;
&lt;p&gt;CMS 13 isn&#39;t a silo; it is the heartbeat of Optimizely One, the world&#39;s first operating system for marketers. It integrates natively with:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;Experimentation&lt;/span&gt;: Run A/B tests on any element directly.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;Personalization&lt;/span&gt;: Deliver unique content based on real-time user data.&lt;/li&gt;
&lt;li&gt;&lt;span style=&quot;text-decoration: underline;&quot;&gt;Opti ID&lt;/span&gt;: A unified authentication system that provides a single sign-on experience across the entire Optimizely suite.&lt;/li&gt;
&lt;/ul&gt;
&lt;hr /&gt;
&lt;h3&gt;Why Upgrade from CMS 13?&lt;/h3&gt;
&lt;p&gt;If you are currently on CMS 12, the move to 13 offers significant performance and functional leaps:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Modern .NET Foundation: Stay current with the latest .NET framework for better performance and security.&lt;/li&gt;
&lt;li&gt;Native Graph Integration: Shift from traditional SQL-heavy delivery to high-performance Graph-powered APIs.&lt;/li&gt;
&lt;li&gt;Enhanced Editor UI: A refreshed, intuitive interface designed for the modern creator.&lt;/li&gt;
&lt;li&gt;Future-Proofing: CMS 13 is the gateway to Optimizely&amp;rsquo;s full SaaS and AI capabilities.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Implementation Checklist: Things to Consider&lt;/h3&gt;
&lt;p&gt;If you&amp;rsquo;re planning a move to the CMS 13 pre-release, keep these four technical shifts in mind:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Opti ID (Single Sign-On) and Optimizely Graph are now mandatory and included in your license. They act as the &quot;connective tissue&quot; for AI and cross-product features.&lt;/li&gt;
&lt;li&gt;Legacy &quot;Search &amp;amp; Navigation&quot; (Find) is deprecated. You must implement search via Optimizely Graph or a third-party provider.&lt;/li&gt;
&lt;li&gt;Good news&amp;mdash;the Visual Builder supports standard ASP.NET applications and is &lt;em&gt;not&lt;/em&gt; dependent on Graph, making it accessible for traditional setups.&lt;/li&gt;
&lt;li&gt;The pre-release includes a refreshed .NET SDK, enhanced multilingual tools, and custom preview routing for headless sites.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Is CMS 13 Right for You?&lt;/h3&gt;
&lt;p&gt;CMS 13 is ideal for all enterprise organizations that require:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Multi-site and multi-language management at scale.&lt;/li&gt;
&lt;li&gt;A &quot;Headless-Plus&quot; approach (the flexibility of headless with the ease of visual editing).&lt;/li&gt;
&lt;li&gt;Deep integration between content, commerce, and experimentation.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Considerations:&lt;/strong&gt; While the benefits are vast, organizations should evaluate the migration path from CMS 11/12 and ensure their development teams are comfortable with the .NET ecosystem and GraphQL delivery models.&lt;/p&gt;
&lt;hr /&gt;
&lt;h3&gt;The Verdict&lt;/h3&gt;
&lt;p&gt;The release of CMS 13 signals the end of the &quot;static&quot; CMS. By combining the speed of AI, the flexibility of a composable architecture, and the freedom of visual editing, Optimizely is giving brands the tools they need to compete in an omnichannel world.&lt;/p&gt;
&lt;/div&gt;</id><updated>2026-05-06T14:02:43.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Hide built in scheduled job from the admin UI</title><link href="https://world.optimizely.com/blogs/Per-Nergard/Dates/2026/4/hide-built-in-scheduled-job-from-the-admin-ui/" /><id>&lt;p&gt;Ok so this probably goes into the not so useful section but late last night I got a veery strong feeling that all projects I am&amp;nbsp; involved with have alot of builtin scheduled jobs that are never used and only add noice to the admin ui scheduled job list. So there must be a way to hide them I thought...&lt;/p&gt;
&lt;p&gt;And it turns out that you can, even though that in retrospect this isn&#39;t such a big problem maybe :). But I created a&amp;nbsp; RCL project which you just register / configure in your solution.&lt;/p&gt;
&lt;p&gt;You can get the code over at &lt;a href=&quot;https://github.com/PNergard/Nergard.ScheduledJobVisibility&quot;&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Usage&lt;br /&gt;1. Add the below line to startup and then start in debug mode and check the output for a list of scheduledjobs and their guid / name&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.HideScheduledJobs(_ =&amp;gt; { });&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;2. Add the Guids you want to hide&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.HideScheduledJobs(opts =&amp;gt; opts
    .Hide(new Guid(&quot;e652f3bd-f550-40e8-8743-2c39cda651dc&quot;), &quot;Remove unrelated content assets&quot;)
    .Hide(new Guid(&quot;656e747e-b2cb-4930-83dc-5d8d97aeaabb&quot;), &quot;Trim content versions&quot;));&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Results&amp;nbsp;&lt;br /&gt;&lt;br /&gt;All jobs visible:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/a8fd58add1374f2fae6aa44ff47e3f54.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;572&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Here I have hidden the bottow two&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/c3ddca0c1c5e459d9b1b0045a68e87ef.aspx&quot; alt=&quot;&quot; width=&quot;1200&quot; height=&quot;523&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</id><updated>2026-05-06T08:52:48.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Optimizely SaaS CMS Developer Certification Exam </title><link href="https://world.optimizely.com/blogs/megharathore/dates/2026/5/optimizely-saas-cms-developer-certification/" /><id>&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;The Optimizely SaaS CMS Developer Certification is an industry-recognized credential for developers and architects who build scalable, composable digital experiences on Optimizely&#39;s cloud-native, headless SaaS CMS. It validates your ability to work with APIs, SDKs, and front-end frameworks to deliver personalized content fast across multiple channels &amp;mdash; without ever managing infrastructure.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;There are two tiers: Core Competency and Expert Competency. I&#39;m starting with Core. Once I clear it, Expert is next. The certification stays valid for 24 months and earns you a Credly digital badge on passing.&lt;/p&gt;
&lt;hr class=&quot;reader-divider-block__horizontal-rule&quot; /&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;&lt;strong&gt;Exam at a glance&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;50 multiple-choice questions&lt;/li&gt;
&lt;li&gt;60 minutes to complete&lt;/li&gt;
&lt;li&gt;80% minimum passing score&lt;/li&gt;
&lt;li&gt;24 months validity&lt;/li&gt;
&lt;li&gt;Cost: $300 USD&lt;/li&gt;
&lt;li&gt;Level: Intermediate&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;&lt;strong&gt;One important thing to know about the exam coupon&lt;/strong&gt;: Once you buy the exam ($300), you have &lt;strong&gt;14 days&lt;/strong&gt; to complete it. Within those 14 days, if you don&#39;t pass on your first attempt, you &lt;strong&gt;do not need to buy again&lt;/strong&gt; &amp;mdash; you can retake the exam using the same purchase. The only condition is that you must wait &lt;strong&gt;24 hours&lt;/strong&gt; after a failed attempt before trying again.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;However, if the 14-day window expires without you passing, you will need to purchase a fresh attempt. So the smart move is to &lt;strong&gt;finish your preparation first, then purchase&lt;/strong&gt;&amp;mdash;don&#39;t buy the exam and then start studying.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;&lt;strong&gt;Also worth noting: exam registrations are for individual use only and cannot be transferred to someone else.&lt;/strong&gt;&lt;/p&gt;
&lt;hr class=&quot;reader-divider-block__horizontal-rule&quot; /&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;&lt;strong&gt;My study plan&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;Week 1&amp;ndash;2: Complete the SaaS CMS Fundamentals eLearning collection on Optimizely Academy &amp;mdash; content types, content graph, visual builder, and delivery APIs.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;Week 3: Get hands-on with the Content Graph API, front-end integration (Next.js / React), visitor groups, and personalization patterns.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;Week 4: Review the official Core Competency reference material, revisit weak areas, and do timed practice runs against the exam guide.&lt;/p&gt;
&lt;hr class=&quot;reader-divider-block__horizontal-rule&quot; /&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;&lt;strong&gt;Resources I&#39;m using &amp;mdash;&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Core Competency reference material &amp;rarr; &lt;a class=&quot;BcCwxaHikpyepwRwtVGKNyXGurXnwmOyGVc &quot; href=&quot;http://academy.optimizely.com/student/activity/2408711&quot;&gt;academy.optimizely.com/student/activity/2408711&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CMS (SaaS) Development Fundamentals eLearning &amp;rarr; &lt;a class=&quot;BcCwxaHikpyepwRwtVGKNyXGurXnwmOyGVc &quot; href=&quot;http://academy.optimizely.com/student/collection/1405874/path/4572932&quot;&gt;academy.optimizely.com/student/collection/1405874/path/4572932&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CMS (SaaS) Advanced Developer eLearning &amp;rarr; &lt;a class=&quot;BcCwxaHikpyepwRwtVGKNyXGurXnwmOyGVc &quot; href=&quot;http://academy.optimizely.com/student/collection/1405874/path/4621878&quot;&gt;academy.optimizely.com/student/collection/1405874/path/4621878&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;CMS event recordings &amp;rarr; &lt;a class=&quot;BcCwxaHikpyepwRwtVGKNyXGurXnwmOyGVc &quot; href=&quot;http://academy.optimizely.com/student/collection/2621565&quot;&gt;academy.optimizely.com/student/collection/2621565&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Official exam page &amp;rarr; &lt;a class=&quot;BcCwxaHikpyepwRwtVGKNyXGurXnwmOyGVc &quot; href=&quot;http://academy.optimizely.com/student/activity/2181428&quot;&gt;academy.optimizely.com/student/activity/2181428&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Optimizely developer docs &amp;rarr; &lt;a class=&quot;BcCwxaHikpyepwRwtVGKNyXGurXnwmOyGVc &quot; href=&quot;http://docs.developers.optimizely.com/&quot;&gt;docs.developers.optimizely.com&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;&lt;strong&gt;One tip from the community: &lt;/strong&gt;Don&#39;t just read &amp;mdash; build things. The exam is practical, so setting up a real SaaS CMS project, wiring up content types, querying the content graph, and rendering through a front-end framework will teach you far more than passive reading alone.&lt;/p&gt;</id><updated>2026-05-05T10:00:17.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Piwik PRO Connector for Optimizely CMS — Now on NuGet (and Yes, It Speaks Both 12 and 13)</title><link href="https://www.codeart.dk/blog/2026/5/announcing-piwikpro-optimizely-connector/" /><id>Analytics has spent the last decade living in another tab — and what&#39;s in that tab usually isn&#39;t the full story. Between consent requirements, browser restrictions, and the gap between &quot;what marketing wants to know&quot; and &quot;what the tracking script actually captures&quot;, most analytics setups end up describing about half the picture. The new Piwik PRO Connector for Optimizely CMS is now live on NuGet, dual-targeted for both CMS 12 (.NET 8) and CMS 13 (.NET 10) from the exact same package — and one of its quieter superpowers is making it dramatically easier to get rich Optimizely context (content type, language, audience membership, block impressions, plus whichever custom dimensions matter for your site) into Piwik PRO, so the dashboards finally know what they&#39;re looking at. Editors get analytics next to their content. Developers get a tracking API that doesn&#39;t require writing JavaScript by hand. And the privacy-first part comes for free, courtesy of Piwik PRO.</id><updated>2026-05-04T20:09:31.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A First Look at Optimizely Remote MCP Server for Experimentation</title><link href="https://world.optimizely.com/blogs/jacob-pretorius/dates/2026/5/a-first-look-at-optimizely-remote-mcp-server-for-experimentation/" /><id>&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;Optimizely just released a &lt;a href=&quot;https://support.optimizely.com/hc/en-us/articles/45321030398349-Optimizely-Experimentation-MCP-server-quickstart&quot;&gt;Remote MCP Server for Experimentation&lt;/a&gt; and I&#39;ve been trying it out to see what it can do.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;If you don&#39;t know, MCP (Model Context Protocol) is the &quot;standard&quot; way for AI tools to talk to external services. Optimizely already had a local MCP server, but this new one is hosted directly by them so anyone with an Optimizely login can point Claude (or ChatGPT, or Cursor, or whatever) at it and start chatting with their experimentation data. No local servers or API keys needed.&lt;/p&gt;
&lt;h2 class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;Setup&lt;/h2&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;Setup was easy enough, although running `claude mcp add --transport http optimizely-exp &lt;a href=&quot;https://exp.mcp.opal.optimizely.com/mcp&quot;&gt;https://exp.mcp.opal.optimizely.com/mcp&lt;/a&gt;` did not work for me, nor did adding the below to my `claude_desktop_config.json` as &lt;a href=&quot;https://support.optimizely.com/hc/en-us/articles/45321466744205-Install-Optimizely-Experimentation-MCP-server&quot;&gt;instructed here&lt;/a&gt;.&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;optimizely&quot;: {
      &quot;url&quot;: &quot;https://exp.mcp.opal.optimizely.com/mcp&quot;
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;When I launched Claude on Mac I got an &quot;Some MCP servers could not be loaded&quot; error.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;&lt;img src=&quot;/link/5ee261dd5e024499bae10602c117e37f.aspx&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;At least the fix is simple, we can use &lt;a href=&quot;https://www.npmjs.com/package/mcp-remote&quot;&gt;mcp-remote&lt;/a&gt; for now in `claude_desktop_config.json`&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;{
  &quot;mcpServers&quot;: {
    &quot;optimizely&quot;: {
      &quot;command&quot;: &quot;npx&quot;,
      &quot;args&quot;: [
        &quot;-y&quot;,
        &quot;mcp-remote&quot;,
        &quot;https://exp.mcp.opal.optimizely.com/mcp&quot;
      ]
    }
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;After that, when I opened Claude Deskop my browser opened to OAuth with my Optimizely credentials and for me to pick a project to connect the MCP with, done.&lt;/p&gt;
&lt;h2 class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;What can it do?&lt;/h2&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;I started simply with &quot;list my Optimizely projects&quot; and after allowing Claude some actions we got a clean table back.&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;&lt;img src=&quot;/link/af4a5599e44a4f67accb8f842296c9b3.aspx&quot; width=&quot;2064&quot; height=&quot;1161&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;&lt;img src=&quot;/link/b2b9b7a7ecf844b398b50a45843a8c3e.aspx&quot; width=&quot;2064&quot; height=&quot;1161&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;Drilled into my Niteco Sandbox to see all experiments.&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;&lt;img src=&quot;/link/6f68a4d92f5d420bbb66bcb90fb063ba.aspx&quot; width=&quot;2064&quot; height=&quot;1161&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;Drilled further into a running test called &quot;Metrics Setup&quot; to see how it was doing.&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;&lt;img src=&quot;/link/1f38fdde6d184c338517a423bfa561a1.aspx&quot; width=&quot;2064&quot; height=&quot;1161&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;Claude summarised everything into nicely formatted tables and flagged anomalies I had set up for testing. It pointed out that the traffic split was 0% on Original vs 100% on Variation #1 and that two metrics are performing worse than expected.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;&lt;img src=&quot;/link/0e3fd8909c7c423a9883d109ca1a3389.aspx?1777642715952&quot; width=&quot;1952&quot; height=&quot;1098&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;Naturally, the next thing was to fix the broken split. I asked Claude to set it back to 50/50, it pulled the entity template, confirmed what it was about to do, and applied the change.&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;&lt;img src=&quot;/link/487e20b1c3b2481e919f3364b3eb9d89.aspx&quot; width=&quot;1952&quot; height=&quot;1098&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;Then it hit the wall. Changes like these don&#39;t go live until you publish them, and even though Claude &lt;em&gt;said&lt;/em&gt; they were live already, turns out they weren&#39;t.&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;&lt;img src=&quot;/link/b2f016fd60c348eeaeea7c75bd858004.aspx&quot; width=&quot;2208&quot; height=&quot;1242&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;I had it double-check.&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;&lt;img src=&quot;/link/8ba6143bccf44a319dd65444dbfa331b.aspx&quot; width=&quot;2064&quot; height=&quot;1161&quot; /&gt;&lt;/p&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;Seems like for now the MCP is leaning towards the safer side. Let AI read everything and modify the active draft, but not actually do the final click to ship. I can see the logic of this, although hopefully it gets added as a project-level setting to allow AI full control.&lt;/p&gt;
&lt;h2 class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;Conclusion&lt;/h2&gt;
&lt;p class=&quot;font-claude-response-body break-words whitespace-normal leading-[1.7]&quot;&gt;For querying, summarising, and inspecting experiments, the remote MCP server seems great. For making changes, it seems like it will be a huge help as well, but you will need to hop into the UI to click Publish one last time.&amp;nbsp;&lt;br /&gt;&lt;br /&gt;I&#39;m looking forward to adding this into our AI workflows to automate manual tasks like reporting and setting up new variant code quickly while giving Claude all the context it needs to get things done correctly first time.&lt;/p&gt;</id><updated>2026-05-01T13:45:13.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Promoted and Certified</title><link href="https://www.technicaldogsbody.com/blog/promoted-and-certified" /><id>What a busy week</id><updated>2026-05-01T10:30:39.7930000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Announcing new library: SettingsManager</title><link href="https://world.optimizely.com/blogs/Quan-Mai/Dates/2026/4/announcing-new-library-settingsmanager/" /><id>&lt;p&gt;When you run .net app, there have been a few ways to store settings. Those can be set via appSettings.json, or via Azure Portal AppService Configuration. However those setting changes require a restart (or even worse, a re-deployment), which is not always something you&#39;d like nor can affort. To support changing settings on a fly, some of our customers have relied on a content approach - by creating a special page containing the settings as properties - which is a nice way to do it, as you have everything you need - you have a nice UI to set the value, you can set the access rights to who can see the settings and who can change them. The settings also support distributed manner, once you publish the page with new property values, the new values will be seen across the instances.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;But that is not without caveats. Reading settings is usually a very hot path, and if you rely on the content API to get the page then the property you need, you could create a severe bottleneck in your website. At best, it creates a lot of unnecessary allocations. At worst it could create infinite loops when you have multiple threads trying to read and write data to cache.&lt;/p&gt;
&lt;p&gt;To address those problems, I have created a new library at &lt;a href=&quot;https://github.com/vimvq1987/SettingManager&quot;&gt;GitHub - vimvq1987/SettingManager: A setting manager for Optimizely CMS &amp;middot; GitHub&lt;/a&gt; as a proof of concept for how you can leverage Content system for settings while avoid those performance issues. I&#39;ll eventually submit the nuget package to &lt;a href=&quot;https://nuget.optimizely.com&quot;&gt;https://nuget.optimizely.com&lt;/a&gt;, but you can start using the library today (just download and build)&lt;/p&gt;
&lt;p&gt;What you need to do is to define your content type of setting page, which inherits from SettingsPage&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    [ContentType(DisplayName = &quot;Setting page&quot;, GUID = &quot;452d1812-7385-42c3-8073-c1b7481e7b22&quot;, Description = &quot;&quot;, AvailableInEditMode = true)]
    public class MySettingPage : SettingsPage
    {
        public virtual string ASetting { get; set; }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then register your type you want to use with this in your Startup.cs&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddSettingPage&amp;lt;MySettingsPage&amp;gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And then use SettingsManager to get the setting on the fly.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var setting = _settingManager.GetSetting&amp;lt;string&amp;gt;(&quot;ASetting&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A setting page will be create per site definition, and you can get site-specific settings. If no site definition is specified, the current site definition will be used.&lt;/p&gt;
&lt;p&gt;Settings will be cached and will be automatically cleared if you making change to the page (by changing properties and publish). This works across instance.&lt;/p&gt;
&lt;p&gt;As I said this is a pretty much POC, so I&#39;ll be happy to receive comments, suggestions, bug reports or fixes to the repository.&lt;/p&gt;
&lt;p&gt;Happy coding!&lt;/p&gt;</id><updated>2026-04-30T12:45:28.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>From Prompting to Production: Optimizely Opal University Cohort and the Future of Agentic MarTech</title><link href="https://world.optimizely.com/blogs/opti-chronicles/dates/2026/4/from-prompting-to-production-what-the-optimizely-opal-university-cohort-reveals-about-the-future-of-agentic-martech/" /><id>&lt;p class=&quot;MsoNormal&quot;&gt;Most organizations today are still &lt;em&gt;playing&lt;/em&gt; with AI. They experiment with prompts, test ideas in isolated chats, and occasionally automate a task or two. It creates value, but it&amp;rsquo;s inconsistent, difficult to scale, and almost impossible to govern in a meaningful way.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;What the Optimizely Opal University Cohort makes clear is that we&amp;rsquo;re moving beyond that phase. This is no longer about using AI&amp;mdash;it&amp;rsquo;s about operationalizing it.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Over the course of the workshop, the experience wasn&amp;rsquo;t just about building agents. It was about understanding what it actually takes to make AI reliable, reusable, and embedded into the day-to-day workflows of marketing and digital teams. And that distinction matters, because the organizations that figure this out won&amp;rsquo;t just be more efficient&amp;mdash;they&amp;rsquo;ll fundamentally change how work gets done.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;The Real Shift: From Conversations to Systems&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;One of the most important ideas reinforced early in the cohort seems simple on the surface, but it has far-reaching implications once you start applying it in practice:&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Chats are disposable. Agents are systems.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;That shift alone reframes how you think about AI. In most teams today, someone writes a prompt, tweaks it until the output looks acceptable, uses it once, and then repeats the process the next time they need something similar. It works, but it doesn&amp;rsquo;t scale, and more importantly, it doesn&amp;rsquo;t create institutional knowledge.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;With Opal, you&amp;rsquo;re encouraged to step back and ask a different question: instead of solving the problem once, how do you design something that solves it consistently?&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The workshop used a restaurant analogy to explain this, which actually holds up surprisingly well when you think about it more deeply. The prompt becomes your recipe, the instructions are your ingredients, the tools are your kitchen equipment, and evaluations act as your quality control. What you&amp;rsquo;re ultimately producing is not just an answer, but a repeatable outcome that can be delivered again and again with a predictable level of quality .&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;What&amp;rsquo;s often missed in the broader AI conversation is that this isn&amp;rsquo;t really about prompting anymore. It&amp;rsquo;s about system design, and that&amp;rsquo;s where Opal starts to feel meaningfully different.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;The Agent Creation Experience: Fast, Structured, and Intentionally Imperfect&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;One of the more impressive aspects of the workshop is how quickly you can go from idea to working agent. The two-tab workflow&amp;mdash;building in Opal University and then deploying in the Opal platform&amp;mdash;removes a lot of the friction that typically comes with setting these things up.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In practice, this approach can save hours of manual effort, especially when compared to building something similar from scratch . But what stood out wasn&amp;rsquo;t just the speed&amp;mdash;it was the expectation that speed alone isn&amp;rsquo;t the goal.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;There&amp;rsquo;s a consistent message throughout the sessions: getting an agent to work is relatively easy; getting it to work well takes iteration.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;That gap between 80% and 95% quality becomes very real once you start testing outputs. It&amp;rsquo;s where you begin to notice inconsistencies, edge cases, and subtle misalignments with your expectations. And it&amp;rsquo;s also where most of the real work happens.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The workflow itself reinforces good habits. You generate a structured prompt using a dedicated builder, validate the output before committing, export it as JSON, and then bring it into the Opal platform for testing and refinement . It&amp;rsquo;s not just efficient&amp;mdash;it introduces a level of discipline that most teams don&amp;rsquo;t naturally apply when working with AI.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;What Actually Makes Agents Work in Practice&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;As the sessions progressed, a pattern started to emerge. It wasn&amp;rsquo;t any single feature that made agents effective&amp;mdash;it was how a few key components worked together.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Instructions: Where Consistency Lives&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;If prompts define what an agent does, instructions define how it behaves over time.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Opal allows you to establish both instance-wide instructions&amp;mdash;things like brand voice or company guidelines&amp;mdash;and more personal layers that reflect individual preferences. You can even generate these from an existing website, effectively turning your digital presence into a baseline for how your agents communicate .&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This is one of those features that sounds operational, but it has strategic implications. It means you&amp;rsquo;re no longer relying on individuals to remember how to phrase things or maintain consistency across outputs. Instead, that consistency is embedded into the system.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;That said, there&amp;rsquo;s an important caveat. When instructions conflict, outputs can become unpredictable. It&amp;rsquo;s a reminder that governance isn&amp;rsquo;t optional&amp;mdash;it&amp;rsquo;s foundational.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Evaluations: Defining What &amp;ldquo;Good&amp;rdquo; Looks Like&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;If there&amp;rsquo;s one capability that feels underappreciated in most AI discussions, it&amp;rsquo;s evaluation. Not in the abstract sense, but as a structured, repeatable way to define quality.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Opal&amp;rsquo;s approach to evals is both simple and powerful. You link examples of what good output looks like, and the agent uses those examples both to score itself and to guide future responses. Over time, this creates a feedback loop that improves consistency and reliability .&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;What&amp;rsquo;s particularly useful is how this forces teams to be explicit. You can&amp;rsquo;t just say &amp;ldquo;this looks good&amp;rdquo;&amp;mdash;you have to define it. And once you do, you can measure against it.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;In practice, this also introduces nuance. Structured outputs might require higher thresholds&amp;mdash;90% or more&amp;mdash;while creative work needs more flexibility. That balance is something teams will need to learn, but having the mechanism in place is a significant step forward.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Workflow Agents: Where AI Becomes Operational&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;This is where things start to feel less like a feature set and more like a platform.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Workflow agents allow you to connect multiple agents together, passing outputs from one to the next and triggering them based on real-world events. You can initiate workflows through chat, webhooks, email, or scheduled runs, which opens up a wide range of possibilities .&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;What makes this particularly compelling is how it mirrors actual business processes. Instead of thinking about isolated tasks, you start thinking about sequences&amp;mdash;how information flows, how decisions are made, and where automation can meaningfully reduce effort.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The newsletter-to-LinkedIn example from the workshop illustrates this well. An incoming email triggers a workflow, which transforms the content, applies formatting improvements, and prepares it for distribution. It&amp;rsquo;s a relatively simple use case, but it captures the essence of what&amp;rsquo;s possible when you move beyond single-agent interactions .&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Reusability Through Variables&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Another detail that becomes increasingly important at scale is the use of variables.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;By parameterizing inputs&amp;mdash;things like URLs, languages, or datasets&amp;mdash;you can reuse the same agent across different contexts without rebuilding it from scratch. This might seem like a small feature, but it&amp;rsquo;s what turns agents into reusable assets rather than one-off solutions.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;The Use Cases That Actually Matter&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;What made the workshop particularly valuable was seeing how these capabilities translate into real work.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Some use cases were more obvious, like competitive analysis or lead generation, but others highlighted where agents can quietly drive significant value.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;For example, transforming meeting notes into structured user stories is not glamorous, but it&amp;rsquo;s incredibly useful. It reduces manual effort, ensures consistency, and accelerates downstream work. Similarly, automating reporting workflows or translating strategic goals into measurable KPIs addresses very real operational bottlenecks.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;More forward-looking use cases, like AEO and GEO optimization, point to where the industry is heading. As AI-driven search becomes more prevalent, understanding how brands appear in those environments&amp;mdash;and how to improve that presence&amp;mdash;will become a critical capability. Agents are particularly well-suited to this kind of analysis because they can combine research, evaluation, and recommendation into a single workflow.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;What&amp;rsquo;s Actually Impressive (And What&amp;rsquo;s Not)&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;It&amp;rsquo;s easy to get caught up in features, but what stood out here was less about what Opal can do and more about how it encourages teams to think.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;There&amp;rsquo;s a clear emphasis on iteration over perfection, which aligns with how real teams operate. There&amp;rsquo;s also a deliberate separation between different components&amp;mdash;creation, instructions, evaluations&amp;mdash;which reduces complexity as usage grows.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;At the same time, it&amp;rsquo;s important to recognize that this isn&amp;rsquo;t a fully abstracted experience. You still need to think about how agents interact, how outputs are structured, and how workflows are designed. In other words, the platform gives you the building blocks, but it doesn&amp;rsquo;t remove the need for 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;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Implementation Realities: Where Things Get Hard&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;If there&amp;rsquo;s one consistent theme that emerged, it&amp;rsquo;s that technology is only part of the equation.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;From a people perspective, someone needs to take ownership of agent design and governance. Without that, it&amp;rsquo;s easy for things to become fragmented or inconsistent.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Process-wise, teams need to define when to use agents versus chats, how to evaluate outputs, and how to maintain and improve what they&amp;rsquo;ve built. These aren&amp;rsquo;t decisions that can be deferred&amp;mdash;they shape how effective the system becomes over time.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;On the technical side, integration and orchestration introduce their own challenges. Even something as straightforward as email triggers can have limitations that require workarounds, as seen during the workshop .&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;And then there&amp;rsquo;s governance. If agents are going to play a meaningful role in operations, there needs to be visibility into how they&amp;rsquo;re performing, control over what data they access, and clear accountability for their outputs.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;The Bigger Picture: Why This Matters Now&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;What the Opal University Cohort ultimately highlights is not just a set of capabilities, but a shift in how AI fits into the MarTech ecosystem.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;We&amp;rsquo;re moving from a world where AI is something you occasionally use, to one where it becomes part of how work gets done. That shift requires new ways of thinking about design, quality, and governance.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The organizations that adapt will find themselves operating differently. They&amp;rsquo;ll move faster, not just because they&amp;rsquo;re more efficient, but because they&amp;rsquo;ve reduced the friction between idea and execution. They&amp;rsquo;ll also be more consistent, because their processes are embedded into the systems they use.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;And perhaps most importantly, they&amp;rsquo;ll be better positioned to adapt as the technology continues to evolve.&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;strong&gt;Final Thoughts&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;The experience of going through the Opal University Cohort makes one thing clear: the future of AI in marketing and digital experience is not about better prompts. It&amp;rsquo;s about better systems.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Opal is not trying to replace how teams work&amp;mdash;it&amp;rsquo;s trying to reshape it in a way that makes AI usable at scale. That&amp;rsquo;s a much harder problem to solve, but it&amp;rsquo;s also the one that matters.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;For teams willing to invest the time to understand and apply these concepts, the payoff is not just incremental improvement. It&amp;rsquo;s a fundamentally different way of operating&amp;mdash;one where AI is no longer an experiment, but an integral part of the organization&amp;rsquo;s capability.&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;Take this opportunity and join the waitlist to be a part of a Cohort: https://www.optimizely.com/ai-marketing-certificate/&lt;/p&gt;
&lt;div class=&quot;MsoNormal&quot; style=&quot;text-align: center;&quot; align=&quot;center&quot;&gt;&amp;nbsp;&lt;/div&gt;</id><updated>2026-04-28T16:59:46.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Six Compelling Reasons for Upgrading to CMS 13</title><link href="https://world.optimizely.com/blogs/muhammad-talha/dates/2026/4/six-compelling-reasons-for-upgrading-to-cms-13/" /><id>&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;Most software updates ask you to keep up. Optimizely CMS 13 asks something different &amp;mdash; it asks whether your digital strategy is built for a world that has already moved on. If your team is still running on CMS 11 or CMS 12, this is not a nudge. It is a wake-up call. CMS 13 is not a patch, not a feature drop, and not the kind of release you can park on a roadmap until next year without consequence. It is a fundamental repositioning of the entire platform around the three forces actively redrawing the map of digital marketing: artificial intelligence, headless content delivery, and AI-powered search.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;This article lays out a clear-eyed case for why upgrading to CMS 13 is a strategically sound decision for digital and IT leaders in 2026 &amp;mdash; and what your teams can realistically expect to gain on the other side.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;line-height: 107%;&quot;&gt;1. Your Content Editors Will Work Dramatically Faster&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-size: 12pt; line-height: 107%; font-family: verdana, geneva, sans-serif;&quot;&gt;The most visible change for day-to-day users is Visual Builder &amp;mdash; a unified interface that replaces the legacy on-page editor and brings pages, blocks, experiences, media assets, and content variations into one place. Autosave eliminates lost work, synchronised side-by-side preview shows editors exactly what their audience will see before publishing, and Blueprint templates let teams standardise page structures and launch new content without starting from scratch. The productivity gains are measurable: Optimizely&#39;s 2025 benchmarking data recorded a reduction of more than 50% in campaign delivery time from brief to publication &amp;mdash; translating directly into lower cost-per-campaign and the ability to act on market moments that would previously have been missed.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;line-height: 107%;&quot;&gt;2. AI Is No Longer an Add-On &amp;mdash; It Is the Editorial Workflow&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;Opal, Optimizely&#39;s AI agent platform, is embedded directly into CMS 13 &amp;mdash; not as a&lt;span style=&quot;mso-ansi-language: EN-GB;&quot;&gt;n&lt;/span&gt; &lt;span style=&quot;mso-ansi-language: EN-GB;&quot;&gt;a&lt;/span&gt;dd-on integration but as a native layer within the content graph. Opal agents can draft and publish content from brand guidelines, run content audits, generate metadata and alt text at scale, assist with content modelling, and orchestrate complex workflows across more than 28 purpose-built agent types.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-size: 12pt; line-height: 107%; font-family: verdana, geneva, sans-serif;&quot;&gt;The Instructions feature lets teams encode brand voice, compliance requirements, and regional tone variations once &amp;mdash; so every piece of AI-assisted content reflects those standards automatically, without manual review.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;line-height: 107%;&quot;&gt;3. Experimentation at a Scale That Was Previously Impractical&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;One of the persistent frustrations with traditional A/B testing is that it requires traffic volume, manual configuration, and significant editorial time to define audience segments and content variations. Many organisations never fully realise the value of experimentation because the overhead makes it impractical at scale. CMS 13 addresses this through two connected capabilities.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpFirst&quot; style=&quot;text-indent: -18.0pt; mso-list: l0 level1 lfo1;&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-ascii-font-family: Calibri; mso-fareast-font-family: Calibri; mso-hansi-font-family: Calibri; mso-bidi-font-family: Calibri;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;-&lt;span style=&quot;font-style: normal; font-variant: normal; font-size-adjust: none; font-language-override: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-weight: normal; font-stretch: normal; line-height: normal;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;strong&gt;Content Variations&lt;/strong&gt; are built in natively, letting editors maintain multiple published versions of the same content item &amp;mdash; each with its own version history &amp;mdash; while storing only the properties that differ from the original. Any variation can be promoted to the primary version when performance data supports it.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoListParagraphCxSpLast&quot; style=&quot;text-indent: -18.0pt; mso-list: l0 level1 lfo1;&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;&lt;!-- [if !supportLists]--&gt;&lt;span style=&quot;mso-ascii-font-family: Calibri; mso-fareast-font-family: Calibri; mso-hansi-font-family: Calibri; mso-bidi-font-family: Calibri;&quot;&gt;&lt;span style=&quot;mso-list: Ignore;&quot;&gt;-&lt;span style=&quot;font-style: normal; font-variant: normal; font-size-adjust: none; font-language-override: normal; font-kerning: auto; font-optical-sizing: auto; font-feature-settings: normal; font-variation-settings: normal; font-weight: normal; font-stretch: normal; line-height: normal;&quot;&gt;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;!--[endif]--&gt;&lt;strong&gt;Contextual personalisation&lt;/strong&gt; rather than requiring manual segment definition, its machine learning model observes real-time visitor signals and automatically surfaces the most relevant experience for each user, learning continuously without ongoing configuration. The result: organisations using Opal alongside CMS 13&#39;s experimentation infrastructure recorded close to an 60% increase in experiments run&lt;span style=&quot;mso-ansi-language: EN-GB;&quot;&gt;,&lt;/span&gt; and better decisions follow when experimentation is this easy to execute.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;line-height: 107%;&quot;&gt;4. Your Content Will Be Discoverable in AI Search &amp;mdash; Not Just Google&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;Search behaviour has shifted. Users are increasingly finding information through AI-powered answer engines &amp;mdash; ChatGPT, Google&#39;s AI Overviews, Perplexity &amp;mdash; which interpret content semantically and surface answers based on clarity and authority, not keyword density or backlinks. Traditional SEO is no longer sufficient; Generative Engine Optimisation (GEO) &amp;mdash; structuring content so AI systems can reliably parse, trust, and reference it &amp;mdash; is the discipline that now matters.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-size: 12pt; line-height: 107%; font-family: verdana, geneva, sans-serif;&quot;&gt;CMS 13 makes GEO a native capability. Optimizely Graph indexes all content semantically &amp;mdash; making it inherently more readable to AI systems than content in conventional databases &amp;mdash; and the Opal GEO Recommendations agent audits individual pages for LLM discoverability and produces prioritised recommendations to improve visibility across major AI platforms. For organisations that have invested in content marketing, this is a measurable competitive advantage: competitors on CMS 11 or CMS 12 are simply not visible in this channel, while CMS 13 teams can treat AI discoverability as an optimisable marketing channel most of the market has yet to activate.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;line-height: 107%;&quot;&gt;5. The Financial Case Is Clearer Than It Appears&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;The upgrade case is stronger than it first appears. Staying on legacy infrastructure carries its own costs &amp;mdash; in maintenance, security exposure, lost productivity, and features you simply cannot access. On the migration itself, automated tooling delivers an estimated 50% reduction in migration cost for a mid-scale project; campaign delivery times drop by approx. more than 50% with Opal integrated into editorial workflows; and experimentation velocity increases by close to 60% with CMS 13&#39;s native variation infrastructure &amp;mdash; all of which reduce&lt;span style=&quot;mso-ansi-language: EN-GB;&quot;&gt;s&lt;/span&gt; cost-per-campaign and improve&lt;span style=&quot;mso-ansi-language: EN-GB;&quot;&gt;s&lt;/span&gt; conversion outcomes without adding headcount.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-size: 12pt; line-height: 107%; font-family: verdana, geneva, sans-serif;&quot;&gt;Optimizely Graph and Opti ID are also bundled in the CMS 13 license, and the new architecture replaces Search &amp;amp; Navigation entirely, so organisations previously paying for it separately should factor that saving into their cost comparison.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&amp;nbsp;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;&lt;strong&gt;&lt;span style=&quot;line-height: 107%;&quot;&gt;6. You Are Securing the Platform&#39;s Future Innovation Path&lt;/span&gt;&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-size: 12pt; line-height: 107%; font-family: verdana, geneva, sans-serif;&quot;&gt;Every major feature Optimizely ships from this point forward is built on the CMS 13 and Graph architecture. The Opal agent library, GEO improvements, new personalisation capabilities&lt;span style=&quot;line-height: 107%;&quot;&gt; and&lt;/span&gt; multi-agent workflow orchestration &amp;mdash; none of these will be backported to CMS 12 or CMS 11.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-size: 12pt; line-height: 107%; font-family: verdana, geneva, sans-serif;&quot;&gt;&lt;span style=&quot;line-height: 107%;&quot;&gt;The l&lt;/span&gt;onger an upgrade is deferred, the larger the capability gap becomes, and &lt;span style=&quot;line-height: 107%;&quot;&gt;the &lt;/span&gt;more complex &lt;span style=&quot;line-height: 107%;&quot;&gt;the &lt;/span&gt;eventual migration. Organisations that upgrade now are positioned to adopt each successive improvement incrementally. Organisations that wait face a consolidating backlog of changes to absorb simultaneously.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-family: verdana, geneva, sans-serif; font-size: 12pt;&quot;&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;&lt;span style=&quot;font-size: 12pt; line-height: 107%; font-family: verdana, geneva, sans-serif;&quot;&gt;Optimizely CMS 13 is not a routine version update. It is the point at which the platform becomes AI-native &amp;mdash; where content is structured for machine comprehension, where editorial workflows are accelerated by agents rather than just assisted by tools, and where experimentation and personalisation operate at a scale that was previously &lt;span style=&quot;line-height: 107%;&quot;&gt;reserved &lt;/span&gt;for organisations with large, dedicated teams.&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;MsoNormal&quot;&gt;* Ref &lt;span style=&quot;font-size: 11.0pt; line-height: 107%; font-family: &#39;Calibri&#39;,sans-serif; mso-ascii-theme-font: minor-latin; mso-fareast-font-family: Calibri; mso-fareast-theme-font: minor-latin; mso-hansi-theme-font: minor-latin; mso-bidi-font-family: Arial; mso-bidi-theme-font: minor-bidi; mso-ansi-language: #0C00; mso-fareast-language: EN-US; mso-bidi-language: AR-SA;&quot;&gt;Sources: Optimizely CMS 13 GA release notes (April 2026), Optimizely Opal AI Benchmark Report (2025), Optimizely Gartner Magic Quadrant (2025)*&lt;/span&gt;&lt;/p&gt;</id><updated>2026-04-28T12:14:33.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Optimizely CMS 13 breaking changes: GetContentTypePropertyDisplayName</title><link href="https://www.gulla.net/en/blog/optimizely-cms-13-breaking-changes-getcontenttypepropertydisplayname/" /><id>When upgrading from CMS 12 to 13, resolving property display names may not work as before. Here’s what changed.</id><updated>2026-04-27T14:52:29.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Accelerate Optimizely DAM Adoption: Unlocking Business Value with Metadata Bulk Import</title><link href="https://world.optimizely.com/blogs/vaibhav/dates/2026/4/accelerating-optimizely-dam-adoption/" /><id>&lt;h1&gt;&lt;img src=&quot;/link/353c6c4812c64850897f5b2b7c50164f.aspx&quot; alt=&quot;&quot; width=&quot;979&quot; height=&quot;448&quot; /&gt;&lt;br /&gt;Accelerating Optimizely DAM Adoption&lt;/h1&gt;
&lt;h2&gt;How a Metadata-Driven Bulk Import Utility Unlocks Real Business Value&lt;/h2&gt;
&lt;h3&gt;Executive Summary&lt;/h3&gt;
&lt;p&gt;For enterprises running Optimizely CMS 12 or 13, Digital Asset Management (DAM) is no longer optional; it is the strategic backbone of content operations. Yet the single biggest obstacle to DAM adoption is not technology; it is the sheer friction of getting thousands of existing assets off shared drives and into a governed, metadata-enriched repository.&lt;/p&gt;
&lt;p&gt;The &lt;strong&gt;ImportAssetToOptiDam&lt;/strong&gt; NuGet utility directly eliminates that friction. Built on .NET 8 and integrated with the Optimizely CMP API, it transforms a simple Excel spreadsheet and a folder of images into a fully tagged, SEO-enriched, governance-ready DAM library, automatically, overnight if required.&lt;/p&gt;
&lt;h4&gt;Why this matters to leadership&lt;/h4&gt;
&lt;p&gt;Every day, assets sit outside the DAM, your teams duplicate effort, miss SEO opportunities, and expose the business to brand and compliance risk. This utility compresses a weeks-long DAM migration into hours.&lt;/p&gt;
&lt;h3&gt;The Business Problem: DAM Adoption Stalls at the Front Door&lt;/h3&gt;
&lt;p&gt;In virtually every Optimizely enterprise engagement, the pattern is the same. The platform is configured, the taxonomy is designed, the workflows are approved&amp;mdash;and then momentum halts. Marketing teams are sitting on thousands of product images structured in a spreadsheet, and the only path to get them into the DAM is manual, one-by-one UI uploads.&lt;/p&gt;
&lt;p&gt;The downstream cost is substantial:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Editor productivity consumed by asset housekeeping instead of content creation&lt;/li&gt;
&lt;li&gt;Inconsistent metadata and tags undermining search and personalization engines&lt;/li&gt;
&lt;li&gt;CMS pages pointing to unmanaged file shares, creating governance blind spots&lt;/li&gt;
&lt;li&gt;SEO performance degraded by missing alt-text and uncategorized assets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For a CTO or Senior Architect, this is an integration gap, not a training problem. The solution is a reliable, repeatable, automated ingestion pipeline&amp;mdash;exactly what this utility provides.&lt;/p&gt;
&lt;h3&gt;What the Utility Does: A Five-Step Pipeline&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Read Excel&lt;/strong&gt; &amp;mdash; Parses each row for asset metadata: title, description, alt text, tags, and custom DAM fields&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Match Files&lt;/strong&gt; &amp;mdash; Maps each row to the corresponding image in the local Images folder&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Authenticate&lt;/strong&gt; &amp;mdash; Obtains an OAuth 2.0 token from Optimizely CMP using Client ID and Client Secret&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Upload &amp;amp; Enrich&lt;/strong&gt; &amp;mdash; Pushes the binary to DAM and immediately applies all structured metadata&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Report&lt;/strong&gt; &amp;mdash; Writes an output Excel containing the published DAM URL for every asset&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Architectural Value: Why This Is the Right Design&lt;/h3&gt;
&lt;h4&gt;Decoupled Ingestion Architecture&lt;/h4&gt;
&lt;p&gt;From an enterprise architecture standpoint, the utility enforces a clean separation of concerns that makes it extensible and platform-agnostic. The Excel sheet acts as the control plane, the Images folder is the binary payload, and the Optimizely CMP API is the integration boundary.&lt;/p&gt;
&lt;h4&gt;Metadata-First: SEO and Governance by Design&lt;/h4&gt;
&lt;p&gt;Assets are not just uploaded&amp;mdash;they arrive in the DAM already enriched. Every image carries structured attributes, alt text, tags, and custom field values defined in the Excel template before a single API call is made.&lt;/p&gt;
&lt;h4&gt;OAuth 2.0 Security &amp;mdash; No Human in the Loop&lt;/h4&gt;
&lt;p&gt;The utility integrates directly with the Optimizely CMP OAuth 2.0 token endpoint. No user session is required, no browser interaction, no shared credentials. The application authenticates using Client ID and Client Secret, making it suitable for unattended batch execution or CI/CD pipelines.&lt;/p&gt;
&lt;h3&gt;Getting Started: Five Minutes to First Import&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;NuGet Package:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.nuget.org/packages/ImportAssetToOptiDam&quot;&gt; https://www.nuget.org/packages/ImportAssetToOptiDam &lt;/a&gt;&lt;br /&gt;Version 1.0.0 | Targets .NET 8.0+&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Installation Steps:&lt;/strong&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Install the package:&lt;br /&gt;&lt;code&gt;dotnet add package ImportAssetToOptiDam --version 1.0.0&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Configure &lt;code&gt;appsettings.json&lt;/code&gt; with CMP BaseUrl, ClientId, and ClientSecret&lt;/li&gt;
&lt;li&gt;Place the Excel file in&amp;nbsp;&lt;code&gt;ExcelSheet&lt;/code&gt; folder and images in &lt;code&gt;Images&lt;/code&gt; folder, then run the console app&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The output Excel (in the Output folder) contains published DAM URLs for all assets&amp;mdash;ready for CMS or downstream systems.&lt;/p&gt;
&lt;div style=&quot;border-left: 4px solid orange; padding: 10px; background: #fff8e1;&quot;&gt;&lt;strong&gt;⚠ Beta Release &amp;mdash; Validate in Lower Environments&lt;/strong&gt;
&lt;p&gt;ImportAssetToOptiDam is currently in Beta. Validate in DEV and UAT environments before production use. Verify metadata mapping, duplicate handling, and file mismatches against your DAM taxonomy.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;Strategic Fit: Where This Accelerates Your Roadmap&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;CMS 11 to CMS 12/13 migration &amp;mdash; bulk migration with enriched metadata&lt;/li&gt;
&lt;li&gt;DAM onboarding &amp;mdash; reduces weeks of manual effort&lt;/li&gt;
&lt;li&gt;Commerce asset refresh &amp;mdash; sync seasonal catalogs efficiently&lt;/li&gt;
&lt;li&gt;Partner ingestion &amp;mdash; external teams can contribute without CMP UI access&lt;/li&gt;
&lt;li&gt;Headless DXP &amp;mdash; generates reusable DAM URLs for any frontend&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Start your DAM adoption journey today:&lt;/strong&gt;&lt;br /&gt;&lt;a href=&quot;https://www.nuget.org/packages/ImportAssetToOptiDam&quot;&gt; https://www.nuget.org/packages/ImportAssetToOptiDam &lt;/a&gt;&lt;/p&gt;</id><updated>2026-04-27T14:37:29.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Optimizely CMS 13 breaking changes: IValidate&lt;T&gt;</title><link href="https://www.gulla.net/en/blog/optimizely-cms-13-breaking-changes-ivalidate/" /><id>Custom IValidate&lt;t&gt; validators in Optimizely CMS 13 are no longer auto-discovered. They must be registered explicitly when upgrading from CMS 12.&lt;/t&gt;</id><updated>2026-04-27T14:30:57.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Convert Blocks in Optimizely CMS: Now Supporting CMS 12 and CMS 13</title><link href="https://www.gulla.net/en/blog/convert-blocks-in-optimizely-cms-now-supporting-cms-12-and-cms-13/" /><id></id><updated>2026-04-24T13:31:11.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Optimizely migration from CMS 12 to CMS 13</title><link href="https://world.optimizely.com/blogs/sanjay-katiyar/dates/2026/4/optimizely-migration-from-cms-12-to-cms-13/" /><id>&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Upgrading from Optimizely CMS 12 to CMS 13 alongside moving the runtime from .NET 8.0 to .NET 10.0 is far more than a routine version upgrade. It is an opportunity to rethink how content is structured, queried, and delivered across modern digital experiences.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;In this article we treat &lt;strong&gt;one search-heavy CMS 12 solution&lt;/strong&gt; as a &lt;strong&gt;real-world worked example&lt;/strong&gt;: a long-lived codebase, mixed-era NuGet references, extensive &lt;strong&gt;Search &amp;amp; Navigation (Find)&lt;/strong&gt; usage for listings and site search, and editorial features that depended on familiar CMS 12 APIs. The upgrade branch had to compile on &lt;strong&gt;.NET 10&lt;/strong&gt;, run on &lt;strong&gt;CMS 13&lt;/strong&gt;, and &lt;strong&gt;remove Find&lt;/strong&gt; in favor of &lt;strong&gt;Optimizely Graph&lt;/strong&gt; (Content Graph) while preserving UX parity for full search, listing pages, and prompt-style autocomplete.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;We share the &lt;strong&gt;technical decisions, challenges, and improvements&lt;/strong&gt; that showed up in an actual &lt;strong&gt;old-vs-new diff&lt;/strong&gt; across services, controllers, initialization, and UI metadata not a theoretical checklist. A key outcome was a&amp;nbsp;&lt;strong&gt;single graph-first query pipeline&lt;/strong&gt; for search, listings, and prompts, instead of three slightly different Find call paths that had diverged over years.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;This guide is aimed at developers and architects who want a &lt;strong&gt;strategic, diff-grounded&lt;/strong&gt; picture of what &amp;ldquo;CMS 12 &amp;rarr; 13 + .NET 10 + Find &amp;rarr; Graph&amp;rdquo; looks like in practice, &lt;strong&gt;alongside&lt;/strong&gt; Optimizely&amp;rsquo;s official upgrade sequence.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Official baseline:&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/upgrade-to-cms-13&quot;&gt;Upgrade to CMS 13 from CMS 12&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/breaking-changes-in-cms-13&quot;&gt;Breaking changes in CMS 13&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/api-replacement-map&quot;&gt;API replacement map&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;How to read this as a real-world migration story&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;The following is a &lt;strong&gt;structured case study&lt;/strong&gt; derived from a representative upgrade branch. It is &lt;strong&gt;not&lt;/strong&gt; a substitute for reading Optimizely&amp;rsquo;s upgrade doc end to end; it answers the question: &lt;em&gt;&amp;ldquo;What actually changed in code when a typical Find-heavy site moved?&amp;rdquo;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;tableView-content-wrap&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;pm-table-resizer-container&quot;&gt;
&lt;div class=&quot;resizer-item display-handle&quot;&gt;
&lt;div class=&quot;pm-table-container&quot;&gt;
&lt;div class=&quot;pm-table-sticky-sentinel-top&quot;&gt;
&lt;div class=&quot;&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Phases that matched how the work unfolded&lt;/span&gt;&lt;/h3&gt;
&lt;ol class=&quot;ak-ol&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Audit and inventory&lt;/strong&gt; - NuGet graph, Find usage map (full search vs listing vs autocomplete), &lt;span class=&quot;code&quot;&gt;ServiceLocator&lt;/span&gt; and &lt;span class=&quot;code&quot;&gt;InitializeModule&lt;/span&gt; hotspots, third-party add-ons.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Framework and packages&lt;/strong&gt; -&lt;span class=&quot;code&quot;&gt;TargetFramework&lt;/span&gt; &amp;rarr; &lt;span class=&quot;code&quot;&gt;net10.0&lt;/span&gt;, bump Optimizely packages, fix restore errors (NU1202 / NU1608), restore &lt;strong&gt;transitive&lt;/strong&gt; dependencies after removing Find (for example &lt;strong&gt;Newtonsoft.Json&lt;/strong&gt; if still required).&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Compile-time modernization&lt;/strong&gt; -DI, &lt;span class=&quot;code&quot;&gt;ContentReference&lt;/span&gt;, routing helpers, &lt;span class=&quot;code&quot;&gt;SaveAction&lt;/span&gt;, metadata extenders, scheduled jobs, shell controllers.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Find &amp;rarr; Graph&lt;/strong&gt; - Introduce shared query builder; migrate entry points one by one; compare totals and ordering; add explicit paging and cache options.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Stabilization&lt;/strong&gt; - Admin URL and host changes, applications model verification, content area rendering regression passes, production-like content volume tests.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;What the official upgrade guide adds (planning reality)&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;These points from Optimizely&amp;rsquo;s upgrade article &lt;strong&gt;directly affected&lt;/strong&gt; the same kind of project:&lt;/span&gt;&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;span class=&quot;code&quot;&gt;.NET 10+&lt;/span&gt; is mandatory for CMS 13; expect &lt;strong&gt;no build&lt;/strong&gt; until packages match the new TFM.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Resolve &lt;/strong&gt;&lt;span class=&quot;code&quot;&gt;[Obsolete]&lt;/span&gt; on CMS 12 before the jump; they become &lt;strong&gt;hard errors&lt;/strong&gt; in CMS 13.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Graph schema&lt;/strong&gt; can break between CMS 12 and 13 for teams already on Graph; plan frontends and &lt;strong&gt;project migration&lt;/strong&gt; on DXP if applicable (&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/cms-13-and-12-graph-comparison&quot;&gt;Graph comparison&lt;/a&gt;, &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/project-migration-for-cms-12-with-optimizely-graph&quot;&gt;project migration&lt;/a&gt;).&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Dynamic properties, mirroring, legacy plugin system&lt;/strong&gt; are &lt;strong&gt;removed&lt;/strong&gt; - search the codebase for &lt;span class=&quot;code&quot;&gt;EPiServer.Core.DynamicProperty*&lt;/span&gt;, &lt;span class=&quot;code&quot;&gt;EPiServer.PlugIn&lt;/span&gt;, mirroring transfer types.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;DAM&lt;/strong&gt; asset migration may need to wait for dedicated CMS 13 tools; other upgrade work can proceed in parallel per current docs.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Why move to CMS 13&lt;/span&gt;&lt;/h2&gt;
&lt;ol class=&quot;ak-ol&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Better long-term maintainability&lt;/strong&gt; - CMS 13 encourages dependency injection, modern APIs, and strongly typed query patterns. That reduces glue code and makes search behavior easier to reason about.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Unified query composition&lt;/strong&gt; - A graph-first approach supports one pipeline for &lt;strong&gt;full search&lt;/strong&gt;, &lt;strong&gt;listing search&lt;/strong&gt;, &lt;strong&gt;autocomplete / prompt search&lt;/strong&gt;, and &lt;strong&gt;filter / facet&lt;/strong&gt; generation.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;More predictable filtering and sorting &lt;/strong&gt;- One composed query flow keeps &lt;strong&gt;global search&lt;/strong&gt;, &lt;strong&gt;listing pages&lt;/strong&gt;, and &lt;strong&gt;prompts&lt;/strong&gt; from drifting apart.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Better scalability options&lt;/strong&gt; - Explicit &lt;strong&gt;paging&lt;/strong&gt; and &lt;strong&gt;bounded&lt;/strong&gt; retrieval make performance characteristics easier to reason about as content volume grows.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Future-ready platform alignment&lt;/strong&gt; - Aligns with Optimizely&amp;rsquo;s current direction and reduces later upgrade risk.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Why this migration matters and what to target&lt;/span&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Why migration is needed&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Legacy search code paths grow complex over time.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Prompt search and full search &lt;strong&gt;drift&lt;/strong&gt; in behavior.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Filter and facet &lt;strong&gt;parity&lt;/strong&gt; issues are painful to debug.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Large content trees need &lt;strong&gt;stable subtree scoping&lt;/strong&gt; and predictable listing queries.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Migration goals for engineering teams&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Define success &lt;strong&gt;before&lt;/strong&gt; rewriting queries:&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Behavior parity&lt;/strong&gt; &amp;ndash; Ensure the existing search UX does not regress&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Single pipeline&lt;/strong&gt; &amp;ndash; Use one composable query model for search, listing, and prompt&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stable scoping&lt;/strong&gt; &amp;ndash; Maintain reliable subtree scoping for navigation-heavy structures&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Performance safety&lt;/strong&gt; &amp;ndash; Apply explicit paging and bounded query windows&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Extensibility&lt;/strong&gt; &amp;ndash; Enable new filters and sorting within a shared composition layer&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Old vs new: concrete differences from the migration diff&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Below is a &lt;strong&gt;practical comparison&lt;/strong&gt; taken from the most important changes applied &lt;strong&gt;across the codebase&lt;/strong&gt; in this example upgrade. Together they move the solution from a &lt;strong&gt;page-and-service-locator&lt;/strong&gt; style to a &lt;strong&gt;content-first, DI-first, graph-based&lt;/strong&gt; CMS 13 architecture.&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;1. NuGet package modernization&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Legacy and mixed-era references were cleaned up.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;ASP.NET Core friendly&amp;nbsp;&lt;strong&gt;CMS 13&lt;/strong&gt; packages were added or updated.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Supporting packages were reviewed and partially aligned.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Already upgraded or aligned on the migration branch:&lt;/strong&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;tableView-content-wrap&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;pm-table-resizer-container&quot;&gt;
&lt;div class=&quot;resizer-item display-handle&quot;&gt;
&lt;div class=&quot;pm-table-container&quot;&gt;
&lt;div class=&quot;pm-table-wrapper&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;EPPlus&lt;/strong&gt; upgraded to version &lt;strong&gt;8.5.3&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;AdaptiveImages&lt;/strong&gt; upgraded to &lt;strong&gt;2.0.15.2-preview&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Jhoose.Security.Admin&lt;/strong&gt; upgraded to &lt;strong&gt;Jhoose.Security.Admin13 v3.1.0.10&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Stott.Optimizely.RobotsHandler&lt;/strong&gt; upgraded to &lt;strong&gt;7.0.0&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;div class=&quot;pm-table-sticky-sentinel-bottom&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Pending compatibility validation&lt;/strong&gt; (treat as follow-up before production):&lt;/span&gt;&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span class=&quot;code&quot; style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Geta.NotFoundHandler.*&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span class=&quot;code&quot; style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Geta.Optimizely.*&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Optimizely&amp;rsquo;s upgrade guide also calls out packages such as &lt;span class=&quot;code&quot;&gt;Geta.NotFoundHandler.Optimizely&lt;/span&gt;, &lt;span class=&quot;code&quot;&gt;Geta.Optimizely.Sitemaps&lt;/span&gt;, &lt;span class=&quot;code&quot;&gt;Geta.Optimizely.GenericLinks&lt;/span&gt;, &lt;span class=&quot;code&quot;&gt;Geta.Optimizely.ContentTypeIcons&lt;/span&gt;, and &lt;span class=&quot;code&quot;&gt;Advanced.CMS.AdvancedReviews&lt;/span&gt; as commonly problematic see &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/optimizely-third-party-packages-breaking-changes&quot;&gt;Optimizely and third-party package breaking changes&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;2. Search engine migration (Find to Content Graph)&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;span class=&quot;code&quot;&gt;EpiServer.Find&lt;/span&gt; is not supported in CMS 13. In this migration:&lt;/span&gt;&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;span class=&quot;code&quot;&gt;FindClient.Instance.Search&amp;lt;T&amp;gt;()&lt;/span&gt; (and similar) pipelines were &lt;strong&gt;removed&lt;/strong&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;New queries start from &lt;span class=&quot;code&quot;&gt;_graphContentClient.QueryContent&amp;lt;T&amp;gt;()&lt;/span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Composition uses &lt;span class=&quot;code&quot;&gt;.AsCurrentUser()&lt;/span&gt;, &lt;span class=&quot;code&quot;&gt;.SetLocale(...)&lt;/span&gt;, &lt;span class=&quot;code&quot;&gt;.WithDisplayFilters()&lt;/span&gt;, &lt;span class=&quot;code&quot;&gt;.WithCacheOptions(...)&lt;/span&gt;, and &lt;strong&gt;async&lt;/strong&gt; execution (&lt;span class=&quot;code&quot;&gt;GetContentAsync&lt;/span&gt; / &lt;span class=&quot;code&quot;&gt;GetAsContentAsync&lt;/span&gt;).&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Listing-style helpers that used Find with &lt;span class=&quot;code&quot;&gt;Ancestors()&lt;/span&gt; and &lt;span class=&quot;code&quot;&gt;StaticallyCacheFor(...)&lt;/span&gt; became &lt;strong&gt;async&lt;/strong&gt;: resolve a normalized site path from the start or root page URL, filter with &lt;span class=&quot;code&quot;&gt;RelativePath.StartsWith(rootPath)&lt;/span&gt;, &lt;span class=&quot;code&quot;&gt;Limit(...)&lt;/span&gt;, then &lt;span class=&quot;code&quot;&gt;await ...GetAsContentAsync().ConfigureAwait(false)&lt;/span&gt; and map or cast; &lt;strong&gt;in-memory ordering&lt;/strong&gt; (for example &lt;span class=&quot;code&quot;&gt;SortIndex&lt;/span&gt; then name) followed where Graph ordering did not match legacy search.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Further reading:&lt;/span&gt;&lt;/p&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/platform-optimizely/docs/how-to-migrate-sn-to-content-graph&quot;&gt;Migrate Search &amp;amp; Navigation to Optimizely Graph&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/migrate-alloy-12-to-13&quot;&gt;Migrate an Alloy site from CMS 12 to CMS 13&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/get-started-with-optimizely-graph-for-cms-13&quot;&gt;Get started with Optimizely Graph for CMS 13&lt;/a&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;3. Routing and context helper migration&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;span class=&quot;code&quot;&gt;IPageRouteHelper&lt;/span&gt; / &lt;span class=&quot;code&quot;&gt;PageRouteHelper&lt;/span&gt; usage moved toward &lt;span class=&quot;code&quot;&gt;IContentRouteHelper&lt;/span&gt; / &lt;span class=&quot;code&quot;&gt;ContentRouteHelper&lt;/span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Note:&lt;/strong&gt; &lt;span class=&quot;code&quot;&gt;IPageRouteHelper&lt;/span&gt; still exists in CMS 13 but is &lt;strong&gt;deprecated&lt;/strong&gt; (planned removal in a future major); plan migration off it when warnings appear.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Page-centric patterns became &lt;strong&gt;content-centric&lt;/strong&gt;; cast to &lt;span class=&quot;code&quot;&gt;PageData&lt;/span&gt; only when required.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;4. Type migration for references&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;span class=&quot;code&quot;&gt;PageReference&lt;/span&gt; members and parameters became &lt;span class=&quot;code&quot;&gt;ContentReference&lt;/span&gt; where appropriate; &lt;span class=&quot;code&quot;&gt;.PageLink&lt;/span&gt; &amp;rarr; &lt;span class=&quot;code&quot;&gt;.ContentLink&lt;/span&gt; where applicable.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Root and start-page checks use &lt;span class=&quot;code&quot;&gt;ContentReference.RootPage&lt;/span&gt; and &lt;span class=&quot;code&quot;&gt;ContentReference.StartPage&lt;/span&gt; patterns aligned with CMS 13&amp;rsquo;s &lt;strong&gt;application&lt;/strong&gt; model (replacing older &lt;span class=&quot;code&quot;&gt;ISiteDefinitionResolver&lt;/span&gt; / &lt;span class=&quot;code&quot;&gt;SiteDefinition.Current&lt;/span&gt;-style access where the diff touched them). See the official upgrade article for &lt;span class=&quot;code&quot;&gt;IApplicationResolver&lt;/span&gt; examples.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;5. Dependency injection modernization&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Many &lt;span class=&quot;code&quot;&gt;ServiceLocator.Current.GetInstance&amp;lt;T&amp;gt;()&lt;/span&gt; calls were removed in favor of &lt;strong&gt;constructor injection&lt;/strong&gt; and &lt;span class=&quot;code&quot;&gt;GetRequiredService&amp;lt;T&amp;gt;()&lt;/span&gt; in services, controllers, and initialization modules.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Remaining &lt;span class=&quot;code&quot;&gt;ServiceLocator&lt;/span&gt; in lazy static fields moved from &lt;span class=&quot;code&quot;&gt;GetInstance&amp;lt;T&amp;gt;()&lt;/span&gt; to &lt;span class=&quot;code&quot;&gt;GetRequiredService&amp;lt;T&amp;gt;()&lt;/span&gt; so missing registrations &lt;strong&gt;fail fast&lt;/strong&gt; instead of returning null.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;In &lt;span class=&quot;code&quot;&gt;InitializationEngine&lt;/span&gt; modules, &lt;span class=&quot;code&quot;&gt;context.Locate.Advanced.GetInstance&amp;lt;T&amp;gt;()&lt;/span&gt; became &lt;span class=&quot;code&quot;&gt;context.Services.GetRequiredService&amp;lt;T&amp;gt;()&lt;/span&gt; where supported; obsolete resolves (for example &lt;span class=&quot;code&quot;&gt;IContentTypeRepository&lt;/span&gt; used only for legacy setup) were &lt;strong&gt;dropped&lt;/strong&gt; where safe.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Where &lt;span class=&quot;code&quot;&gt;IContentTypeRepository&lt;/span&gt; remains: in CMS 13 it is &lt;strong&gt;no longer generic &lt;/strong&gt;use &lt;span class=&quot;code&quot;&gt;IContentTypeRepository&lt;/span&gt; without a type argument.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;6. Indexing metadata updates&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Legacy &lt;span class=&quot;code&quot;&gt;[Searchable(false)]&lt;/span&gt; attributes became &lt;span class=&quot;code&quot;&gt;[IndexingType(IndexingType.Disabled)]&lt;/span&gt; where indexing should be suppressed under the new model.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;7. Content list and filter API updates&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;In this codebase, some paths had already abstracted &lt;span class=&quot;code&quot;&gt;FilteredItems&lt;/span&gt;-style access behind helpers. Under CMS 13, &lt;span class=&quot;code&quot;&gt;ContentArea.FilteredItems&lt;/span&gt; is removed; the supported replacement is &lt;span class=&quot;code&quot;&gt;ContentArea.Items&lt;/span&gt;. &lt;strong&gt;Retest&lt;/strong&gt; every content area and block rendering path filtering semantics are not guaranteed to be identical to legacy&amp;nbsp;&lt;span class=&quot;code&quot;&gt;FilteredItems&lt;/span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;8. Save behavior and metadata extenders&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Save calls moved from &lt;span class=&quot;code&quot;&gt;SaveAction.Non &lt;/span&gt;to &lt;span class=&quot;code&quot;&gt;SaveAction.Default&lt;/span&gt;, preserving compatibility flags where required (for example &lt;span class=&quot;code&quot;&gt;SaveAction.Default | SaveAction.ForceNewVersion&lt;/span&gt; with &lt;span class=&quot;code&quot;&gt;AccessLevel.NoAccess&lt;/span&gt; unchanged).&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Some block &lt;span class=&quot;code&quot;&gt;UIDescriptor&lt;/span&gt; constructors dropped explicit &lt;span class=&quot;code&quot;&gt;SortKey = new SortColumn { ColumnName = &quot;typeIdentifier&quot;, SortDescending = true }&lt;/span&gt; where the UI no longer depended on that default sort.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;span class=&quot;code&quot;&gt;IMetadataExtender&lt;/span&gt; implementations became &lt;strong&gt;async&lt;/strong&gt;: &lt;span class=&quot;code&quot;&gt;ModifyMetadata&lt;/span&gt; &amp;rarr; &lt;span class=&quot;code&quot;&gt;ModifyMetadataAsync&lt;/span&gt;, with &lt;span class=&quot;code&quot;&gt;await metadata.GetPropertiesAsync(cancellationToken)&lt;/span&gt; (and nested collections the same way) instead of synchronous &lt;span class=&quot;code&quot;&gt;Properties&lt;/span&gt; casts. Some classes dropped legacy &lt;span class=&quot;code&quot;&gt;[ServiceConfiguration(IncludeServiceAccessor = false)]&lt;/span&gt; and adopted current infrastructure attribute namespaces.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;9. Editor descriptor and UI metadata cleanup&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Descriptor metadata was simplified and modernized.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Command &lt;strong&gt;icon class&lt;/strong&gt; values were updated to current shared block icon conventions.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;10. Scheduled job attribute alignment&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Scheduled job annotations were updated to CMS 13 compatible usage.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;11. Site / application resolver abstraction&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;span class=&quot;code&quot;&gt;IApplicationResolver&lt;/span&gt; for site URL and application name resolution uses &lt;strong&gt;routed application context&lt;/strong&gt; instead of legacy global patterns; verify &lt;strong&gt;Settings &amp;rarr; Applications&lt;/strong&gt; after first run on CMS 13 (&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/application-framework&quot;&gt;Application framework&lt;/a&gt;).&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;12. Startup registration alignment&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Use &lt;span class=&quot;code&quot;&gt;using EPiServer.DependencyInjection;&lt;/span&gt; for &lt;span class=&quot;code&quot;&gt;AddCms()&lt;/span&gt; and related extension methods.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services
    .AddCms()
    .AddContentGraph()
    .AddContentManager();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Order matters:&lt;/strong&gt; register &lt;span class=&quot;code&quot;&gt;AddContentGraph()&lt;/span&gt; before &lt;span class=&quot;code&quot;&gt;AddContentManager()&lt;/span&gt;. Enable Graph in the &lt;strong&gt;PaaS portal&lt;/strong&gt; before adding Graph packages. Typical package references on the branch included:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&amp;lt;PackageReference Include=&quot;Optimizely.Graph.Cms&quot; Version=&quot;13.0.2&quot; /&amp;gt;
&amp;lt;PackageReference Include=&quot;Optimizely.Graph.Cms.Query&quot; Version=&quot;13.0.2&quot; /&amp;gt;
&amp;lt;PackageReference Include=&quot;EPiServer.Cms.UI.ContentManager&quot; Version=&quot;13.0.2&quot; /&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;CMS 13&amp;nbsp;&lt;strong&gt;assembly scanning&lt;/strong&gt; means every referenced package needs a matching &lt;span class=&quot;code&quot;&gt;Add*()&lt;/span&gt; registration or must be removed. &lt;strong&gt;SQL Server&lt;/strong&gt; compatibility level &lt;strong&gt;140+&lt;/strong&gt; is required (see official guide for &lt;span class=&quot;code&quot;&gt;UpdateDatabaseCompatibilityLevel&lt;/span&gt;).&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;tableView-content-wrap&quot;&gt;
&lt;div&gt;
&lt;div class=&quot;pm-table-resizer-container&quot;&gt;
&lt;div class=&quot;resizer-item display-handle&quot;&gt;
&lt;div class=&quot;pm-table-container&quot;&gt;
&lt;div class=&quot;pm-table-sticky-sentinel-top&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;NU1202 on .NET 10.0&lt;/strong&gt; &amp;ndash; Upgrade or remove incompatible third-party packages&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;NU1608&lt;/strong&gt; &amp;ndash; Align all EPiServer.* / Optimizely.* packages to the same CMS 13 version&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Missing types after removing Find&lt;/strong&gt; &amp;ndash; Re-add explicit dependencies (e.g., Newtonsoft.Json) or migrate to System.Text.Json&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;13. Model transforms and content store projections&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Some transforms moved from &lt;span class=&quot;code&quot;&gt;ContentDataStoreModelTransform&lt;/span&gt; to &lt;span class=&quot;code&quot;&gt;TransformBase&amp;lt;ContentDataStoreModel&amp;gt;&lt;/span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Synchronous &lt;span class=&quot;code&quot;&gt;TransformInstance&lt;/span&gt; overrides became &lt;span class=&quot;code&quot;&gt;Task TransformInstanceAsync(..., CancellationToken cancellationToken = default)&lt;/span&gt; with &lt;span class=&quot;code&quot;&gt;await base.TransformInstanceAsync(...)&lt;/span&gt; where applicable.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;14. Shell controllers and BCL-style validation&lt;/span&gt;&lt;/h3&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Shell or admin controllers that resolved services from &lt;span class=&quot;code&quot;&gt;ServiceLocator.Current&lt;/span&gt; in chained constructors were updated to &lt;span class=&quot;code&quot;&gt;GetRequiredService&amp;lt;T&amp;gt;()&lt;/span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;span class=&quot;code&quot;&gt;EPiServer.Data.Validator.ValidateArgNotNull(&quot;paramName&quot;, value)&lt;/span&gt; call sites became &lt;span class=&quot;code&quot;&gt;ArgumentNullException.ThrowIfNull(value)&lt;/span&gt; for clearer, framework-standard null checks.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Search and Navigation vs Content Graph query pattern&lt;/span&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Legacy-style pseudocode (Find)&lt;/span&gt;&lt;/h3&gt;
&lt;div class=&quot;code-block-content-wrapper&quot;&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var query = legacySearchClient.Search&amp;lt;SeoPageData&amp;gt;();
if (!string.IsNullOrWhiteSpace(term))
{
    query = query.For(term);
}

query = query.Filter(x =&amp;gt; !x.ExcludeFromSearch);
var result = query.Skip((page - 1) * pageSize).Take(pageSize).GetResult();&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Graph-style pattern (same responsibilities)&lt;/span&gt;&lt;/h3&gt;
&lt;div class=&quot;code-block-content-wrapper&quot;&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var q = graphClient
    .QueryContent&amp;lt;SeoPageData&amp;gt;()
    .AsCurrentUser()
    .SetLocale(currentCulture)
    .WithDisplayFilters()
    .WithCacheOptions(o =&amp;gt; o.AbsoluteExpiration = TimeSpan.FromMinutes(5));

if (!string.IsNullOrWhiteSpace(term) &amp;amp;&amp;amp; q is ISearchableContentQuery&amp;lt;SeoPageData&amp;gt; searchable)
{
    q = searchable.SearchFor(term).WithPinned();
}
q = q.Where(x =&amp;gt; x.ExcludeFromSearch != true);
q = ApplySort(q, selectedSortValue);

var graphResult = await q.IncludeTotal().Skip(skip).Limit(pageSize).GetAsContentAsync(ct);&lt;/code&gt;&lt;/pre&gt;
&lt;/div&gt;
&lt;div class=&quot;code-block--end&quot;&gt;&amp;nbsp;&lt;/div&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Converting search queries to Graph (practical flow)&lt;/span&gt;&lt;/h2&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Configure Graph&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;&quot;Optimizely&quot;: {
  &quot;ContentGraph&quot;: {
    &quot;GatewayAddress&quot;: &quot;https://cg.optimizely.com&quot;,
    &quot;AppKey&quot;: &quot;&quot;,
    &quot;Secret&quot;: &quot;&quot;,
    &quot;SingleKey&quot;: &quot;&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Convert full search query&lt;/span&gt;&lt;/h3&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public async Task&amp;lt;SearchResponse&amp;gt; SearchAsync(SearchRequest request, CancellationToken ct)
{
    var q = _graphContentClient
        .QueryContent&amp;lt;SeoPageData&amp;gt;()
        .AsCurrentUser()
        .SetLocale(CultureInfo.CurrentCulture)
        .WithDisplayFilters()
        .WithCacheOptions(o =&amp;gt; o.AbsoluteExpiration = TimeSpan.FromMinutes(5));

    if (!string.IsNullOrWhiteSpace(request.Term) &amp;amp;&amp;amp; q is ISearchableContentQuery&amp;lt;SeoPageData&amp;gt; searchable)
    {
        q = searchable.SearchFor(request.Term).WithPinned();
    }

    q = q.Where(x =&amp;gt; !x.ExcludeFromSearch);

    var skip = (Math.Max(request.Page, 1) - 1) * request.PageSize;
    var result = await q.IncludeTotal().Skip(skip).Limit(request.PageSize).GetAsContentAsync(ct);

    return new SearchResponse
    {
        Total = result.Total ?? 0,
        Items = result.Select(MapSearchHit).ToList()
    };
}&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Keep prompt / autocomplete aligned&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Reuse the &lt;strong&gt;same&lt;/strong&gt; composed query with a small window so prompts cannot diverge from full search rules:&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var promptResult = await q
    .IncludeTotal()
    .Skip(0)
    .Limit(5)
    .GetAsContentAsync(ct);&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Case-study takeaways&amp;nbsp;&lt;/span&gt;&lt;/h2&gt;
&lt;ul class=&quot;ak-ul&quot;&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Biggest calendar sink:&lt;/strong&gt; third-party packages and &lt;strong&gt;obsolete&lt;/strong&gt; API removal not the Graph fluent API mapping itself.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Biggest quality win:&lt;/strong&gt; &lt;strong&gt;one&lt;/strong&gt; shared query composition function for &lt;strong&gt;term, filters, sort, scope&lt;/strong&gt;, then different callers only change &lt;strong&gt;skip/limit&lt;/strong&gt; (full page vs prompt).&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Subtle regressions:&lt;/strong&gt; &lt;strong&gt;sort order&lt;/strong&gt; vs legacy Find, &lt;strong&gt;pinned&lt;/strong&gt; behavior, and &lt;strong&gt;content area&lt;/strong&gt; rendering after &lt;span class=&quot;code&quot;&gt;FilteredItems&lt;/span&gt; &amp;rarr; &lt;span class=&quot;code&quot;&gt;Items&lt;/span&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;&lt;strong&gt;Ops surprises:&lt;/strong&gt; admin base path (&lt;span class=&quot;code&quot;&gt;/ui/CMS&lt;/span&gt; vs &lt;span class=&quot;code&quot;&gt;/Optimizely/CMS&lt;/span&gt;), SQL index conflicts on first-run migration, tab identifier rules see &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/upgrade-to-cms-13&quot;&gt;Upgrade to CMS 13 from CMS 12&lt;/a&gt;.&lt;/span&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;If the admin UI shows &lt;strong&gt;&amp;ldquo;No policy found&amp;rdquo;&lt;/strong&gt; or &lt;strong&gt;&amp;ldquo;Unable to find a module by assembly&amp;rdquo;&lt;/strong&gt;, a removed package often left &lt;strong&gt;policies&lt;/strong&gt; or &lt;strong&gt;menu providers&lt;/strong&gt; half-wired strip registrations and &lt;span class=&quot;code&quot;&gt;using&lt;/span&gt; directives completely.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;Final recommendation&lt;/span&gt;&lt;/h2&gt;
&lt;p&gt;&lt;span style=&quot;font-family: helvetica, arial, sans-serif;&quot;&gt;For a CMS 12 to CMS 13 migration, treat &lt;strong&gt;search conversion as an architecture task&lt;/strong&gt;, not only a syntax task. Follow Optimizely&amp;rsquo;s &lt;strong&gt;ordered upgrade steps&lt;/strong&gt; (framework, packages, &lt;span class=&quot;code&quot;&gt;AddCms()&lt;/span&gt;, Graph and Content Manager registration order, then breaking changes) and use the &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/api-replacement-map&quot;&gt;&lt;strong&gt;API replacement map&lt;/strong&gt;&lt;/a&gt; when &lt;span class=&quot;code&quot;&gt;dotnet build&lt;/span&gt; surfaces unfamiliar errors. If you centralize scoping, filters, sorting, and paging in a graph-first pipeline, you get cleaner code, easier testing, and far fewer search regressions after release.&lt;/span&gt;&lt;/p&gt;</id><updated>2026-04-24T06:34:49.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Optimizely CMS 13 host(s) management</title><link href="https://world.optimizely.com/blogs/harish-yadav/dates/2026/4/optimizely-cms-13-hosts-management/" /><id>&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;One of the features I found most impressive is the way Optimizely CMS 13 handles hosts with clear definition and intent. It may sound low level configuration update but it has direct impact on how your solution handles &lt;strong&gt;URLs, routing, preview, redirects, and the separation between CMS and front end&lt;/strong&gt;.&lt;/p&gt;
&lt;h3 class=&quot;ember-view reader-text-block__heading-3&quot;&gt;&lt;strong&gt;So what is it, really?&lt;/strong&gt; &#128071;&lt;/h3&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;In CMS 13, Optimizely lets you define different application host types depending on whether your solution follows a traditional or headless architecture. This is built around two application types.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Website (out-of-process):&lt;/strong&gt; This represent headless or decoupled architecure where optimizely manages content and but another application handles rendering ex. react, angular, next.js. With this approach more responsibility typically sits in the front-end layer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;InProcessWebsite :&lt;/strong&gt; This is traditional setup where website is rendered inside the same ASP.NET Core application as CMS. With this approach Optimizely handles behaviour directly inside application itself.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3 class=&quot;ember-view reader-text-block__heading-3&quot;&gt;&lt;strong&gt;Application host types support &lt;/strong&gt;⚙️&lt;/h3&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;CMS 13&lt;strong&gt; &lt;/strong&gt;support several hosts types including:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a class=&quot;vBYnWVkPRypFSfHBTqJeVZIGbkWsgwTk &quot; href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/application-framework#primary&quot;&gt;Primary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;vBYnWVkPRypFSfHBTqJeVZIGbkWsgwTk &quot; href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/application-framework#default&quot;&gt;Default&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;vBYnWVkPRypFSfHBTqJeVZIGbkWsgwTk &quot; href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/application-framework#preview&quot;&gt;Preview&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;vBYnWVkPRypFSfHBTqJeVZIGbkWsgwTk &quot; href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/application-framework#edit&quot;&gt;Edit&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;vBYnWVkPRypFSfHBTqJeVZIGbkWsgwTk &quot; href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/application-framework#redirectpermanent&quot;&gt;RedirectPermanent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;vBYnWVkPRypFSfHBTqJeVZIGbkWsgwTk &quot; href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/application-framework#redirecttemporary&quot;&gt;RedirectTemporary&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class=&quot;vBYnWVkPRypFSfHBTqJeVZIGbkWsgwTk &quot; href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/docs/application-framework#media&quot;&gt;Media&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;What I found especially interesting is that these host types are not just labels as they reflect clear responsibilities.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;I was particularly drawn to &lt;strong&gt;RedirectPermanent&lt;/strong&gt;&amp;nbsp;because it directly connected to a real-world problem I was looking to solve.&lt;/p&gt;
&lt;h3 class=&quot;ember-view reader-text-block__heading-3&quot;&gt;&lt;strong&gt;A very practical example: non-www &amp;rarr; www redirect&lt;/strong&gt; &#127757;&lt;/h3&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;Let&amp;rsquo;s say your preferred public domain is &lt;strong&gt;www.example.com&lt;/strong&gt;&lt;strong&gt; b&lt;/strong&gt;ut visitors may also enter &lt;strong&gt;example.com&lt;/strong&gt;&lt;strong&gt; &lt;/strong&gt;&lt;em&gt;(should have valid certificate for apex domain and uses A record)&lt;/em&gt;&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;In an &lt;strong&gt;InProcessWebsite&lt;/strong&gt; setup, a clean solution is to configure:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;www.example.com&lt;/strong&gt; as the &lt;strong&gt;Primary&lt;/strong&gt; host&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;example.com&lt;/strong&gt; as &lt;strong&gt;RedirectPermanent&lt;/strong&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;That creates a proper &lt;strong&gt;301 redirect&lt;/strong&gt; from &lt;strong&gt;non-www&lt;/strong&gt; to &lt;strong&gt;www&lt;/strong&gt;.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;There are certainly several ways to solve this in Optimizely CMS, but in my view, this is one of the cleanest and most pragmatic approach.&lt;/p&gt;
&lt;p class=&quot;ember-view reader-text-block__paragraph&quot;&gt;Cheers!&lt;/p&gt;</id><updated>2026-04-23T19:13:50.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Building Opal tools on Optimizely Connect Platform: a Mailchimp walkthrough</title><link href="https://world.optimizely.com/blogs/sanjay-katiyar/dates/2026/4/building-opal-tools-on-optimizely-connect-platform-a-mailchimp-walkthrough/" /><id>&lt;h3 class=&quot;mt-6 mb-2 font-semibold text-xl&quot;&gt;About the Mailchimp Opal Tool&lt;/h3&gt;
&lt;p&gt;The&amp;nbsp;&lt;span class=&quot;font-semibold&quot;&gt;Mailchimp Opal Tool&lt;/span&gt;&amp;nbsp;is an Optimizely Connect Platform app that brings Mailchimp audience operations directly into Opal workflows. It exposes developer-friendly tools for audience, contact, tag, and campaign management, with settings-driven authentication so teams can configure API access once and reuse it across automations. In addition to interactive tool calls, it includes a background sync job that can ingest Mailchimp contacts in batches and upsert them into ODP, making it useful for both real-time actions and scheduled data synchronization.&lt;/p&gt;
&lt;p&gt;Built with TypeScript on OCP, the app follows a clear architecture: app.yml for runtime/function declarations, forms/settings.yml for secure credential inputs, Lifecycle hooks for install/settings handling, and modular @tool-decorated function classes for API operations. This structure makes the integration easy to extend, test, and maintain as Mailchimp use cases evolve.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Log in to the Optimizely Connect Platform using your OptiID credentials and install the Mailchimp Opal Tool.&lt;/strong&gt;&lt;/p&gt;
&lt;h2 class=&quot;mt-6 mb-2 font-semibold text-2xl&quot;&gt;&lt;img src=&quot;/link/f26f553d4f8845c6a1fe42564c0aafe3.aspx&quot; /&gt;&lt;/h2&gt;
&lt;h2 class=&quot;mt-6 mb-2 font-semibold text-2xl&quot;&gt;OCP Developer Guide&lt;/h2&gt;
&lt;p&gt;An OCP app is app.yml + a compiled Node.js bundle + optional forms/settings + assets for directory listing content.&lt;br /&gt;Opal tools are typically implemented as a single exported class extending ToolFunction, with @tool-decorated methods.&lt;/p&gt;
&lt;p&gt;Use:&lt;/p&gt;
&lt;ul class=&quot;list-inside list-disc whitespace-normal [li_&amp;amp;]:pl-6&quot;&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;@zaiusinc/app-sdk for lifecycle, storage, jobs, and notifications&lt;/li&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;@optimizely-opal/opal-tool-ocp-sdk for tool metadata and routing shape&lt;/li&gt;
&lt;/ul&gt;
&lt;h3 class=&quot;mt-6 mb-2 font-semibold text-xl&quot;&gt;Who This Is For&lt;/h3&gt;
&lt;p&gt;You already know TypeScript and REST APIs. You want a checklist + mental model for OCP and a real project layout (this repo), not abstract marketing copy.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Node.js: Align with runtime in app.yml (this project uses node22).&lt;/li&gt;
&lt;li&gt;Yarn 1.x: Used in package.json scripts (npm also works if you adapt commands).&lt;/li&gt;
&lt;li&gt;OCP CLI: Install via yarn global add @optimizely/ocp-cli and ensure the global bin is in PATH.&lt;/li&gt;
&lt;li&gt;OCP credentials: %USERPROFILE%\.ocp\credentials.json (Windows) or ~/.ocp/credentials.json with your API key.&lt;/li&gt;
&lt;li&gt;Verify CLI: ocp accounts whoami&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Mental model: what runs where&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;Merchant installs app
    &amp;rarr; reads app.yml (meta, runtime, functions, jobs)
    &amp;rarr; shows forms/settings.yml
    &amp;rarr; Lifecycle.onInstall / onSettingsForm &amp;rarr; storage.settings.put(...)
Opal invokes a tool
    &amp;rarr; OCP loads entry_point class (e.g. MailchimpOpalToolFunction)
    &amp;rarr; method decorated with @tool(...) executes with authData.credentials
Job scheduler runs sync_contacts
    &amp;rarr; Job.prepare / Job.perform loop until status.complete&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Minimal project skeleton&lt;/strong&gt;&lt;br /&gt;Suggested layout (matches this repo):&lt;br /&gt;&lt;br /&gt;mailchimp-opal-tool/&lt;br /&gt;├── app.yml &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; # OCP manifest&lt;br /&gt;├── package.json&lt;br /&gt;├── tsconfig.json&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; # decorators: true (required for @tool)&lt;br /&gt;├── forms/&lt;br /&gt;│ &amp;nbsp; └── settings.yml&amp;nbsp; &amp;nbsp; &amp;nbsp;# merchant-facing settings schema&lt;br /&gt;├── assets/&lt;br /&gt;│ &amp;nbsp; └── directory/ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;# marketplace copy, icons, etc.&lt;br /&gt;└── src/&lt;br /&gt;&amp;nbsp; &amp;nbsp; ├── index.ts&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;# export entry_point classes + Lifecycle&lt;br /&gt;&amp;nbsp; &amp;nbsp; ├── api-client.ts&lt;br /&gt;&amp;nbsp; &amp;nbsp; ├── types.ts&lt;br /&gt;&amp;nbsp; &amp;nbsp; ├── lifecycle/&lt;br /&gt;&amp;nbsp; &amp;nbsp; │ &amp;nbsp; └── Lifecycle.ts&lt;br /&gt;&amp;nbsp; &amp;nbsp; ├── functions/&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;# ToolFunction subclasses + @tool methods&lt;br /&gt;&amp;nbsp; &amp;nbsp; ├── jobs/ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; # optional Job subclasses&lt;br /&gt;&amp;nbsp; &amp;nbsp; ├── odp/ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;# mappers (e.g. Mailchimp &amp;rarr; ODP)&lt;br /&gt;&amp;nbsp; &amp;nbsp; └── data/ &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; # types for API responses / job state&lt;br /&gt;&lt;br /&gt;&lt;strong&gt;Dependencies you actually care about&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;From package.json:&lt;/p&gt;
&lt;p&gt;@optimizely-opal/opal-tool-ocp-sdk ToolFunction, @tool, ParameterType.&lt;br /&gt;@zaiusinc/app-sdk Lifecycle, Job, storage, logger, notifications, Request.&lt;br /&gt;@zaiusinc/node-sdk&amp;nbsp; ODP writes (e.g. z.customer(batch) in jobs).&lt;br /&gt;axios&amp;nbsp; HTTP client to the third-party API (here, Mailchimp).&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;app.yml: the contract with OCP&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Important fields in this app:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;meta.app_id: stable identifier (here: mailchimpopaltool).&lt;/li&gt;
&lt;li&gt;runtime: must match your local/toolchain (here: node22).&lt;/li&gt;
&lt;li&gt;functions.opal_tool:
&lt;ul&gt;
&lt;li&gt;opal_tool: true&lt;/li&gt;
&lt;li&gt;entry_point: must match an exported class name from your bundle (here: MailchimpOpalToolFunction).&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;jobs.sync_contacts: &amp;nbsp;
&lt;ul&gt;
&lt;li&gt;entry_point: SyncContacts&amp;nbsp; exported Job subclass.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If entry_point does not match an export, validation or deploy will fail in confusing ways&amp;nbsp; treat exports as part of your public API.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;src/index.ts: exports are the wiring&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Pattern used here:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Export the Opal tool class the manifest names.&lt;/li&gt;
&lt;li&gt;Export Lifecycle for install/settings/upgrade hooks.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Opal tool class in this project is a re-export alias: MailchimpOpalToolFunction points at the leaf subclass that includes all tools (audience &amp;rarr; tag &amp;rarr; contact &amp;rarr; campaign stack), so app.yml stays stable while you add layers in functions/.&lt;/p&gt;
&lt;h2 class=&quot;mt-6 mb-2 font-semibold text-2xl&quot;&gt;Opal tools: implementation recipe&lt;/h2&gt;
&lt;ol class=&quot;list-inside list-decimal whitespace-normal [li_&amp;amp;]:pl-6&quot;&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;Extend ToolFunction from @optimizely-opal/opal-tool-ocp-sdk.&lt;/li&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;On each public tool method, add @tool({ name, description, endpoint, parameters }).&lt;/li&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;Use ParameterType.* and required: true | false so Opal gets a proper JSON schema for the agent.&lt;/li&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;Resolve HTTP client from authData.credentials (throw a clear error if missing).&lt;/li&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;Return a predictable JSON object (this codebase uses { success, data } / { success: false, error }) so agents can branch without parsing stack traces.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;span class=&quot;font-semibold&quot;&gt;Mailchimp-specific tip:&lt;/span&gt;&amp;nbsp;member endpoints use the&amp;nbsp;&lt;span class=&quot;font-semibold&quot;&gt;MD5 hash of lowercased email&lt;/span&gt; as the path segment; this repo centralizes that in a base class helper.&lt;/p&gt;
&lt;h2 class=&quot;mt-6 mb-2 font-semibold text-2xl&quot;&gt;Jobs: SyncContacts pattern&lt;/h2&gt;
&lt;p&gt;Use a job when:&lt;/p&gt;
&lt;ul class=&quot;list-inside list-disc whitespace-normal [li_&amp;amp;]:pl-6&quot;&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;Work exceeds a single request/response cycle.&lt;/li&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;You need&amp;nbsp;&lt;span class=&quot;font-semibold&quot;&gt;pagination&lt;/span&gt;,&amp;nbsp;&lt;span class=&quot;font-semibold&quot;&gt;retries&lt;/span&gt;, and&amp;nbsp;&lt;span class=&quot;font-semibold&quot;&gt;notifications&lt;/span&gt;&amp;nbsp;on completion/failure.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Implementation notes from this job:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;prepare:&amp;nbsp; initialize status.state (offset, count, retries, list id).&lt;/li&gt;
&lt;li&gt;perform: fetch page &amp;rarr; map to ODP payloads &amp;rarr; batch upsert (chunk size tuned to ODP limits) &amp;rarr; advance offset &amp;rarr; set status.complete when done.&lt;/li&gt;
&lt;li&gt;Retries:&amp;nbsp; bounded retries + backoff; on exhaustion, notify and complete.&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 class=&quot;mt-6 mb-2 font-semibold text-2xl&quot;&gt;Build&lt;/h2&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code&gt;yarn install
yarn build
ocp app validate
ocp dev&lt;/code&gt;&lt;/pre&gt;
&lt;h2 class=&quot;mt-6 mb-2 font-semibold text-2xl&quot;&gt;CLI quick reference&lt;/h2&gt;
&lt;pre class=&quot;language-python&quot;&gt;&lt;code&gt;ocp accounts whoami
ocp app validate
yarn build
ocp dev
ocp app prepare
ocp directory publish
ocp app logs --appId &amp;lt;YOUR_APP_ID&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;br /&gt;More step-by-step PowerShell setup lives in &lt;a href=&quot;https://github.com/NiyoDx/OpalTool-PowerShell-Generator/blob/main/setup/Scaffold-OcpOpalTool.ps1&quot;&gt;script&lt;/a&gt;.&lt;/p&gt;
&lt;h2 class=&quot;mt-6 mb-2 font-semibold text-2xl&quot;&gt;Debugging checklist&lt;/h2&gt;
&lt;ul class=&quot;list-inside list-decimal whitespace-normal [li_&amp;amp;]:pl-6&quot;&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;ocp app validate fails, &amp;nbsp;Check entry_point strings vs src/index.ts exports; check runtime vs local Node.&lt;/li&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;Tools fail at runtime with &amp;ldquo;credentials required&amp;rdquo;, Settings section key mismatch: ensure onSettingsForm saved the section your tool reads (credentials in this app).&lt;/li&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;Decorators seem ignored tsconfig / wrong outDir; ensure you are running the built output OCP expects.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class=&quot;font-semibold&quot;&gt;Job stuck or repeating Inspect status.state logging; ensure status.complete is set on all exit paths; avoid throwing without updating state if you intend to retry.&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2 class=&quot;mt-6 mb-2 font-semibold text-2xl&quot;&gt;Extending this app safely&lt;/h2&gt;
&lt;ul class=&quot;list-inside list-disc whitespace-normal [li_&amp;amp;]:pl-6&quot;&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;&lt;span class=&quot;font-semibold&quot;&gt;New tool: add a method + @tool on the appropriate class in the inheritance chain, or add a new subclass and change the final export if you want a cleaner split.&lt;/span&gt;&lt;/li&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;&lt;span class=&quot;font-semibold&quot;&gt;New setting: add field to forms/settings.yml, validate in Lifecycle, read in tools/jobs.&lt;/span&gt;&lt;/li&gt;
&lt;li class=&quot;py-1 [&amp;amp;&amp;gt;p]:inline&quot;&gt;&lt;span class=&quot;font-semibold&quot;&gt;New job: add class under src/jobs/, export if needed, add block under jobs: in app.yml.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keep&amp;nbsp;&lt;span class=&quot;font-semibold&quot;&gt;manifest, exports, and form keys&lt;/span&gt; in sync, that is the most common source of integration bugs.&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;Thanks for visting!&lt;/p&gt;</id><updated>2026-04-22T06:06:14.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>&#128227; Build, Automate, and Scale Content Operations with CMS REST API v1 - now live! </title><link href="https://world.optimizely.com/blogs/kathy-copeland/dates/2026/4/-build-automate-and-scale-content-operations-with-cms-rest-api-v1---now-live-/" /><id>&lt;p&gt;&lt;strong&gt;Now available for both CMS13 and CMS SaaS&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We are excited to announce the&amp;nbsp;&lt;strong&gt;v1 release of our CMS REST API&lt;/strong&gt;&amp;mdash;a major milestone in delivering a stable, production-ready foundation for automating and integrating with Optimizely&amp;rsquo;s CMS. This release will apply to both our recently released CMS13 on PaaS and our CMS SaaS platforms.&lt;/p&gt;
&lt;p&gt;&#128161;&lt;strong&gt;&amp;nbsp;Why this matters&amp;nbsp;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Previous iterations of our CMS REST API were released as preview versions allowing us to make available these short term stable releases as we continue to mature the API. With v1, we are officially shifting to a&amp;nbsp;&lt;strong&gt;commitment of stability, backward compatibility, and long-term support&lt;/strong&gt;&amp;mdash;providing our developer audience and partners the confidence to build their integrations with our CMS platforms at scale.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;This release aligns closely with the capabilities of the Optimizely SaaS CMS UI, ensuring consistency between what users see and what developers can programmatically control. For CMS13 developers, only those features available in the CMS13 user experience will be covered by the CMS REST API.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;An overview of migrating from Preview3 to v1 for the CMS REST API for SaaS can be found &lt;a class=&quot;fui-Link ___1q1shib f2hkw1w f3rmtva f1ewtqcl fyind8e f1k6fduh f1w7gpdv fk6fouc fjoy568 figsok6 f1s184ao f1mk8lai fnbmjn9 f1o700av f13mvf36 f1cmlufx f9n3di6 f1ids18y f1tx3yz7 f1deo86v f1eh06m1 f1iescvh fhgqx19 f1olyrje f1p93eir f1nev41a f1h8hb77 f1lqvz6u f10aw75t fsle3fq f17ae5zn&quot; title=&quot;https://docs.developers.optimizely.com/content-management-system/v1.0.0-cms-saas/reference/migrate-content-api-preview3-to-v1&quot; href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/reference/migrate-content-api-preview3-to-v1&quot;&gt;here&lt;/a&gt;:&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Documentation for the CMS REST API v1 for CMS13 can be found &lt;a class=&quot;fui-Link ___1q1shib f2hkw1w f3rmtva f1ewtqcl fyind8e f1k6fduh f1w7gpdv fk6fouc fjoy568 figsok6 f1s184ao f1mk8lai fnbmjn9 f1o700av f13mvf36 f1cmlufx f9n3di6 f1ids18y f1tx3yz7 f1deo86v f1eh06m1 f1iescvh fhgqx19 f1olyrje f1p93eir f1nev41a f1h8hb77 f1lqvz6u f10aw75t fsle3fq f17ae5zn&quot; title=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-cms/reference/introduction-cms-rest-api&quot; href=&quot;https://docs.developers.optimizely.com/content-management-system/v13.0.0-CMS/reference/introduction-cms-rest-api&quot;&gt;here&lt;/a&gt;:&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;&#127381;&lt;strong&gt;&amp;nbsp;What&amp;rsquo;s Included in v1?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;The v1 API delivers a comprehensive set of endpoints designed to support the full content lifecycle and schema management of the CMS platform programmatically. Any developers who have been using Preview3 endpoints will be familiar with many of the v1 endpoints. New to V1 are the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Content: Manage content and versions (moved out of experimental status)
&lt;ul&gt;
&lt;li&gt;Standalone content lifecycle endpoints (new)&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Content Types: Define structured schemas for pages, blocks for programmatic content modeling&lt;/li&gt;
&lt;li&gt;Content Sources: Create and manage external content sources (new)&lt;/li&gt;
&lt;li&gt;Content Type Bindings: Map relationships and property associations for external content sources (new)&lt;/li&gt;
&lt;li&gt;Blueprints: Create and manage content blueprints&lt;/li&gt;
&lt;li&gt;Locales: Manage supported content languages (new)&lt;/li&gt;
&lt;li&gt;Display templates: Create and manage style display templates for use in the CMS visual builder.&lt;/li&gt;
&lt;li&gt;Property groups: Create and manage content property groups.&lt;/li&gt;
&lt;li&gt;Manifest: Export and/or import a content manifest with content types, locales, display templates and property groups&lt;/li&gt;
&lt;li&gt;Credentials: Manage client credentials for secure API access (SaaS only)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The Packaging API remains under the /experimental/ prefix in v1. For more information about our policy regarding Experimental endpoints, please refer to the documentation found &lt;a class=&quot;fui-Link ___1q1shib f2hkw1w f3rmtva f1ewtqcl fyind8e f1k6fduh f1w7gpdv fk6fouc fjoy568 figsok6 f1s184ao f1mk8lai fnbmjn9 f1o700av f13mvf36 f1cmlufx f9n3di6 f1ids18y f1tx3yz7 f1deo86v f1eh06m1 f1iescvh fhgqx19 f1olyrje f1p93eir f1nev41a f1h8hb77 f1lqvz6u f10aw75t fsle3fq f17ae5zn&quot; title=&quot;https://docs.developers.optimizely.com/content-management-system/v1.0.0-cms-saas/reference/experimental-apis&quot; href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/reference/experimental-apis&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Now, with the v1 CMS REST API, developers and development partners can depend upon Optimizely CMS API stability and continuity between SaaS and PaaS releases. Further, they will be able to trust the enterprise readiness, security, and performance of their applications at scale. This transition offers our developer audience the confidence they need to take the Optimizely CMS platform to scalable content operations beyond just our user interfaces.&lt;/p&gt;
&lt;p&gt;V1 is just the start of big things to come! &#128640;&lt;/p&gt;</id><updated>2026-04-21T21:47:48.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Introducing AI Assistant v4 for Optimizely CMS 12 and 13</title><link href="https://optimizely.blog/2026/04/introducing-ai-assistant-v4-for-optimizely-cms-12-and-13/" /><id>Epicweb AI Assistant v4.0 adds full support for Optimizely CMS 13 on .NET 10 while staying compatible with CMS 12 on .NET 8, plus new AI Chat tools for Visitor Groups and Display Options to simplify personalization and layout for ContentAreas.
</id><updated>2026-04-20T21:18:24.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Remote Debugging in Optimizely DXP: What Is Actually Possible? </title><link href="https://world.optimizely.com/blogs/mike/dates/2026/4/remote-debugging-in-optimizely-dxp-what-is-actually-possible-/" /><id>&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;h3 class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Introduction&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;At SYZYGY &lt;/span&gt;&lt;span class=&quot;NormalTextRun SpellingErrorV2Themed SCXW248700128 BCX8&quot;&gt;Techsolutions&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;, we support Optimizely DXP projects at scale, so continuously&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;identifying&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;the right tools and approaches for analyzing complex issues is an essential part of how we work.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;At some point, most developers&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;encounter&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; issues that are complex&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;to reproduce locally. Differences between local setup and other environments, variations in operating systems, and discrepancies in configuration or data all contribute to this gap.&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;While logs and telemetry provide valuable signals, they are inherently indirect. They rely on post&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;NoBreakHyphenBlob BlobObject DragDrop SCXW248700128 BCX8&quot;&gt;‑&lt;/span&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;hoc interpretation and selective instrumentation, which can make it difficult to fully understand execution flow and runtime behavior in a managed platform like Optimizely DXP.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;This led to a question:&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot; style=&quot;text-align: left; padding-left: 20pt;&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&lt;strong&gt;Can you remotely debug an application running in Optimizely DXP?&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;strong&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;After going through official documentation, community discussions, and existing guides, I realized that the answer&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;isn&amp;rsquo;t&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;clearly documented. And&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;that&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;not accidental.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;strong&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;TL;DR&lt;/span&gt;&lt;/strong&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&lt;strong&gt;:&lt;/strong&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Based on this investigation, true remote debugging inside Optimizely DXP does not appear to be a supported workflow&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;This aligns with the nature of DXP as a managed Platform-as-a-Service (PaaS), where direct access to infrastructure and debugging capabilities is limited.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Still, the question&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;remains&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;relevant. For developers working with complex behavior,&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;it&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;useful to understand&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;the boundaries&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;.&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;To get a clear picture, I approached this as a structured exploration. Instead of focusing on DXP directly, the investigation starts from the underlying platform it builds upon &amp;ndash; Azure App Services (Linux) &amp;ndash; and moves upward from there. This makes it possible to map what is available, how it behaves, and how those capabilities surface within a DXP environment&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;&lt;hr /&gt;
&lt;h3 class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Why Remote Debugging Matters &amp;ndash; and Why&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;It&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; So Hard in DXP&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Remote debugging is one of the most powerful &amp;ndash; yet often overlooked &amp;ndash; tools in a developer&amp;rsquo;s toolkit. Being able to attach a debugger to a live environment allows you to inspect variables, step through code paths, and diagnose elusive bugs that only manifest in production-like conditions. In traditional Azure App Service setups, remote debugging with tools like &lt;strong&gt;Visual Studio&lt;/strong&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;or&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&lt;strong&gt;JetBrains Rider&lt;/strong&gt;&amp;nbsp;is not only possible but well-documented.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;Optimizely&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;DXP is a managed Platform-as-a-Service (PaaS) which prioritizes multiple layers of abstraction and a strong emphasis on security, compliance, and performance over infrastructure access.&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;In practice, DXP limits direct access to underlying app services, VM internals, and debugging endpoints.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;So what options are actually available &amp;ndash; and how far can you realistically go with them?&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;h3 class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Remote Debugging Options &amp;ndash; Azure Web App (Linux) + .NET&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;The Optimizely ecosystem runs on Linux containers, which means that tools like &lt;/span&gt;&lt;a title=&quot;Official Microsoft Documentation&quot; href=&quot;https://learn.microsoft.com/en-us/visualstudio/debugger/debug-live-azure-applications?view=vs-2022&quot;&gt;Snapshot Debugger&lt;/a&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;or&amp;nbsp;&lt;a title=&quot;Official Microsoft Documentation&quot; href=&quot;https://learn.microsoft.com/en-us/visualstudio/debugger/remote-debugging-azure-app-service?view=vs-2022&quot;&gt;Remote debugging on Azure App Services (Windows)&lt;/a&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; are simply not available. The alternative&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;we&#39;re&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; left with is an &lt;a title=&quot;Official Microsoft Documentation&quot; href=&quot;https://learn.microsoft.com/en-us/visualstudio/debugger/remote-debugging-dotnet-core-linux-with-ssh?view=vs-2022&quot;&gt;SSH debugger&lt;/a&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;. The referenced article explains how it works &amp;ndash; but since we aimed to explore every&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;viable&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;option&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;,&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;it&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;worth noting that both JetBrains Rider and Visual Studio support SSH-based debugging. They use slightly different configurations, but the idea is the same &amp;ndash;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;establish&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;a tunnel over a specific&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;port, and&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; communicate bidirectionally about the execution process. Ideally, the deployed application should be built in Debug configuration (&lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;dotnet build --configuration Debug&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; and &quot;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;dotnet publish --configuration Debug&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;), so that symbol files &lt;em&gt;(&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;.pdb&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;) are included &amp;ndash; enabling the debugger to accurately map execution to source code.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;As an Optimizely Power User, you typically have access to three environments via the Azure Portal: Integration, Preproduction, and Production (sometimes also ADE1).&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;In my case, only the Integration environment exposed enough of the Web App&amp;rsquo;s configuration to investigate this directly. Since Preproduction and Production did not expose the Web App resource without Optimizely Support involvement, all debugging attempts focused on the Integration environment.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;While &lt;a title=&quot;Official Microsoft Documentation&quot; href=&quot;https://learn.microsoft.com/en-us/azure/app-service/resources-kudu&quot;&gt;Kudu&lt;/a&gt; allows basic SSH access to the instance, enabling remote debugging requires &lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;establishing&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;an SSH tunnel from the local environment. Ideally, the tunnel should be managed by Azure and connect directly to the Optimizely DXP environment &amp;ndash; avoiding&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;firewall&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; issues or potential security risks. Fortunately, Azure provides an out-of-the-box solution for this: &lt;a title=&quot;Official Microsoft Documentation&quot; href=&quot;https://learn.microsoft.com/en-us/azure/app-service/configure-linux-open-ssh-session?pivots=container-linux&quot;&gt;Open as SSH session to a container in Azure App&amp;nbsp;Service&lt;/a&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;. The documentation clearly outlines the necessary steps. Just ensure the &lt;a title=&quot;Official Microsoft Documentation&quot; href=&quot;https://learn.microsoft.com/en-us/cli/azure/install-azure-cli?view=azure-cli-latest&quot;&gt;Azure CLI is&amp;nbsp;installed&lt;/a&gt; &lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;and that&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;you&#39;ve&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; run &quot;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;az login&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; beforehand. Once you run &quot;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;az webapp create-remote-connection --subscription &amp;lt;subscription-id&amp;gt; --resource-group &amp;lt;resource-group-name&amp;gt; -n &amp;lt;app-name&amp;gt;&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;, the SSH tunnel to your instance will be active. Then, using your preferred SSH client, you can connect and gain shell access to the server &amp;ndash; just as described in the documentation.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;h3 class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Where the approach started to break down&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Encouraged by the successful SSH connection, I opened JetBrains Rider and&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;attempted&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;to &amp;ldquo;Attach to Remote Process&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;rdquo;.&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;After entering the local port of the SSH tunnel, I was prompted &amp;ndash; as expected &amp;ndash; with a message like &amp;ldquo;Your server&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;doesn&amp;rsquo;t&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;have the necessary files for debugging. Would you like to install them&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;?&amp;rdquo;.&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;I clicked &amp;ldquo;Yes&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;rdquo;.&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;The debugger tools downloaded successfully &amp;ndash; but the installation failed after just 1-2 MB were transferred to the server. No clear exception was shown; Rider simply displayed the same prompt again. Multiple retries led nowhere, so I started investigating the issue more closely. It turned out Rider was&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;attempting&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; to download and install the debugging tools by copying them over the SSH tunnel. The Kudu logs referenced a &quot;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;WebSocketException&quot;&amp;nbsp;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;(&lt;em&gt;The remote party closed the WebSocket connection without completing the close &lt;/em&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;&lt;em&gt;handshake.&lt;/em&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;), but&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; provided little else of value. I did confirm that Rider was uploading ZIP archives to the expected directory (&lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;~/.local/share/JetBrains/RiderRemoteDebugger/...&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;), but only partially &amp;ndash; the file sizes were well below the 100MB+ expected for full debugger tools. Naturally, trying to unzip a partially downloaded archive failed. At that point, it became clear we had two options: either upload the debugger archive via &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;scp&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;, or&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; download and install it directly from within the instance. Using &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;wget&quot;&lt;/em&gt;&amp;nbsp;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;was straightforward &amp;ndash; and it worked without issues.&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;I installed the Linux debugger tools matching the container architecture&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;(d&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;etails&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;a title=&quot;Official JetBrains Documentation&quot; href=&quot;https://www.jetbrains.com/help/rider/SSH_Remote_Debugging.html#-q06re1_143&quot;&gt;here&lt;/a&gt;) into the same directory where Rider had previously failed. The exact path may vary by Rider version, but&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;it&#39;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; typically something like &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;~/.local/share/JetBrains/RiderRemoteDebugger/...&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;. After installing &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;unzip&quot;&lt;/em&gt; &lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;(&lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;apt-get update &amp;amp;&amp;amp; apt-get install -y unzip&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;) and extracting the archive, I reached the&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;final step&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;: Rider was now able to list the running processes on the instance &amp;ndash; including my active .NET process.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;&lt;hr /&gt;
&lt;h3 class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Next attempt &amp;ndash; a&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;nd&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;one more&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;discovery&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;I clicked &lt;strong&gt;Attach&lt;/strong&gt;&amp;nbsp;again, however the same pattern reappeared: the connection was briefly&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;established&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;, then&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;immediately&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; closed. Kudu logs once again showed a &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;WebSocketException&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;, prompting me to investigate potential issues with the SSH connection itself. I decided to retry the file upload using &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;scp&quot;&lt;/em&gt;&amp;nbsp;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;myself &amp;ndash; this time with verbose logging &amp;ndash; to better understand what was happening. I started small: uploading an empty &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;test.txt&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; worked fine. A slightly larger file with a few lines of text &amp;ndash; also successful. But when &lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;attempting&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;to upload a larger file, I&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;encountered&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; a familiar error: &lt;strong&gt;broken pipe&lt;/strong&gt;. This pointed toward a &lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;likely culprit&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;: some form of bandwidth limitation.&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;So&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; I tried uploading the file with bandwidth throttling enabled:&lt;em&gt; &quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;scp&amp;nbsp;-vvv&amp;nbsp;-o MACs=hmac-sha1 -P &amp;lt;port&amp;gt; -l 8192 &quot;debugger-file.zip&quot;&amp;nbsp;root@127.0.0.1:~/.local/share/JetBrains/RiderRemoteDebugger/...&quot;&amp;nbsp;&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;That worked. My colleague and I reproduced the behavior on multiple machines, which made a purely client-side explanation less likely.&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;The remaining question was: how can we enforce the same throttling for JetBrains Rider&amp;rsquo;s automatic upload process?&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;And&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;here&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;the tricky part: the SSH connection is managed by Azure, leaving little room for server-side customization. I briefly considered&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;terminating&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;the existing SSH server and launching a custom one with modified settings &amp;ndash; but OpenSSH&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;doesn&amp;rsquo;t&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;offer the necessary configuration flexibility, and interfering with the managed Azure/Optimizely infrastructure&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;wasn&amp;rsquo;t&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;a viable&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;option&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;. My next attempt involved using &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;tc&quot;&lt;/em&gt;&amp;nbsp;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;(traffic control) on the server to limit bandwidth, matching the constraint&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;I&amp;rsquo;d&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; used with &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;scp&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;. However, even the&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;initial&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; setup command &amp;ndash; &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;tc&amp;nbsp;qdisc&amp;nbsp;add dev $IFACE root handle 1:&amp;nbsp;htb default 30&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; &amp;ndash; failed with a &lt;strong&gt;Permission &lt;/strong&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;&lt;strong&gt;denied&lt;/strong&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; error. A quick check using &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;capsh&amp;nbsp;--print | grep&amp;nbsp;cap_net_admin&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;confirmed it: I&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;didn&amp;rsquo;t&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;have the required capabilities &amp;ndash; and that was the end of that path.&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Realizing that tools like trickle or other ad hoc bandwidth limiters would&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;likely interfere&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;with the existing setup, I shifted focus&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;to throttling the connection from the client side. On Windows, I experimented with built-in QoS policies to throttle traffic &amp;ndash; but it&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;didn&amp;rsquo;t&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;help. Rider continued to disconnect shortly after starting the debugger, and the issue&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;remained&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;&lt;hr /&gt;&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;h3 class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Eliminating&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;concerns, or what else was tried&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/h3&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;1.&amp;nbsp;&lt;strong&gt;SFTP&lt;/strong&gt;. Some resources mention SFTP as a requirement for remote debugging, raising concerns about whether&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;it&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; enabled in the Optimizely setup. It is. You can confirm this either in the Azure Portal or by running &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;grep sftp /etc/ssh/sshd_config&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;. Any output&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;indicates&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;it&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;active &amp;ndash; and&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;that&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;sufficient.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;2. &lt;strong&gt;Release vs. Debug&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;&lt;strong&gt;configurations.&lt;/strong&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;I tested both build modes to rule out any mismatch &amp;ndash; same result in both cases. The issues persisted regardless of configuration.&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;That may have been the next problem if the SSH issue had been resolved, but I did not get far enough to prove it&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;3. &lt;strong&gt;Azure&amp;rsquo;s &amp;ldquo;Remote Debugging Enabled&amp;rdquo;&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;&lt;strong&gt;flag.&lt;/strong&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;I did not find this useful for the .NET on Linux scenario tested here&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;In this setup,&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;it was not applicable here and also interfered with SSH access, as both rely on port&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;2222&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; Still, if you want to experiment, you can toggle it using the following commands: &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;az webapp config set --resource-group &amp;lt;resource-group&amp;gt; -n &amp;lt;webapp-name&amp;gt; --remote-debugging-enabled=true&quot; &lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;and to roll-back&lt;em&gt; &quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;az webapp config set --resource-group &amp;lt;resource-group&amp;gt; -n &amp;lt;webapp-name&amp;gt; --remote-debugging-enabled=false&quot;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;. Even if not useful for this scenario, the output of these commands is worth exploring &amp;ndash; Azure exposes a surprisingly rich ARM definition of your Web App.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;4. &lt;strong&gt;What about Visual&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;&lt;strong&gt;Studio?&lt;/strong&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;As expected, I&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;gave it a try&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&amp;ndash; but the results were even worse. Visual Studio refused the SSH connection entirely and exited with the&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;message:&amp;nbsp;&lt;/span&gt;&lt;em&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&quot;Connectivity Failure: Please make sure host name and port number are correct&lt;/span&gt;&lt;/em&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;&lt;em&gt;.&quot;&lt;/em&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;No&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;additional&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;context was provided, leaving me guessing what might&amp;rsquo;ve gone wrong&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;.&amp;nbsp;&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Throughout this process, I&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;monitored&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;Kudu logs in parallel. While some error entries did appear, they&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;weren&amp;rsquo;t&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; particularly helpful &amp;ndash; mostly the same &lt;em&gt;&quot;&lt;/em&gt;&lt;/span&gt;&lt;/span&gt;&lt;em&gt;WebSocketException&quot;&amp;nbsp;&lt;/em&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;patterns I saw when using Rider. One thing was clear: Visual Studio recognized the SSH tunnel. When another connection was already active, it would wait and only fail once the other connection was released &amp;ndash; confirming awareness of the underlying channel, even if it&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;couldn&amp;rsquo;t&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;use it properly.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;5. &lt;strong&gt;Limit bandwidth from Rider&amp;nbsp;&lt;/strong&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;&lt;strong&gt;directly?&lt;/strong&gt;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;I checked&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Rider&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;available&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;settings, but&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;found no built-in way to throttle the SSH transfer rate.&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;It&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;possible that using a proxy or a more advanced traffic-shaping setup could help &amp;ndash; but investigating that path would take&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;considerably more&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;time, with no guaranteed payoff. At this point, I made&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;the&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;call to stop here.&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; Remaining options required more time with no clear path to a reliable result.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;hr /&gt;
&lt;h3 class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Final Observations&lt;/span&gt;&lt;/span&gt;&lt;/h3&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;I&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;attempted&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;to connect to the instance&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;overnight, when&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;I expected activity in Integration to be minimal.&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;Interestingly, the debugger connection held for nearly 10 seconds, longer than any of the daytime attempts, before ultimately failing again.&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;Bandwidth-related limits or instability seem like the most plausible explanation from these tests, though I could not prove that definitively or&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;rule out other&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;blockers&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;At this point,&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;it&amp;rsquo;s&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;worth stepping back and looking at the outcome&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;more practically&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;Optimizely&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;DXP is a managed platform, and remote debugging is not a workflow it currently exposes or documents directly&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;. That makes the result expected &amp;ndash; but the path to that understanding is not always obvious when you start.&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;For developers working with complex systems, the question itself still comes up. This exploration&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;doesn&amp;rsquo;t&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;change the&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;platform&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;behavior, but it does make the current boundaries clearer: what can be&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;attempted&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;, what partially works, and where things start to break down in practice.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;OutlineElement Ltr SCXW248700128 BCX8&quot;&gt;
&lt;p class=&quot;Paragraph SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;TextRun SCXW248700128 BCX8&quot;&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;If nothing else, this should save time for anyone approaching the same&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;idea&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt; &amp;ndash; and provide a more concrete starting point&lt;/span&gt;&lt;span class=&quot;NormalTextRun ContextualSpellingAndGrammarErrorV2Themed SCXW248700128 BCX8&quot;&gt;, should&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;&amp;nbsp;you decide to take it&amp;nbsp;&lt;/span&gt;&lt;span class=&quot;NormalTextRun SCXW248700128 BCX8&quot;&gt;further.&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;EOP Selected SCXW248700128 BCX8&quot;&gt;&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;</id><updated>2026-04-20T08:45:18.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>