<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by Keshav Dave</title><link href="http://world.optimizely.com" /><updated>2026-02-15T17:16:37.0000000Z</updated><id>https://world.optimizely.com/blogs/keshav-dave/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Architecting AI in Optimizely CMS: When to Use Opal vs Custom Integration</title><link href="https://world.optimizely.com/blogs/keshav-dave/dates/2026/2/architecting-ai-in-optimizely-cms-when-to-use-opal-vs-custom-integration/" /><id>&lt;p&gt;AI is rapidly becoming a core capability in modern digital experience platforms. As developers working with &lt;span class=&quot;hover:entity-accent entity-underline inline cursor-pointer align-baseline&quot;&gt;&lt;span class=&quot;whitespace-normal&quot;&gt;Optimizely&lt;/span&gt;&lt;/span&gt; CMS 12 (.NET Core), the real question is no longer:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;Can we integrate AI?&amp;rdquo;&lt;br /&gt;&lt;br /&gt;&lt;/strong&gt;But rather:&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&amp;ldquo;What is the right architectural approach for AI inside Optimizely?&amp;rdquo;&lt;br /&gt;&lt;br /&gt;&lt;/strong&gt;In this article, I&amp;rsquo;ll share practical implementation patterns, lessons learned, and how to decide between custom AI integration and leveraging Opal.&lt;strong&gt;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;h2&gt;Why AI Integration Matters in CMS Implementations&lt;/h2&gt;
&lt;p&gt;Across multiple implementations, I&amp;rsquo;ve observed recurring challenges:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Manual metadata tagging&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Inconsistent summaries and SEO descriptions&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Static personalization logic&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Slow campaign iteration cycles&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Limited experimentation insights&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI, when architected correctly, can significantly enhance these areas - without disrupting core CMS performance.&lt;/p&gt;
&lt;h2&gt;Option 1: Custom AI Integration in Optimizely CMS 12&lt;/h2&gt;
&lt;p&gt;For organizations requiring flexibility and control, integrating external AI services (e.g., Azure OpenAI or private ML models) remains a powerful option.&lt;/p&gt;
&lt;h3&gt;Recommended Architecture&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Editor &amp;rarr; CMS &amp;rarr; AI Service Layer &amp;rarr; External AI Provider&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 1: Introduce an Abstraction Layer&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public interface IAIContentService
{
    Task&amp;lt;string&amp;gt; GenerateSummaryAsync(string content);
    Task&amp;lt;List&amp;lt;string&amp;gt;&amp;gt; GenerateTagsAsync(string content);
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This ensures your CMS remains provider-agnostic.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 2: Register via Dependency Injection&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddHttpClient&amp;lt;IAIContentService, AIContentService&amp;gt;();
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Keep AI logic outside controllers and content models. Treat it as infrastructure.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Step 3: Hook into CMS Events&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Example: Auto-tag content during publishing.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;_contentEvents.PublishingContent += async (sender, args) =&amp;gt;
{
    if (args.Content is ArticlePage page)
    {
        var tags = await _aiService.GenerateTagsAsync(page.MainBody.ToHtmlString());
        page.Tags = tags;
    }
};
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&lt;strong&gt;Important Considerations&lt;/strong&gt;&lt;/h3&gt;
&lt;h3&gt;Performance&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Never execute AI calls during page rendering.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use background jobs or publish-time triggers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Cache generated outputs.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Security&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Store API keys in secure vaults.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid exposing AI endpoints client-side.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Prompt Governance&lt;/h3&gt;
&lt;p&gt;Treat prompts like code:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Version them&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Document them&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Test them&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Option 2: Leveraging Opal&lt;/h2&gt;
&lt;p&gt;Opal introduces AI natively within the Optimizely ecosystem.&lt;/p&gt;
&lt;p&gt;Rather than building infrastructure from scratch, Opal enables:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;AI-assisted content creation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Campaign generation&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Intelligent experimentation insights&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Workflow-level automation&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From a developer perspective, Opal reduces:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Integration complexity&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maintenance overhead&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Governance concerns&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It shifts AI from being API-driven to being workflow-native.&lt;/p&gt;
&lt;h2&gt;Architectural Decision: Opal vs Custom AI&lt;/h2&gt;
&lt;p&gt;In enterprise implementations, the decision should be strategic.&lt;/p&gt;
&lt;table style=&quot;border-collapse: collapse; width: 100.033%; height: 117.563px;&quot;&gt;
&lt;tbody&gt;
&lt;tr style=&quot;height: 19.5938px;&quot;&gt;
&lt;td style=&quot;height: 19.5938px; text-align: left;&quot;&gt;&lt;strong&gt;Criteria&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px; text-align: left;&quot;&gt;&lt;strong&gt;Opal&lt;/strong&gt;&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px; text-align: left;&quot;&gt;&lt;strong&gt;Custom Integration&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19.5938px;&quot;&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Speed to Market&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;High&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19.5938px;&quot;&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Full AI Control&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Medium&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;High&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19.5938px;&quot;&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Maintenance&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Low&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Higher&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19.5938px;&quot;&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Compliance Control&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Managed&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Self-managed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr style=&quot;height: 19.5938px;&quot;&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Custom ML Use Cases&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Limited&lt;/td&gt;
&lt;td style=&quot;height: 19.5938px;&quot;&gt;Strong&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;div class=&quot;TyagGW_tableContainer&quot;&gt;
&lt;div class=&quot;group TyagGW_tableWrapper flex flex-col-reverse w-fit&quot;&gt;
&lt;h3&gt;Recommended Enterprise Approach&lt;/h3&gt;
&lt;p&gt;In most scenarios, I recommend a hybrid model:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use Opal for editor productivity and campaign acceleration.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use custom AI integration for domain-specific business logic.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Keep AI infrastructure modular and loosely coupled.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This ensures flexibility without overengineering.&lt;/p&gt;
&lt;h2&gt;Designing AI-Ready Content Models&lt;/h2&gt;
&lt;p&gt;Regardless of approach, structure matters.&lt;/p&gt;
&lt;p&gt;Best practices:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Avoid storing critical data in large RichText blobs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Use structured properties.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maintain clean content types.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Align metadata fields for AI enrichment.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;AI works best with well-structured data.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;Final Thoughts:-&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;AI in &lt;span class=&quot;hover:entity-accent entity-underline inline cursor-pointer align-baseline&quot;&gt;&lt;span class=&quot;whitespace-normal&quot;&gt;Optimizely&lt;/span&gt;&lt;/span&gt; CMS should not be treated as a feature toggle.&lt;/p&gt;
&lt;p&gt;It is an architectural layer.&lt;/p&gt;
&lt;p&gt;As developers and architects, our responsibility is to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Protect performance&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Maintain security&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Ensure maintainability&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deliver business value&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whether through custom services or via Opal, the goal remains the same:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Build intelligent, scalable digital experiences. :)&lt;/strong&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2026-02-15T17:16:37.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Designing Scalable Catalog Structures in Optimizely Commerce</title><link href="https://world.optimizely.com/blogs/keshav-dave/dates/2025/8/designing-scalable-catalog-structures-in-optimizely-commerce/" /><id>&lt;p&gt;In any eCommerce solution, the &lt;strong&gt;catalog is the backbone&lt;/strong&gt; of the digital experience. A well-designed catalog structure in Optimizely Commerce ensures &lt;strong&gt;fast performance, easy management, and a smooth customer journey&lt;/strong&gt; &amp;mdash; while a poorly designed one can lead to slow searches, frustrated merchandisers, and scalability challenges as the business grows.&lt;/p&gt;
&lt;p&gt;In this article, we&amp;rsquo;ll explore how to design &lt;strong&gt;scalable catalog structures&lt;/strong&gt; in Optimizely Commerce, the key considerations, and best practices learned from projects.&lt;/p&gt;
&lt;h2&gt;Why Catalog Design Matters&lt;/h2&gt;
&lt;p&gt;Optimizely Commerce can handle &lt;strong&gt;thousands &lt;/strong&gt;&lt;strong&gt;of SKUs&lt;/strong&gt;, but the way you structure your catalog directly impacts:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt; &amp;rarr; Faster search, indexing, and page load times.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;User Experience&lt;/strong&gt; &amp;rarr; Easier navigation, better filtering, fewer clicks.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SEO&lt;/strong&gt; &amp;rarr; Clean URLs, optimized category hierarchies, breadcrumb trails.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Maintainability&lt;/strong&gt; &amp;rarr; Simpler workflows for merchandisers and admins.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt; &amp;rarr; Ability to expand into new markets, product lines, or currencies without restructuring.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Example structure:&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;Catalog: Fashion Store  
 └── Category: Men&amp;rsquo;s Clothing  
      └── Product: Oxford Shirt  
           ├── Variant: Blue, Size M  
           ├── Variant: Blue, Size L  
           └── Variant: White, Size M &lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Catalog Design Considerations for Scalability&lt;/h2&gt;
&lt;p&gt;When structuring your catalog, keep in mind:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Performance&lt;/strong&gt; &amp;ndash; Large categories with thousands of items can slow down queries.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Navigation &amp;amp; UX&lt;/strong&gt; &amp;ndash; Customers should reach products in &lt;strong&gt;3&amp;ndash;4 clicks max&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;SEO&lt;/strong&gt; &amp;ndash; URLs and breadcrumbs should reflect clean hierarchies.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Admin Usability&lt;/strong&gt; &amp;ndash; Merchandisers need intuitive structures.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Localization&lt;/strong&gt; &amp;ndash; Plan for &lt;strong&gt;multi-language, multi-market, multi-currency&lt;/strong&gt; setups.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Common Catalog Design Patterns&lt;/h2&gt;
&lt;h3&gt;1. Single vs Multi-Catalog&lt;/h3&gt;
&lt;p&gt;=&amp;gt; &lt;strong&gt;Diagram: Single vs Multi-Catalog&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Single Catalog (Recommended for most cases):&amp;nbsp;&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;Catalog Root
 ├── Men&amp;rsquo;s Clothing
 ├── Women&amp;rsquo;s Clothing
 ├── Footwear
 └── Accessories&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Multi-Catalog (When business models differ):&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;B2C Catalog
 ├── Men&amp;rsquo;s Clothing
 ├── Women&amp;rsquo;s Clothing

B2B Catalog
 ├── Bulk Apparel
 ├── Corporate Footwear&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;=&amp;gt;&lt;/strong&gt; &lt;/strong&gt;Start with a single catalog unless you have strong business reasons (different assortments, B2B vs B2C).&lt;/p&gt;
&lt;h3&gt;2. Flat vs Deep Category Hierarchies&lt;/h3&gt;
&lt;p&gt;=&amp;gt; &lt;strong&gt;Diagram: Catalog Hierarchies&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Flat Catalog (Simpler, but wide categories):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;Fashion Store
 ├── Shirts (500 SKUs)
 ├── Pants (400 SKUs)
 ├── Shoes (6,000 SKUs)
 └── Accessories (3,000 SKUs)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Deep Catalog (Organized):&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;Fashion Store
 └── Men&amp;rsquo;s Clothing
      └── Tops
           └── Shirts (1,000 SKUs)
      └── Bottoms
           └── Pants (800 SKUs)
 └── Footwear
      ├── Casual Shoes (2,000 SKUs)
      ├── Formal Shoes (1,500 SKUs)
      └── Sports Shoes (2,500 SKUs)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;&lt;strong&gt;&amp;nbsp;Best Practice:&lt;/strong&gt; &lt;/strong&gt;Keep category depth&lt;strong&gt; &lt;strong&gt;2-3 levels max&lt;/strong&gt; &lt;/strong&gt;and balance the size of each category.&lt;/p&gt;
&lt;h3&gt;3. Product vs Variant Modeling&lt;/h3&gt;
&lt;p&gt;=&amp;gt; &lt;strong&gt;Diagram: Product &amp;rarr; Variants&lt;br /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-html&quot;&gt;&lt;code&gt;Product: Shirt
 ├── Variant: Blue, Size M
 ├── Variant: Blue, Size L
 ├── Variant: White, Size M
 └── Variant: White, Size L&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;Code Example: Defining Product &amp;amp; Variants&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[CatalogContentType(
    DisplayName = &quot;Shirt Product&quot;,
    GUID = &quot;630CB424-945B-48F3-9116-C8E15C8B1E0D&quot;,
    MetaClassName = &quot;ShirtProduct&quot;)]
public class ShirtProduct : ProductContent
{
    [Display(Name = &quot;Brand&quot;)]
    public virtual string Brand { get; set; }

    [Display(Name = &quot;Material&quot;)]
    public virtual string Material { get; set; }
}

[CatalogContentType(
    DisplayName = &quot;Shirt Variant&quot;,
    GUID = &quot;2B586ABE-1646-4140-8E3E-7FEE3398E440&quot;,
    MetaClassName = &quot;ShirtVariant&quot;)]
public class ShirtVariant : VariationContent
{
    [Display(Name = &quot;Color&quot;)]
    public virtual string Color { get; set; }

    [Display(Name = &quot;Size&quot;)]
    public virtual string Size { get; set; }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Use &lt;strong&gt;variants&lt;/strong&gt; for attributes like size and color; use &lt;strong&gt;separate products&lt;/strong&gt; when items differ significantly or need unique SEO pages.&lt;/p&gt;
&lt;h3&gt;4. Associations for Better Cross-Sell&lt;/h3&gt;
&lt;p&gt;Use associations to improve &lt;strong&gt;average order value :&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Accessories &amp;rarr; Phone &amp;rarr; Case, Charger.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Up-sell &amp;rarr; Laptop &amp;rarr; Higher model with more RAM.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Replacement &amp;rarr; Printer &amp;rarr; Ink cartridge.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This avoids catalog duplication while enabling personalization.&lt;/p&gt;
&lt;h2&gt;Performance Optimization Techniques&lt;/h2&gt;
&lt;p&gt;Even the best catalog design needs &lt;strong&gt;performance tuning&lt;/strong&gt;:&lt;/p&gt;
&lt;h3&gt;1. Search (Optimizely Find)&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use synonyms (&lt;em&gt;t-shirt&lt;/em&gt; = &lt;em&gt;tee&lt;/em&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Boost by category or sales.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Avoid unfiltered queries on huge categories.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;Code Example: Boosting Search Results&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var results = _searchClient
    .Search&amp;lt;ShirtVariant&amp;gt;()
    .For(&quot;blue shirt&quot;)
    .InFields(x =&amp;gt; x.Name, x =&amp;gt; x.Color, x =&amp;gt; x.Size)
    .Filter(x =&amp;gt; x.Color.Match(&quot;Blue&quot;))
    .OrderByDescending(x =&amp;gt; x.MarketPopularity) // Boost popular products
    .Take(20)
    .GetResult();
&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;&amp;nbsp; 2. Caching&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;strong&gt;output caching&lt;/strong&gt; for product/category pages.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Implement &lt;strong&gt;distributed caching&lt;/strong&gt; (e.g., Redis) in high-traffic environments.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&amp;nbsp; 3. Lazy Loading&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Load related products/variants only when needed.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&amp;nbsp; 4. Batch Operations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;Use&amp;nbsp;&lt;strong&gt;bulk APIs&lt;/strong&gt; for imports and updates instead of looping item-by-item.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Best Practices&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Keep categories &lt;strong&gt;logical &amp;amp; balanced&lt;/strong&gt; (avoid dumping 10,000+ items into a single category).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Don&amp;rsquo;t duplicate products &amp;mdash; use &lt;strong&gt;associations&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Plan for &lt;strong&gt;future expansion&lt;/strong&gt; (new markets, currencies, or product lines).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Regularly &lt;strong&gt;test indexing&lt;/strong&gt; performance for large catalogs in Find.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Designing a scalable catalog in Optimizely Commerce is not just about organizing products &amp;mdash; it&amp;rsquo;s about creating a &lt;strong&gt;foundation for performance, SEO, and long-term growth&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;Thanks :)&lt;/p&gt;</id><updated>2025-08-25T11:57:57.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>How to Create Custom Audience Criteria for Mobile Visitors in Optimizely CMS</title><link href="https://world.optimizely.com/blogs/keshav-dave/dates/2025/8/how-to-create-custom-audience-criteria-for-mobile-visitors-in-optimizely-cms/" /><id>&lt;p&gt;Personalization is one of the most powerful features of &lt;strong&gt;Optimizely CMS&lt;/strong&gt;. By tailoring content to specific audiences, you can significantly improve engagement, conversions, and user satisfaction.&lt;/p&gt;
&lt;p&gt;One common scenario is &lt;strong&gt;detecting mobile visitors&lt;/strong&gt; and delivering a more mobile-friendly experience. While Optimizely provides built-in groups (like geographic location, referral, etc.), sometimes you need to define &lt;strong&gt;custom audience criteria&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;In this blog, I&amp;rsquo;ll walk you through how to create a &lt;strong&gt;Custom Audience Criterion&lt;/strong&gt; that detects whether the user is browsing on a mobile device &amp;mdash; and then use it in Optimizely&amp;rsquo;s personalization engine.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;h2&gt;Why Mobile-Specific Criteria?&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Business value&lt;/strong&gt;: Mobile visitors may need faster-loading content, simplified layouts, or exclusive mobile offers.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Developer flexibility&lt;/strong&gt;: Built-in rules may not be enough; a custom criterion lets you define exactly what &amp;ldquo;mobile&amp;rdquo; means for your site.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scalability&lt;/strong&gt;: Once built, the same rule can be reused across campaigns, promotions, and personalized content blocks.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step 1: Create a Custom Criterion Model&lt;/h2&gt;
&lt;p&gt;Every custom audience criterion in Optimizely starts with a &lt;strong&gt;model class&lt;/strong&gt; that defines its settings. For our mobile visitor detection, the model is simple (no extra configuration needed):&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using EPiServer.Personalization.VisitorGroups;

namespace MySite.Business.VisitorGroups
{
    public class MobileVisitorModel : CriterionModelBase
    {
        // No custom properties needed for now
        public override ICriterionModel Copy()
        {
            return base.ShallowCopy();
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Step 2: Create the Criterion Logic&lt;/h2&gt;
&lt;p&gt;Now we define the actual &lt;strong&gt;evaluation logic&lt;/strong&gt; by implementing &lt;code&gt;CriterionBase&amp;lt;T&amp;gt;&lt;/code&gt;.&lt;br /&gt;Here we&amp;rsquo;ll check the &lt;code&gt;User-Agent&lt;/code&gt; string to detect mobile devices.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using System;
using System.Web;
using EPiServer.Personalization.VisitorGroups;

namespace MySite.Business.VisitorGroups
{
    [VisitorGroupCriterion(
        Category = &quot;Device&quot;,
        DisplayName = &quot;Mobile Visitor&quot;,
        Description = &quot;Checks if the visitor is using a mobile device&quot;)]
    public class MobileVisitorCriterion : CriterionBase&amp;lt;MobileVisitorModel&amp;gt;
    {
        public override bool IsMatch(IPrincipal principal, HttpContextBase httpContext)
        {
            if (httpContext?.Request?.UserAgent == null)
                return false;

            string userAgent = httpContext.Request.UserAgent.ToLower();

            // A very simplified check for mobile devices
            return userAgent.Contains(&quot;iphone&quot;) ||
                   userAgent.Contains(&quot;android&quot;) ||
                   userAgent.Contains(&quot;ipad&quot;) ||
                   userAgent.Contains(&quot;mobile&quot;);
        }
    }
}
&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;VisitorGroupCriterion&lt;/code&gt; attribute makes it available in the Optimizely UI.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;IsMatch&lt;/code&gt; decides if the visitor meets the condition (mobile browsing).&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;We used a simple &lt;code&gt;User-Agent&lt;/code&gt; check, but you can extend this with a more robust device detection library.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Step 3: Create &amp;amp; Use in Visitor Groups&lt;/h2&gt;
&lt;p&gt;Once deployed:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Go to &lt;strong&gt;CMS Admin -&amp;gt; Audience&lt;/strong&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&amp;nbsp;Create Audience and choose &lt;strong&gt;Mobile Visitor&lt;/strong&gt; from the criteria list.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Combine it with other rules (e.g. &lt;em&gt;Mobile + Returning Visitor&lt;/em&gt;).&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;&lt;img src=&quot;/link/5a0fd118cd534ec88b2492d6a0e50e55.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;4. Assign this visitor group to personalized content blocks, banners, or promotions.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/ebe6b5b5525049a3813caa00cba86707.aspx&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Step 4: Testing&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Use &lt;strong&gt;browser dev tools&lt;/strong&gt; to switch device mode and test different User-Agent strings.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Deploy to staging and validate across real devices.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Monitor analytics (Optimizely Experimentation + Google Analytics) to measure engagement lift.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;- By creating a custom&amp;nbsp;Mobile Visitor criterion, you can:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Deliver targeted, device-aware experiences.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Go beyond default visitor groups.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Set up scalable personalization strategies in Optimizely CMS.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Personalization in Optimizely is all about &lt;strong&gt;meeting users where they are&lt;/strong&gt;. With custom audience criteria, the possibilities are endless.&lt;/p&gt;
&lt;p&gt;:) Thanks!&lt;/p&gt;</id><updated>2025-08-19T11:39:25.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>