<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by AllThingsOpti</title><link href="http://world.optimizely.com" /><updated>2025-05-30T14:46:33.0000000Z</updated><id>https://world.optimizely.com/blogs/allthingsopti/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>A day in the life of an Optimizely Developer - How Optimizely Opal AI transforms marketing operations with infinite scale</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2025/5/a-day-in-the-life-of-an-optimizely-developer---how-optimizely-opal-ai-transforms-marketing-operations-with-infinite-scale/" /><id>&lt;p class=&quot;whitespace-normal break-words&quot;&gt;In May 2025, Optimizely revolutionized its AI capabilities with the next evolution of Opal, delivering what the company calls an &quot;infinitely scalable workforce&quot; for marketing teams. This isn&#39;t just another AI tool&amp;mdash;it&#39;s the industry&#39;s first AI assistant built from the ground up specifically for marketing.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The significance extends beyond impressive metrics. As businesses face mounting pressure to deliver more content, run more experiments, and personalize more experiences with flat or shrinking budgets, Opal AI represents a fundamental shift in how marketing operations scale.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;What makes Opal particularly compelling is its deep integration across the entire Optimizely One platform&amp;mdash;from content management to experimentation to personalization. Unlike standalone AI tools that require complex integrations, Opal works seamlessly within existing marketing workflows, powered by Google&#39;s advanced Gemini models and backed by Optimizely&#39;s decade of domain expertise. For business leaders evaluating AI investments, understanding Opal&#39;s comprehensive capabilities and proven ROI becomes essential for competitive positioning in an increasingly AI-driven market.&lt;/p&gt;
&lt;h2 class=&quot;text-xl font-bold text-text-100 mt-1 -mb-0.5&quot;&gt;The evolution from AI features to agentic workflows&lt;/h2&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Traditional marketing AI tools typically offer isolated features&amp;mdash;generate a blog post here, optimize an email subject line there. Opal fundamentally reimagines this approach through what Optimizely calls &quot;agentic AI,&quot; where specialized AI agents work together to complete complex, multi-step marketing workflows.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Consider a typical product launch campaign. Previously, teams would spend weeks coordinating between content creators, campaign managers, and analysts. With Opal&#39;s agentic workflows, &lt;strong&gt;specialized agents handle distinct tasks simultaneously&lt;/strong&gt;: one agent develops the campaign brief based on brand guidelines and past performance data, another creates multi-channel content variations, while a third sets up experimentation frameworks to test messaging effectiveness. These agents don&#39;t work in isolation&amp;mdash;they share context and coordinate efforts, much like a well-orchestrated human team.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The platform&#39;s &lt;strong&gt;persistent chat interface&lt;/strong&gt; maintains conversation history across all interactions, ensuring continuity as teams move between tasks. This contextual awareness proves particularly valuable when dealing with complex campaigns that evolve over time. Marketing teams report that Opal remembers previous decisions, brand preferences, and performance insights, eliminating the need to repeatedly provide the same information.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;What truly distinguishes Opal is its &lt;strong&gt;brand-aware intelligence&lt;/strong&gt;. The system ingests company-specific data including brand guidelines, visual assets, historical campaign performance, and customer insights. This deep contextual understanding means generated content aligns with brand voice without constant human oversight.&lt;/p&gt;
&lt;h2 class=&quot;text-xl font-bold text-text-100 mt-1 -mb-0.5&quot;&gt;How specialized AI agents revolutionize marketing workflows&lt;/h2&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The technical architecture behind Opal&#39;s success centers on its specialized agent system. Rather than relying on a single, general-purpose AI, Opal deploys &lt;strong&gt;purpose-built agents&lt;/strong&gt; for specific marketing functions. This specialization enables superior performance compared to generic AI tools.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The &lt;strong&gt;Content Creation Agent&lt;/strong&gt; understands nuanced brand voice and can generate everything from social media posts to long-form thought leadership articles. It doesn&#39;t just write&amp;mdash;it strategizes, suggesting content angles based on trending topics and historical performance data. Marketing teams report that this agent reduces brief-to-publish time from days to hours.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The &lt;strong&gt;Experimentation Agent&lt;/strong&gt; transforms how teams approach testing. It analyzes past experiments to suggest hypotheses, automatically creates test variations, and provides real-time insights as data accumulates. One particularly powerful feature is its ability to &lt;strong&gt;dynamically allocate traffic&lt;/strong&gt; to winning variations, maximizing the value of every visitor. Companies using this agent report running 3-4x more experiments with the same team resources.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The &lt;strong&gt;Campaign Orchestration Agent&lt;/strong&gt; manages complex, multi-channel campaigns from inception to completion. It coordinates between different marketing channels, ensures consistent messaging, and automatically adjusts tactics based on performance data. This agent essentially functions as an AI-powered campaign manager that never sleeps.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The &lt;strong&gt;Analytics Agent&lt;/strong&gt; democratizes data insights across the organization. Team members can ask questions in natural language&amp;mdash;&quot;What drove last quarter&#39;s conversion spike?&quot; or &quot;Which content themes resonate with enterprise buyers?&quot;&amp;mdash;and receive instant, actionable answers. This eliminates the bottleneck of waiting for analyst resources and enables data-driven decision-making at every level.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;These agents work together through Opal&#39;s &lt;strong&gt;agentic workflow&lt;/strong&gt; system.&amp;nbsp;For instance, when launching a new product feature, the Content Creation Agent might develop announcement materials while the Experimentation Agent simultaneously sets up A/B tests for different messaging approaches. The Campaign Orchestration Agent coordinates the rollout across channels, and the Analytics Agent monitors performance in real-time, feeding insights back to optimize ongoing efforts.&lt;/p&gt;
&lt;h2 class=&quot;text-xl font-bold text-text-100 mt-1 -mb-0.5&quot;&gt;Implementation strategies for maximum ROI&lt;/h2&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Organizations achieving the highest returns from Opal follow a structured implementation approach that balances quick wins with long-term transformation. The most successful deployments begin with focused pilot programs before expanding to enterprise-wide adoption.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Critical success factors include &lt;strong&gt;executive sponsorship&lt;/strong&gt; to drive adoption, &lt;strong&gt;clear use case prioritization&lt;/strong&gt; to demonstrate value quickly, and &lt;strong&gt;ongoing optimization&lt;/strong&gt; of agent instructions based on performance. Organizations that treat Opal as a strategic platform rather than a tactical tool report significantly better outcomes.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Common implementation challenges include initial resistance from team members concerned about AI replacing their roles. Successful organizations address this by positioning Opal as an enhancement to human creativity rather than a replacement.&lt;/p&gt;
&lt;h2 class=&quot;text-xl font-bold text-text-100 mt-1 -mb-0.5&quot;&gt;Competitive advantages in an AI-driven market&lt;/h2&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Optimizely&#39;s market position reflects both its technological capabilities and strategic vision. The company holds leadership positions in multiple 2025 Gartner Magic Quadrants, including &lt;strong&gt;eight consecutive years&lt;/strong&gt; as a leader in Content Marketing Platforms. This sustained recognition indicates not just current capabilities but consistent innovation over time.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Compared to traditional marketing platforms adding AI features as an afterthought, Opal&#39;s ground-up AI design provides distinct advantages. The platform&#39;s &lt;strong&gt;context windows&lt;/strong&gt;&amp;mdash;its ability to consider vast amounts of relevant information when generating content or making recommendations&amp;mdash;exceed most competitors. This translates to more nuanced, accurate outputs that require less human editing.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Against pure-play AI writing tools, Opal&#39;s integration advantage becomes clear. While standalone tools might generate decent content, they lack the connectivity to experimentation data, customer insights, and performance metrics that make Opal&#39;s outputs strategically valuable. A blog post created by Opal doesn&#39;t just read well&amp;mdash;it&#39;s optimized based on what has actually driven conversions for that specific business.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The platform&#39;s &lt;strong&gt;credit-based pricing model&lt;/strong&gt;, introduced in May 2025, provides cost predictability while allowing organizations to scale usage based on need. This approach proves more economical than hiring additional staff or engaging agencies for routine content creation and campaign management tasks.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Perhaps most importantly, Opal&#39;s position within the broader Optimizely One ecosystem creates compounding value. Organizations using Opal alongside Optimizely&#39;s experimentation, personalization, and content management capabilities report synergies that amplify ROI.&amp;nbsp;For instance, content created by Opal can be automatically tested through the experimentation platform, with winning variations feeding back to improve future AI outputs.&lt;/p&gt;
&lt;h2 class=&quot;text-xl font-bold text-text-100 mt-1 -mb-0.5&quot;&gt;Future-proofing marketing operations&lt;/h2&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The marketing technology landscape continues evolving rapidly, with AI capabilities advancing at an unprecedented pace. Optimizely&#39;s roadmap for Opal suggests several developments that will further transform marketing operations.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;&lt;strong&gt;Enhanced personalization capabilities&lt;/strong&gt; will enable Opal to create individualized content at massive scale. Rather than segments, marketers will target individuals with AI-generated content tailored to specific preferences, behaviors, and contexts.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;&lt;strong&gt;Multimodal content generation&lt;/strong&gt; represents another frontier. Future Opal versions will seamlessly create and optimize visual content, videos, and interactive experiences, not just text. This expansion addresses the growing importance of visual storytelling in modern marketing.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The platform&#39;s &lt;strong&gt;predictive capabilities&lt;/strong&gt; will also expand, moving beyond analyzing past performance to forecasting future outcomes. Marketers will receive AI-powered recommendations about which campaigns to run, when to launch them, and how to allocate budgets for maximum impact.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Industry trends suggest that by 2027, AI-powered marketing platforms like Opal will handle the majority of routine marketing tasks autonomously. Organizations building expertise with these platforms today position themselves for significant competitive advantages as capabilities expand.&lt;/p&gt;
&lt;h2 class=&quot;text-xl font-bold text-text-100 mt-1 -mb-0.5&quot;&gt;Making the business case for Opal AI&lt;/h2&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;For executives evaluating Opal AI, the business case centers on three compelling factors: &lt;strong&gt;proven ROI&lt;/strong&gt;, &lt;strong&gt;scalability without headcount growth&lt;/strong&gt;, and &lt;strong&gt;competitive differentiation&lt;/strong&gt;. The platform&#39;s track record of delivering increased ROI provides confidence in financial returns, while its ability to scale marketing output without proportional team growth addresses a critical business challenge.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The competitive landscape increasingly rewards organizations that can produce more content, run more experiments, and deliver more personalized experiences. Opal enables this at a scale impossible with human teams alone.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Risk mitigation also factors into the business case. With SOC 2 compliance and enterprise-grade security, Opal meets the requirements of even highly regulated industries. The platform&#39;s audit trails and governance features ensure AI usage remains controlled and accountable.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;For organizations already using Optimizely products, Opal adoption requires minimal additional investment while multiplying the value of existing tools. For those new to Optimizely, the integrated platform approach eliminates the complexity of connecting multiple point solutions.&lt;/p&gt;
&lt;h2 class=&quot;text-xl font-bold text-text-100 mt-1 -mb-0.5&quot;&gt;Transforming marketing&#39;s future today&lt;/h2&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Optimizely Opal AI represents more than an incremental improvement in marketing technology&amp;mdash;it&#39;s a fundamental reimagining of how marketing teams operate. By combining specialized AI agents, deep platform integration, and proven business results, Opal delivers on the promise of AI-powered transformation.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;Organizations implementing Opal today gain immediate efficiency benefits while building capabilities that will become essential for future competitiveness. As marketing continues its evolution toward AI-augmented operations, early adopters of comprehensive platforms like Opal position themselves to lead rather than follow industry transformation.&lt;/p&gt;
&lt;p class=&quot;whitespace-normal break-words&quot;&gt;The question for business leaders isn&#39;t whether to adopt AI in marketing&amp;mdash;it&#39;s how quickly they can implement solutions that deliver measurable value. With its proven ROI, enterprise readiness, and continuous innovation, Optimizely Opal AI provides a clear path forward for organizations ready to transform their marketing operations through the power of specialized, integrated AI.&lt;/p&gt;</id><updated>2025-05-30T14:46:33.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - Creating a Cloudflare Turnstile Form Element Block</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2025/3/a-day-in-the-life-of-an-optimizely-developer---creating-a-cloudflare-turnstile-form-element-block/" /><id>&lt;p&gt;Hello and welcome to another installment of a day in the life of an Optimizely developer. Today I am going to show how to create a Cloudflare Turnstile form element block for use within Optimizely Forms.&lt;/p&gt;
&lt;p&gt;Cloudflare Turnstile is an alternative to traditional CAPTCHA systems, providing a user-friendly way to prevent spam and abuse on your website. Integrating Turnstile into Optimizely CMS allows you to enhance form security without compromising user experience.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Prerequisites&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Cloudflare Account&lt;/strong&gt;: Ensure you have a Cloudflare account and have registered your site to obtain the sitekey and secret key - &lt;a href=&quot;https://developers.cloudflare.com/turnstile/get-started/&quot;&gt;https://developers.cloudflare.com/turnstile/get-started/&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Optimizely CMS Setup&lt;/strong&gt;: Make sure your Optimizely CMS environment is set up and ready for development.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The first task is to create a new Element Block, ensuring that you inherit from ValidatableElementBlockBase, this allows you register a validator against the element.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Turnstile Element Block&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;/// 
/// Represents a Turnstile element block for form UI. It provides extra resources, specifically a script for Cloudflare
/// Turnstile.
/// 
[ContentType(
    GUID = &quot;{E426413A-1B5D-4353-B715-871F09D556C3}&quot;,
    DisplayName = &quot;Turnstile&quot;,
    GroupName = ConstantsFormsUI.FormElementGroup, 
    Order = 2230)]
[ImageUrl(&quot;~/img/cloudflare-turnstile-logo.png&quot;)]
public class TurnstileElementBlock : ValidatableElementBlockBase, IExcludeInSubmission, IViewModeInvisibleElement, IElementRequireClientResources
{
    private static readonly ILogger _logger = LogManager.GetLogger(typeof(RecaptchaElementBlock));
    private Injected _config;

    [Display(GroupName = SystemTabNames.Content, Order = -5000)]
    [ScaffoldColumn(false)]
    public override string Validators
    {
        get
        {
            var turnstileValidator = typeof(TurnstileValidator).FullName;
            var validators = this.GetPropertyValue(content =&amp;gt; content.Validators);
            return string.IsNullOrWhiteSpace(validators) ? turnstileValidator : string.Concat(validators, &quot;|||&quot;, turnstileValidator);
        }
        set
        {
            this.SetPropertyValue(content =&amp;gt; content.Validators, value);
        }
    }

    public override object GetSubmittedValue()
    {
        var httpContext = ServiceLocator.Current.GetInstance();
        return httpContext.HttpContext.Request.Method == &quot;POST&quot; ? httpContext.HttpContext.Request.Form[&quot;turnstile-response&quot;] : httpContext.HttpContext.Request.Query[&quot;turnstile-response&quot;];
    }

    [Ignore]
    public override string Label
    {
        get =&amp;gt; base.Label;
        set =&amp;gt; base.Label = value;
    }

    [Ignore]
    public override string Description
    {
        get =&amp;gt; base.Description;
        set =&amp;gt; base.Description = value;
    }

    /// 
    /// The site key for the Turnstile element.
    /// 
    [Display(GroupName = SystemTabNames.Content, Order = -3500)]
    public virtual string SiteKey
    {
        get
        {
            var siteKey = this.GetPropertyValue(content =&amp;gt; content.SiteKey);
            if (string.IsNullOrWhiteSpace(siteKey))
            {
                try
                {
                    siteKey = _config.Service.TurnstileKey?.SiteKey;
                }
                catch (ConfigurationErrorsException ex)
                {
                    _logger.Warning(&quot;Cannot get TurnstileSiteKey from app settings.&quot;, ex);
                }
            }
            return siteKey;
        }
        set
        {
            this.SetPropertyValue(content =&amp;gt; content.SiteKey, value);
        }
    }

    /// 
    /// The shared key between the site and Turnstile.
    /// 
    [Display(GroupName = SystemTabNames.Content, Order = -3400)]
    public virtual string SecretKey
    {
        get
        {
            var secretKey = this.GetPropertyValue(content =&amp;gt; content.SecretKey);
            if (string.IsNullOrWhiteSpace(secretKey))
            {
                try
                {
                    secretKey = _config.Service.TurnstileKey?.SecretKey;
                }
                catch (ConfigurationErrorsException ex)
                {
                    _logger.Warning(&quot;Cannot get TurnstileSecretKey from app settings.&quot;, ex);
                }
            }
            return secretKey;
        }
        set
        {
            this.SetPropertyValue(content =&amp;gt; content.SecretKey, value);
        }
    }

    public IEnumerable&amp;gt; GetExtraResources()
    {
        return new List&amp;gt;() {
                new(&quot;script&quot;, &quot;https://challenges.cloudflare.com/turnstile/v0/api.js&quot;)
            };
    }
}
&lt;/pre&gt;
&lt;p&gt;The next step is to create a validator class that needs to inherit from InternalElementValidatorBase, it is this validator that takes the token generated by the Turnstile element, and performs the call to the Turnstile siteverify endpoint, this is a crucial step as without it you can not confirm if the generated token has successfully verified the site.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Turnstile Validator&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;public class TurnstileValidator : InternalElementValidatorBase
{
    private const string TurnstileVerifyBaseUrl = &quot;https://challenges.cloudflare.com&quot;;

    public override bool? Validate(IElementValidatable targetElement)
    {
        var submittedValue = targetElement.GetSubmittedValue().ToString();
        if (string.IsNullOrWhiteSpace(submittedValue))
        {
            return false;
        }

        var turnstileElement = targetElement as TurnstileElementBlock;
        if (turnstileElement == null)
        {
            return false;
        }

        var client = new HttpClient();

        var formData = new Dictionary
            {
                { &quot;secret&quot;, &quot;&amp;lt;your secret key&amp;gt;&quot; },
                { &quot;response&quot;, submittedValue }
            };

        var content = new FormUrlEncodedContent(formData);
        var postTask = client.PostAsync($&quot;{TurnstileVerifyBaseUrl}/turnstile/v0/siteverify&quot;, content).Result;
        
        var result = postTask.Content.ReadAsStringAsync().Result;
        var resultObject = JsonSerializer.Deserialize(result);

        return resultObject.GetProperty(&quot;success&quot;).GetBoolean();
    }
}&lt;/pre&gt;
&lt;p&gt;The following class allows the Site key and Secret key to be retrieved from config, and is injected into the TurnstileElementBlock whereby the associated Site Key and Secret Key properties are set to the values stored in config.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Turnstile API Key Options&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;[Options(ConfigurationSection = &quot;Turnstile&quot;)]
public class TurnstileApiKeyOptions
{
    public TurnstileKey? TurnstileKey { get; set; }
}

public class TurnstileKey
{
    public string? SiteKey { get; set; }

    public string? SecretKey { get; set; }
}&lt;/pre&gt;
&lt;p&gt;The following configuration needs to be added to your appsettings.json file which specifies your Turnstile site key and secret key.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Appsettings Configuration&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;img src=&quot;/link/c4ddbd66988241a6b5de7127853e081a.aspx&quot; /&gt;&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Finally you need to create a new CSHTML file within the &quot;Views/Shared/ElementBlocks&quot; folder naming the file the same name as your element block (in the above case it would be named &#39;TurnstileElementBlock.cshtml&#39;)&lt;/p&gt;
&lt;p&gt;You will notice that the file contains a div which is where the Turnstile component gets injected to, this also has a sitekey data attribute which needs to be set to the site key specified in the block, there is also a callback data attribute in this case named &#39;javascriptCallback&#39; which calls a Javascript function passing in the token, the function then sets the value of a hidden field to the token passed back.&lt;/p&gt;
&lt;p&gt;CSHTML File&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/5949fbea1f604ecea14b3c52699aae8e.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Once all of the above has been implemented, when you add the new element block to an Optimizely form, you will see the Turnstile element block appears within the form.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/a39a734a588a43bf80900b20bb2d66c5.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;On submission of the form, the validator method will be called and the generated token verified, if the token is verified then the form submits successfully, if not verified then form submission will be unsuccessful.&lt;/p&gt;</id><updated>2025-03-24T12:55:54.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - London Meetup 2024</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2024/7/a-day-in-the-life-of-an-optimizely-developer---london-meetup-2024/" /><id>&lt;p&gt;&lt;span&gt;Hello and welcome to another instalment of A Day In The Life Of An Optimizely Developer. Last night (11th July 2024) I was excited to have attended the 2024 London Meetup and in this blog post I will give an overview of the evening and what my learnings and main takeaways were. The meetup was kindly organised by both Niteco and Netcel.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;The Venue&lt;/h2&gt;
&lt;p&gt;The location of the London meetup was The Lightwell situated on Worship Street, London. I was very impressed by the venue, in terms of facilities and comfort. I arrived at 5:45 allowing 45 minutes for networking before the talks began at 6.30pm.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;https://cdn.prod.website-files.com/5d79ea1cef0e0f787ba4e1a1/651c29692699bcc1af6e595b_Event_space_TV_view_side.webp&quot; width=&quot;863&quot; height=&quot;575&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;figcaption&gt;The Lightwell venue&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;The networking for the area took place in the the same room as the talks and was a perfect and relaxing area to chat with the attendees and speakers both prior to the presentations and during the mid-point break and after the presentations (also helped by both the open bar and food).&lt;/p&gt;
&lt;h2&gt;The Talks&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;The meetup consisted of seven talks which were both very informative and inspirational on a number of different topics.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/fb69dd3b332542189d3be1a2fa61aa90.aspx&quot; alt=&quot;&quot; style=&quot;width: 862px; height: 647px;&quot; /&gt;
&lt;figcaption&gt;The evenings agenda&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Scott Reed &amp;amp; Jacob Pretorius (Niteco) - Tips and Tricks for CMS12/Commerce 14 Upgrade&lt;/h2&gt;
&lt;p&gt;Scott and Jacob opened up the evening with a talk about upgrading from CMS11/Commerce 13 to CMS12/Commerce 14.&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/ebcfeb4644934168abff4cd172f65e03.aspx&quot; width=&quot;855&quot; alt=&quot;&quot; height=&quot;641&quot; /&gt;
&lt;figcaption&gt;Scott and Jacob&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;The talk started off with some slides that highlighted the performance benefits of upgrading to CMS12/Commerce 13 which is of no surprise considering that they both run on .Net core which is well known for it&#39;s performance (&lt;a href=&quot;https://devblogs.microsoft.com/dotnet/performance-improvements-in-aspnet-core-8/&quot;&gt;https://devblogs.microsoft.com/dotnet/performance-improvements-in-aspnet-core-8/&lt;/a&gt;). It was also noted that when running CMS12/Commerce 13 on DXP this is a revised infrastructure that runs as containers on Linux.&lt;/p&gt;
&lt;p&gt;Scott and Jacob then went on to provide a list of steps that they would recommend are followed when performing an upgrade and included:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Planning and discovery - includes tasks such as reviewing the existing codebase, doing audits of existing plugins, breaking changes, etc.&lt;/li&gt;
&lt;li&gt;Upgrade - this is the actual process of upgrading and includes tasks such as running the upgrade assistant, executing code, analysing and updating packages, etc.&lt;/li&gt;
&lt;li&gt;QA / Stabilisation - this task includes execution of test plans, fixing any bugs that are found, etc.&lt;/li&gt;
&lt;li&gt;UAT/NFR/Prod Prep - includes tasks such as performing a demo to the client, end to end integration testing, etc.&lt;/li&gt;
&lt;li&gt;Rollout - this includes tasks such as performing the migration within DXP, finalising the production setup, etc.&lt;/li&gt;
&lt;li&gt;Hypercare - this final task happens after go-live and includes fixing any critical bugs/incidents, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So you may ask yourself, is the effort worth it? &lt;span&gt;Absolutely.&lt;/span&gt;&lt;strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;&lt;span&gt;Whilst upgrading from Optimizely CMS 11 to CMS 12 will require time, effort and budget, it is a strategic move that can significantly benefit your organisation. From enhanced performance, security, and content personalisation, along with improved user experience, and mobile-friendliness, Optimizely CMS 12 brings many advantages drive competitive advantage in the digital landscape.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/761a8c3983a34b95a58f7cead35c5290.aspx&quot; width=&quot;1488&quot; alt=&quot;&quot; height=&quot;1116&quot; style=&quot;width: 853px; height: 639px;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The final takeaway from this talk was to highlight that you should not agree to a fixed deadline when performing an upgrade, this is because an upgrade can be highly complex depending on the complexity of the solution being upgraded, and in my own personal experience there are often many skeletons in the closet that become apparent.&lt;/p&gt;
&lt;h2&gt;Cindy Gilbertson (Optimizely) - Get started with Visual Builder&lt;/h2&gt;
&lt;p&gt;The second talk was done by Optimizely&#39;s own Cindy Gilbertson and was a talk and demonstration of the excellent Visual Builder which is described by Optimizely as a standalone &quot;visual experience builder&quot;. The talk was done in conjunction with a demo of Visual Builder showing how easy it is to setup both reusable components and pages as described below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/6581045036524b0d80c59763348879a2.aspx&quot; alt=&quot;SaaS CMS | Optimizely Developer Community&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Visual builder comes in two forms, namely PaaS (Platform as a Service) and SaaS (Software as a Service) versions, the PaaS version is more customisable than the SaaS version and runs on the yet to be released CMS13. The SaaS version utilises Opti Graph to allow content to be queried and returned (it also worth noting that Opti Graph can also be installed into and utilised within the PaaS version)&lt;/p&gt;
&lt;p&gt;The whole concept of building content is via the Outline area, where you add sections, and to the sections you add rows and columns. Within these rows and columns you can then add elements which are essentially the fields where content is added, for example rich text, headings, images, buttons, etc. Both sections and experiences can be saved as blueprints, this essentially makes them available for re-use and they appear as options when you next try to add a new section or page.&lt;/p&gt;
&lt;p&gt;Cindy was asked what is missing from Visual Builder that she would love to see in the product going forwards, and this turned out to be having more granular control over the permissions as well as adding integration for blocks, which currently do not show up within Visual Builder.&lt;/p&gt;
&lt;p&gt;The final takeaway for me was that Optimizely are planning to move away from the DOJO interface over time.&lt;/p&gt;
&lt;h2&gt;Minesh Shah (Netcel) - Guide to SaaS CMS and Hybrid Headless&lt;/h2&gt;
&lt;p&gt;Minesh Shah opened up the fourth talk of the evening with a presentation on how to setup SaaS CMS and Visual Builder running on Vercel.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/5a18404f4e894700a84a32bc1fa37de8.aspx&quot; width=&quot;832&quot; alt=&quot;&quot; height=&quot;624&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;figcaption&gt;Minesh Shah&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;This talk consisted of a demo on how quick it is to create a site utilising the example Mosey Bank github repo (&lt;a href=&quot;https://github.com/episerver/cms-visual-builder-vercel-beta&quot;&gt;https://github.com/episerver/cms-visual-builder-vercel-beta&lt;/a&gt;). Minesh ran through the steps on retrieving the necessary configuration keys and secrets from SaaS CMS and then adding these into the required places, as well as performing the steps to get this all built and deployed to Vercel.&lt;/p&gt;
&lt;p&gt;I was impressed on how quickly Minesh got a demo site created and how it was up and running on Vercel within a matter of minutes.&lt;/p&gt;
&lt;h2&gt;Mark Stott (Netcel) - Creating AddOns for PaaS CMS&lt;/h2&gt;
&lt;p&gt;After the break, we moved onto the fourth talk of the evening that was presented by Mark Stott. This talk was all about how to go about creating AddOns within PaaS CMS.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/b745a66c09904dfa952ab48bdeba9d3d.aspx&quot; width=&quot;1488&quot; alt=&quot;&quot; height=&quot;1116&quot; style=&quot;width: 824px; height: 618px; display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;figcaption&gt;Mark Stott&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;Mark started off by highlighting some important considerations to keep in mind concerning Optimizely add-ons and included:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Have a great idea&lt;/li&gt;
&lt;li&gt;Be passionate about your plugin&lt;/li&gt;
&lt;li&gt;Be prepared to spend a lot of time on your plugin&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;He then showed some statistics on the two add-ons that he created and actively works on during his spare time, these add-ons are as follows along with the Github links:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Stott.Optimizely.RobotsHandler - &lt;a href=&quot;https://github.com/GeekInTheNorth/Stott.Optimizely.RobotsHandler&quot;&gt;https://github.com/GeekInTheNorth/Stott.Optimizely.RobotsHandler&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;li&gt;Stott.Security.Optimizely - &lt;a href=&quot;https://github.com/GeekInTheNorth/Stott.Security.Optimizely&quot;&gt;https://github.com/GeekInTheNorth/Stott.Security.Optimizely&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mark then went on to provide some examples of how best to build add-ons for Optimizely, along with some tips and tricks he found during the time of creating his own add-ons. This covered off topics such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Utilising Razor class libraries (&lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-8.0&amp;amp;tabs=visual-studio&quot;&gt;https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-8.0&amp;amp;tabs=visual-studio&lt;/a&gt;) to ensure all of the add-on files are kept together.&lt;/li&gt;
&lt;li&gt;Having a separate UI builder folder.&lt;/li&gt;
&lt;li&gt;Ensuring that you provide a sample project within your repository so that the add-on can be easily tested.&lt;/li&gt;
&lt;li&gt;The use of menu providers to place your add-on in the correct location of the CMS, e.g. in the add-ons section, ability to add as a gadget, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Anil Patel (Knight Frank) - Azure AI Speech Integration with Optimizely CMS&lt;/h2&gt;
&lt;p&gt;The fifth talk of the evening was presented by Anil Patel and covered how the Azure AI Speech service can be utilised within the Optimizely CMS interface.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/f3956cac94a54c909c95df841e566a59.aspx&quot; width=&quot;1488&quot; alt=&quot;&quot; height=&quot;1116&quot; style=&quot;width: 822px; height: 616px; display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;figcaption&gt;Anil Patel&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;Anil provided three examples of how Azure AI Speech can be utilised and this included demos of:&lt;/p&gt;
&lt;h3&gt;Text to speech&lt;/h3&gt;
&lt;p&gt;Anil started off with a demo that showed how text could be converted to speech. He took some text and pasted it into a text area and then published the page. After a few seconds an audio file appeared in the media section, he dropped this into a content area and upon viewing the page an audio file appeared which when played was a direct representation of the text he had used just a few seconds ago. It was also worth noting the breadth of voices that could be used to generate the speech.&lt;/p&gt;
&lt;h3&gt;Speech to text&lt;/h3&gt;
&lt;p&gt;This second demo was the direct opposite of the first demo, and involved dropping an audio file into a folder, which after a few seconds generated a direct text representation of the speech that existed within the audio file.&lt;/p&gt;
&lt;h3&gt;Speech to text translation&lt;/h3&gt;
&lt;p&gt;In this demo, Anil showed us how he could utilise the speech to text translation feature. He took an audio file, dropped it into a folder and selected a language, after a short while and upon refreshing the page, a text area was filled with the translation of the words that existed within the uploaded audio file.&lt;/p&gt;
&lt;p&gt;Overall it was great to see examples of how AI can be put to work in some great use cases, and it has certainly opened my eyes more to the possibilities that are available with AI, even given the current negativity of AI as a whole.&lt;/p&gt;
&lt;h2&gt;Tom Bramley (Optimizely) - Opal in PaaS Commerce + New Stuff&lt;/h2&gt;
&lt;p&gt;Optimizely&#39;s own Tom Bramley opened up the penultimate talk of the evening, this covered a demo of Opal within PaaS Commerce along with an overview of the some new stuff within Commerce Connect (formerly Customized Commerce) as well as the Q3 roadmap.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;https://www.epinova.no/siteassets/epinova.no/bilder/artikkelbilder/optimizely-composable-commerce-concept/&quot; width=&quot;811&quot; alt=&quot;Concept architecture of Optimizely Composable Commerce for SaaS Core and PaaS Core&quot; height=&quot;475&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;
&lt;figcaption&gt;Composable Modules&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;Tom started off by highlighting that Commerce Connect is the new name for Customized Commerce, and also highlighed (see image above) how composable modules are being created that can be utilised by both Commerce Connect and Configured Commerce.&lt;/p&gt;
&lt;p&gt;Tom then went on to provide a demo of utilising Opal AI for the product description, the demo took a current product description which was pasted into a field, upon clicking a button Opal AI was fired up and then based on a prompt created a revised product description for the product detail entered. I was impressed by the results and speed at which the product description was generated.&lt;/p&gt;
&lt;p&gt;Other new features that Tom highlighted were either already built or soon to be coming were as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Providing the ability to Import/Export the product catalog directly via UI&lt;/li&gt;
&lt;li&gt;Opti Graph for commerce&lt;/li&gt;
&lt;li&gt;A tutorial PLP build&lt;/li&gt;
&lt;li&gt;Newly reviewed and refreshed customizable views&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/56625944d25e4309af8c38073021665f.aspx&quot; width=&quot;820&quot; alt=&quot;&quot; height=&quot;615&quot; /&gt;
&lt;figcaption&gt;Q3 Roadmap&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;Tom finished off his presentation by running through the roadmap for Q3 (see image above) and highlighted the items that were committed (definitely being built), planned (will be built) and considered (highly likely to be built). I was pleased to see the breadth of features that were being built/planned to be built and am excited to try these features out when they are ultimately released.&lt;/p&gt;
&lt;h2&gt;Dom Sipowicz (Vercel) - Implementing Optimizely flags through Vercel&lt;/h2&gt;
&lt;p&gt;Dom Sipowicz closed off the meetups presentations with a very insightful look at how Optimizely Flags can be utilised within Vercel.&amp;nbsp;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;https://assets.vercel.com/image/upload/contentful/image/e5382hct74si/6vjsh6ZKLUSewLoNevxgOZ/44c97f57e5fbfa61f2f9e21deb232169/Toolbar_in_Production.jpg&quot; width=&quot;748&quot; alt=&quot;Use the Vercel Toolbar in Production with the Chrome Extension or the  toolbar menu &amp;ndash; Vercel&quot; height=&quot;421&quot; /&gt;
&lt;figcaption&gt;Vercel Toolbar&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;A demonstration was done which showed how the Vercel Toolbar (see above) could be used to quickly enable/disable feature flags that existed within Optimizely feature experimentation, with the changes appearing on the fly.&lt;/p&gt;
&lt;p&gt;Ultimately, I was very impressed by the sheer number of feature flags that were supported with no apparent slowdown on the sample site that was being demonstrated.&lt;/p&gt;
&lt;h2&gt;Main Takeaways and Learnings&lt;/h2&gt;
&lt;p&gt;All in all the meetup was very insightful and gave me a lot of food for thought in terms of how we could utilise some of these practices and technologies in the Optimizely builds we do at&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;/www.26-dx.com&quot;&gt;26&lt;span&gt; DX&lt;/span&gt;&lt;/a&gt;- the main points that I took away from this event are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Performing an upgrade to CMS12/Commerce 13 can be very time consuming dependent on the complexity of the project, and when planning an upgrade never agree to a fixed deadline.&lt;/li&gt;
&lt;li&gt;Visual Builder is a great tool for marketers to create reusable components and pages. I was impressed to see how &lt;span&gt;Visual Builder provides a user-friendly, standalone tool for content creation within Optimizely&#39;s evolving SaaS and headless initiative.&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;The seamless integration with Vercel and Optimizely SaaS and how fast it is to get a sample website up and running and how fast these websites run when hosted on Vercel.&lt;/li&gt;
&lt;li&gt;There are many ways in which Optimizely add-ons can be created and added to the Optimizely CMS interface, and I was intrigued to see how Razor Class libraries can be utilised when building an add-on. This talk has certainly increased my drive to create my first add-on.&lt;/li&gt;
&lt;li&gt;I was impressed to see how feature flags can be utilised in conjunction with Vercel to provide a blazingly fast way of performing tests within your applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;Below are a list of links to further information on areas of the talks by all seven speakers.&lt;/p&gt;
&lt;h3&gt;SaaS / Visual Builder&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/docs/overview-of-cms-saas&quot;&gt;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/docs/overview-of-cms-saas&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/docs/demo-site-with-cms-saas-and-vercel&quot;&gt;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/docs/demo-site-with-cms-saas-and-vercel&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/docs/create-a-demo-site-using-cms-saas-and-netlify&quot;&gt;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/docs/create-a-demo-site-using-cms-saas-and-netlify&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/docs/visual-builder&quot;&gt;https://docs.developers.optimizely.com/content-management-system/v1.0.0-CMS-SaaS/docs/visual-builder&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Vercel&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://vercel.com/templates/next.js/feature-flag-optimizely&quot;&gt;https://vercel.com/templates/next.js/feature-flag-optimizely&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://github.com/episerver/cms-visual-builder-vercel-beta/&quot;&gt;https://github.com/episerver/cms-visual-builder-vercel-beta/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://github.com/episerver/cms-visual-builder-hello-world&quot;&gt;https://github.com/episerver/cms-visual-builder-hello-world&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://vercel.com/docs/workflow-collaboration/vercel-toolbar&quot;&gt;https://vercel.com/docs/workflow-collaboration/vercel-toolbar&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.optimizely.com/apps/vercel/&quot;&gt;https://www.optimizely.com/apps/vercel/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Commerce Connect / Configured Commerce / Composable Modules&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.optimizely.com/product-updates/commerce-connect/&quot;&gt;https://www.optimizely.com/product-updates/commerce-connect/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.optimizely.com/products/content-management/commerce-connect/&quot;&gt;https://www.optimizely.com/products/content-management/commerce-connect/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.optimizely.com/products/configured-commerce/&quot;&gt;https://www.optimizely.com/products/configured-commerce/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;CMS12 / Commerce 13 Upgrade&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/docs/why-upgrade-to-content-cloud-cms-12&quot;&gt;https://docs.developers.optimizely.com/content-management-system/docs/why-upgrade-to-content-cloud-cms-12&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/docs/upgrading-to-content-cloud-cms-12&quot;&gt;https://docs.developers.optimizely.com/content-management-system/docs/upgrading-to-content-cloud-cms-12&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/docs/upgrade-assistant&quot;&gt;https://docs.developers.optimizely.com/content-management-system/docs/upgrade-assistant&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.jondjones.com/learn-optimizely/cms/optimizely-cms-upgrading-guide-learn-how-to-convert-your-project-from-net-to-net-core/&quot;&gt;https://www.jondjones.com/learn-optimizely/cms/optimizely-cms-upgrading-guide-learn-how-to-convert-your-project-from-net-to-net-core/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Plugin Creation&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/docs/developing-add-ons&quot;&gt;https://docs.developers.optimizely.com/content-management-system/docs/developing-add-ons&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.getadigital.com/blog/optimizely-12-ui-plugin&quot;&gt;https://www.getadigital.com/blog/optimizely-12-ui-plugin&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Azure AI&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://azure.microsoft.com/en-gb/products/ai-services/&quot;&gt;https://azure.microsoft.com/en-gb/products/ai-services/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/products/ai-services/speech-to-text&quot;&gt;https://azure.microsoft.com/en-us/products/ai-services/speech-to-text&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://azure.microsoft.com/en-gb/products/ai-services/text-to-speech&quot;&gt;https://azure.microsoft.com/en-gb/products/ai-services/text-to-speech&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://azure.microsoft.com/en-gb/products/ai-services/ai-translator&quot;&gt;https://azure.microsoft.com/en-gb/products/ai-services/ai-translator&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;author__image col-sm-5&quot;&gt;&lt;img src=&quot;https://assets-eu-01.kc-usercontent.com/1e387446-ba57-010e-8dbf-944631f19d11/d003b6bf-e48d-43b5-ae36-ace9342bcecb/GrahamCarr_680x454.jpg?w=500&amp;amp;h=1000&amp;amp;auto=format&quot; /&gt;&lt;/div&gt;
&lt;div class=&quot;author__content col-sm-7 keep-margin-bottom&quot;&gt;
&lt;h2&gt;Graham Carr, Lead .NET Developer&lt;/h2&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;I am an experienced Lead .Net Developer with over 25 years&amp;rsquo; experience in a wide range of products and technologies. I have helped companies deliver their digital vision from concept all the way through to delivery. I have a particular passion for DXPs (Digital Experience Platforms) and am a certified developer for products such as Optimizely, Umbraco, Kontent.ai and more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2024-07-16T14:49:30.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - Introduction to Optimizely SaaS Core</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2024/5/a-day-in-the-life-of-an-optimizely-developer---introduction-to-saas-core/" /><id>&lt;h2&gt;What is SaaS Core&lt;/h2&gt;
&lt;p&gt;Optimizely SaaS Core is a cloud-based, headless, and API-first version of the Optimizely CMS (Content Management System) and Commerce platform. Unlike traditional platforms, SaaS Core provides customers with a complete package - both the operating environment and the application itself - without the need for extensive coding or technical expertise.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/ee2489cbd3704af1ae443bca248d5d0e.aspx&quot; width=&quot;1119&quot; height=&quot;409&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;The Challenge: Complexity in Composability&lt;/h2&gt;
&lt;p&gt;Composability has traditionally meant complexity, especially for marketers. As businesses strive to build custom tech stacks tailored to their unique needs, marketers often find themselves navigating intricate systems designed primarily for developers.&lt;/p&gt;
&lt;h2&gt;Key Features of SaaS Core&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Low-Code/No-Code Development: One of the most attractive features of SaaS Core is its no-code approach to template building. Users can define content types, specify properties, and configure data types all through a user-friendly web interface, eliminating the reliance on developers for &amp;ldquo;basic&amp;rdquo; site customisation.&lt;/li&gt;
&lt;li&gt;Always Updated: Optimizely takes care of infrastructure, monitoring, security, and upgrades to core components. This ensures that users benefit from the latest features and improvements without the hassle of planning or executing upgrades.&lt;/li&gt;
&lt;li&gt;Headless Architecture: SaaS Core adopts a headless approach, storing content in a presentation-agnostic format accessible via APIs. This allows for greater flexibility in creating custom front-end experiences across various digital channels.&lt;/li&gt;
&lt;li&gt;Low-Code Integrations: Pre-built integrations (&quot;connectors&quot;) simplify data exchange between CMS/Commerce and other systems. Customers can set up integrations with just a few clicks, reducing as much dependency on custom development.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How does Optimizely SaaS Core differ from PaaS Core&lt;/h2&gt;
&lt;p&gt;Whilst both products are built on the same foundational CMS they do differ in several different ways. SaaS Core is headless, versionless and composable whilst PaaS Core is highly configurable and customisable.&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;&lt;strong&gt;SaaS Core&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;&lt;strong&gt;PaaS Core&lt;/strong&gt;&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Automatic and versionless updates&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;Partner managed updates&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;API-First approach&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;Supports hybrid, headless or coupled&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;Do not need to worry about installation&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;Partner managed installation&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;JS Frameworks and No .Net Core&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;JS Frameworks and/or .Net Core&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;No-coding approach&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;Ability to modify code for extensibility&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;No add-ons at this current time&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;
&lt;p&gt;Customisations can be done via add-ons&lt;/p&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&amp;nbsp;&lt;img src=&quot;/link/e6dc146552224709bde9fde70a51a806.aspx&quot; width=&quot;1056&quot; height=&quot;494&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Related Technologies&lt;/h2&gt;
&lt;h3&gt;Optimizely Graph&lt;/h3&gt;
&lt;p&gt;Optimizely Graph is a SaaS service built on GraphQL, designed to transform how users query and deliver content. Here is a summary of its key features and benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;GraphQL: Optimizely Graph leverages GraphQL, an open-source data query language, to generate unique schemas for each site, enabling efficient content querying.&lt;/li&gt;
&lt;li&gt;Semantic Search: Utilises AI for semantic search, understanding contextual meaning behind keywords to deliver more accurate results, such as recognising &quot;The Windy City&quot; as Chicago.&lt;/li&gt;
&lt;li&gt;External Data Integration: Allows querying of both CMS and external data sources, enabling data linkage across multiple sources via a single endpoint.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;How It Works:&lt;/h4&gt;
&lt;ul&gt;
&lt;li&gt;Content Sync: As content is published in the CMS, the GraphQL API dynamically generates schemas based on synchronised content, ensuring performance through Cloudflare CDN edge nodes.&lt;/li&gt;
&lt;li&gt;External Data Integration: Define content types via API, sync data in JSONL format, and push it to Graph via API for seamless integration and querying.&lt;/li&gt;
&lt;li&gt;Querying and Search: Access an interactive GraphQL page to build custom queries within the CMS, perform standard or semantic searches on properties defined as &quot;searchable.&quot;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/link/94147011306149f8b621b6d50f7afbb8.aspx&quot; width=&quot;1127&quot; height=&quot;544&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Visual Builder&lt;/h3&gt;
&lt;p&gt;Optimizely&#39;s new feature, Visual Builder, is described by Optimizely as a standalone &quot;visual experience builder&quot; designed to empower content creators with an intuitive editing interface. Here&#39;s a summary of its key points:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Purpose&lt;/strong&gt;: Visual Builder enhances content composition by providing a streamlined interface focused on assembling content blocks and enabling easy previewing before publishing.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Key Features&lt;/strong&gt;:
&lt;ul&gt;
&lt;li&gt;Improved visual aesthetics emphasising content composition without CMS scaffolding.&lt;/li&gt;
&lt;li&gt;Template creation without coding.&lt;/li&gt;
&lt;li&gt;Integration with Optimizely Graph for content manipulation.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Base&lt;/strong&gt;: Visual Builder is ideal for Optimizely SaaS users who prefer a decoupled approach to content creation, allowing flexibility in editing interfaces and adaptation to various digital channels.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Positioning&lt;/strong&gt;: Positioned as the primary visual content composer within Optimizely SaaS, Visual Builder offers flexibility for content management independent of presentation layers.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Integration&lt;/strong&gt;: Works in tandem with Optimizely Graph&#39;s APIs, transforming Optimizely SaaS into a headless CMS for composing, modifying, and distributing content.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Availability&lt;/strong&gt;: Expected to launch in H1 2024, Visual Builder will likely be a cloud-based add-on service integrated with both CMS and CMP content composition.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Visual Builder provides a user-friendly, standalone tool for content creation within Optimizely&#39;s evolving SaaS and headless initiative, offering enhanced flexibility and control over content management and distribution.&lt;/p&gt;
&lt;h2&gt;Who Should Consider SaaS Core&lt;/h2&gt;
&lt;p&gt;Optimizely SaaS Core is ideal for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Composable Flexibility: Organisations seeking a flexible CMS/Commerce platform that allows for component-based customisation.&lt;/li&gt;
&lt;li&gt;Time-to-Market: Businesses requiring rapid deployment of simple campaign sites, pop-up stores, or event websites.&lt;/li&gt;
&lt;li&gt;Structured Data Management: Those looking to store content in a clean, structured format for seamless synchronisation across digital channels.&lt;/li&gt;
&lt;li&gt;Frontend Freedom: Developers wanting to create custom frontends using preferred frameworks, independent of traditional WYSIWYG editors.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Do I Still Need an Optimizely Partner?&lt;/h2&gt;
&lt;p&gt;While SaaS Core reduces the technical complexity associated with template development and setup, partnering with Optimizely experts like &lt;a href=&quot;https://www.26-dx.com&quot;&gt;26 DX&lt;/a&gt; remains valuable. An experienced partner can optimise platform setup, streamline integrations, and provide strategic guidance to maximise ROI.&lt;/p&gt;
&lt;p&gt;In conclusion, Optimizely SaaS Core represents a major step towards democratising web development, empowering businesses to create, manage, and optimise digital experiences with unparalleled ease and flexibility.&lt;/p&gt;
&lt;h3&gt;References&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;em&gt;&lt;/em&gt;&lt;/h3&gt;
&lt;div class=&quot;author__image col-sm-5&quot;&gt;&lt;img src=&quot;https://assets-eu-01.kc-usercontent.com/1e387446-ba57-010e-8dbf-944631f19d11/d003b6bf-e48d-43b5-ae36-ace9342bcecb/GrahamCarr_680x454.jpg?w=500&amp;amp;h=1000&amp;amp;auto=format&quot; /&gt;&lt;/div&gt;
&lt;div class=&quot;author__content col-sm-7 keep-margin-bottom&quot;&gt;
&lt;h2&gt;Graham Carr, Lead .NET Developer&lt;/h2&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;I am an experienced Lead .Net Developer with over 28 years&amp;rsquo; experience in a wide range of products and technologies. I have helped companies deliver their digital vision from concept all the way through to delivery. I have a particular passion for DXPs (Digital Experience Platforms) and am a certified developer for products such as Optimizely, Umbraco, Kontent.ai and more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2024-06-04T12:33:43.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - Enabling Opti ID within your application</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2024/5/a-day-in-the-life-of-an-optimizely-developer---enabling-opti-id-within-your-websites/" /><id>&lt;p&gt;Hello and welcome to another instalment of A Day In The Life Of An Optimizely developer, in this blog post I will provide details on Optimizely&#39;s Opti ID, what it is and how it can easily be enabled within your website.&lt;/p&gt;
&lt;h2&gt;What is Opti ID&lt;/h2&gt;
&lt;p&gt;Opti ID offers a centralised login experience, allowing seamless switching between Optimizely products with just one authentication using Okta, Entra ID, or a local login. It also enables centralised user management using the Opti ID Admin Centre.&lt;/p&gt;
&lt;p&gt;Opti ID provides the following benefits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Centralized Login with SSO&lt;/strong&gt;: Enjoy single sign-on (SSO) with support for multi-factor authentication (MFA) using your preferred MFA setup and active directory authentication provider.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Application Switching&lt;/strong&gt;: Switch between applications without needing to re-authenticate.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;User Administration&lt;/strong&gt;: Easily manage Opti ID users, groups, and roles from a centralized location.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Account and User Dashboard&lt;/strong&gt;: Access comprehensive usage and billing information through a centralized dashboard.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Businesses investing in marketing technology often face challenges in balancing flexibility and composability within their tech stacks while managing multiple solutions from different providers. Analysts highlight the financial and administrative burdens associated with maintaining diverse best-of-breed point solutions.&lt;/p&gt;
&lt;p&gt;Optimizely addresses these challenges by simplifying the adoption and management of digital experience solutions. Whether you choose a single Optimizely product or the entire suite, you gain access to a cohesive solution that can be conveniently accessed and utilized from a unified platform.&lt;/p&gt;
&lt;h2&gt;How to enable Opti ID&lt;/h2&gt;
&lt;p&gt;There are a couple of ways of enabling Opti ID within your website, either by SAML or OIDC. I decided to go down the OIDC route so this is what will be covered, however the references section further down provides some links to useful articles on enabling Opti ID.&lt;/p&gt;
&lt;h3&gt;Install Nuget Package&lt;/h3&gt;
&lt;p&gt;The first step is to ensure that the following Nuget package is installed in your web project:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/3cb7330112864f60ae51c3b01611299c.aspx&quot; /&gt;&lt;/p&gt;
&lt;h3&gt;Update Startup.cs&lt;/h3&gt;
&lt;p&gt;You now need to add the following line of code to your Startup.cs class in the ConfigureServices method:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddOptimizelyIdentity(useAsDefault: true);&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You need to ensure at this point that if you are not using ASP.Net Identity then you need to remove any code references to:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddCmsAspNetIdentity&amp;lt;TUser&amp;gt;()&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Running Opti ID locally&lt;/h3&gt;
&lt;p&gt;To ensure that you can run Opti ID locally you need to first of all add the following to your appsettings.json file within the Episerver / CMS section (it is worth noting that these values get added automatically when you deploy your website to DXP):&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;      &quot;OptimizelyIdentity&quot;: {
        &quot;InstanceId&quot;: &quot;xxx&quot;,
        &quot;ClientId&quot;: &quot;xxx&quot;,
        &quot;ClientSecret&quot;: &quot;xxx&quot;
      },&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;To get the values for InstanceId, ClientId and ClientSecret, you need to head over to PaaSPortal (&lt;a href=&quot;https://paasportal.episerver.net&quot;&gt;https://paasportal.episerver.net&lt;/a&gt;) and go into the API tab of the correct organisation. You will see a section detailing Opti ID dev key, these are the values that you need to put into your appsettings.json.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/52d6372ba06e43df9de1649dbab600e1.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Then that is all that is required from a coding perspective, the next step goes beyond the detail of this article however the references section provides links to detail on how you configure Entra or Okta to allow authentication, authorisation and synchronisation of users and groups.&lt;/p&gt;
&lt;p&gt;In conclusion, Opti ID is a great solution for organisations who have multiple Optimizely products that they want to be able to access via an integrated SSO solution.&lt;/p&gt;
&lt;h3&gt;References&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;em&gt;&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://support.optimizely.com/hc/en-us/articles/18127857412493-Install-Opti-ID-for-CMS&quot;&gt;https://support.optimizely.com/hc/en-us/articles/18127857412493-Install-Opti-ID-for-CMS&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://support.optimizely.com/hc/en-us/articles/18129917620109-Configure-SSO-with-Opti-ID-using-SAML&quot;&gt;https://support.optimizely.com/hc/en-us/articles/18129917620109-Configure-SSO-with-Opti-ID-using-SAML&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://support.optimizely.com/hc/en-us/articles/18129890210573-Configure-SSO-with-Opti-ID-using-OIDC&quot;&gt;https://support.optimizely.com/hc/en-us/articles/18129890210573-Configure-SSO-with-Opti-ID-using-OIDC&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://support.optimizely.com/hc/en-us/articles/17917477783181-Sync-groups-from-your-SSO-provider&quot;&gt;https://support.optimizely.com/hc/en-us/articles/17917477783181-Sync-groups-from-your-SSO-provider&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;author__image col-sm-5&quot;&gt;&lt;img src=&quot;https://assets-eu-01.kc-usercontent.com/1e387446-ba57-010e-8dbf-944631f19d11/d003b6bf-e48d-43b5-ae36-ace9342bcecb/GrahamCarr_680x454.jpg?w=500&amp;amp;h=1000&amp;amp;auto=format&quot; /&gt;&lt;/div&gt;
&lt;div class=&quot;author__content col-sm-7 keep-margin-bottom&quot;&gt;
&lt;h2&gt;Graham Carr, Lead .NET Developer&lt;/h2&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;I am an experienced Lead .Net Developer with over 25 years&amp;rsquo; experience in a wide range of products and technologies. I have helped companies deliver their digital vision from concept all the way through to delivery. I have a particular passion for DXPs (Digital Experience Platforms) and am a certified developer for products such as Optimizely, Umbraco, Kontent.ai and more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2024-05-09T08:40:48.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - Creating an AI powered conversational robot that utilises Semantic Search in Optimizely Graph</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2024/1/a-day-in-the-life-of-an-optimizely-developer---creating-an-ai-powered-conversational-robot-that-utilises-semantic-search-in-graph/" /><id>&lt;h2&gt;Overview&lt;/h2&gt;
&lt;p&gt;Hello and welcome to another installment of A Day In The Life Of An Optimizely Developer!&lt;br /&gt;&lt;br /&gt;In this blog post I will be covering an exciting POC that I recently undertook for one of our clients. The ask was to create a POC of an AI powered chatbot that followed the RAG model utilising Optimizely Graph and Semantic Search for retrieving related content that the chatbot can use as a context to be able to &lt;span&gt;enhance the quality and relevance of its generated responses.&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;What is RAG?&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;The term RAG stands for Retrieval-Augmented Generation model and is a type of architecture used in natural language processing (NLP) and machine learning.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In simple terms:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Retrieval:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;This part involves fetching information from a pre-existing set of data or knowledge. It might retrieve relevant text passages or documents based on a given input or query.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Augmented Generation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The system then uses this retrieved information to enhance or &quot;augment&quot; its ability to generate new, contextually relevant content. This content can be in the form of text, responses, or any other linguistic output.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;In the context of language models, this combination is often employed to improve the model&#39;s ability to generate more accurate and contextually appropriate responses by leveraging information from a broader knowledge base.&lt;/p&gt;
&lt;p&gt;For instance, if you ask a question, the model might retrieve relevant information from a database or existing text and use that information to generate a more informed and accurate response. This approach aims to enhance the overall performance of the system by leveraging both pre-existing knowledge and the model&#39;s generative capabilities.&lt;/p&gt;
&lt;h2&gt;Process Flow&lt;/h2&gt;
&lt;p&gt;The following is a high-level overview of the process flow from the moment the user enters a search query.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/ab90f983e01a449696c8ca955453106b.aspx&quot; width=&quot;353&quot; alt=&quot;&quot; height=&quot;506&quot; /&gt;&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;Users enters prompt.&lt;/li&gt;
&lt;li&gt;Prompt used to search website (Semantic search within Optimizely Graph used for this).&lt;/li&gt;
&lt;li&gt;Content components extracted from the returned search data.&lt;/li&gt;
&lt;li&gt;Embeddings created from the content components, these are saved to a persistent data source.&lt;/li&gt;
&lt;li&gt;Prompt created and context created containing embeddings, these are fed into LLM with a strong anti-hallucination bias.&lt;/li&gt;
&lt;li&gt;Show answer generated by LLM with links to citations.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;Semantic Search within Optimizely Graph&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;Semantic search is an advanced search technique that goes beyond traditional keyword-based search to understand the meaning of words and the context in which they are used. Instead of simply matching search queries with keywords, semantic search aims to comprehend the intent and the context of the user&#39;s query to provide more accurate and relevant results.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;To be able to perform semantic searches within Optimizely Graph, a number of pre-requisite steps need to be carried out to enable Graph.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Enable the Graph service within PaaSPortal - when you enable the service be aware that although you have enabled a free trial, it cannot be used for live traffic and a subscription needs to be purchased when using in a production environment.&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;/link/a65a33d9188a4b7fa5e81732e5c5d14e.aspx&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;The next step is to i&lt;span&gt;nstall&amp;nbsp;&lt;/span&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;Optimizely.ContentGraph.CMS&lt;/span&gt;&lt;/code&gt;&lt;span&gt;&amp;nbsp;in your Optimizely Content Management System (CMS) site to synchronize content types and content. In Visual Studio, go to&amp;nbsp;&lt;/span&gt;&lt;strong&gt;Tools&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;strong&gt;Nuget Package Manager&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&amp;gt;&amp;nbsp;&lt;/span&gt;&lt;strong&gt;Package Manager Console&lt;/strong&gt;&lt;span&gt;. At the console, enter&amp;nbsp;&lt;/span&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;install-package Optimizely.ContentGraph.Cms&lt;/span&gt;&lt;/code&gt;&lt;span&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;You now need to add some new configuration to your appsettings.json file:&lt;br /&gt;&lt;/span&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;&quot;Optimizely&quot;: {
  &quot;ContentGraph&quot;: {
    &quot;GatewayAddress&quot;: &quot;&quot;,
    &quot;AppKey&quot;: &quot;&quot;,
    &quot;Secret&quot;: &quot;&quot;,
    &quot;SingleKey&quot;: &quot;&quot;,
    &quot;AllowSendingLog&quot;: &quot;true&quot;
  }
}&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;GatewayAddress&lt;/span&gt;&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; URL for the API Gateway. This value should be set to&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;https://cg.optimizely.com&lt;/span&gt;&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;for all production environments.&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;AppKey&lt;/span&gt;&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; Available via the Content Graph Service Configurations area of PaaSPortal&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;Secret&lt;/span&gt;&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; Available via the Content Graph Service Configurations area of PaaSPortal&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;SingleKey&lt;/span&gt;&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; Available via the Content Graph Service Configurations area of PaaSPortal&lt;/li&gt;
&lt;li&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;AllowSendingLog&lt;/span&gt;&lt;/code&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&amp;ndash; Flag that allows sending errors and warnings to the API Gateway. This data helps the support team investigate when something goes wrong. Defaults to&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;true&lt;/span&gt;&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Next, if you do not use Content Delivery API in your CMS site yet, add the following in the&amp;nbsp;&lt;/span&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;ConfigureServices(IServiceCollection services)&lt;/span&gt;&lt;/code&gt;&lt;span&gt;&amp;nbsp;method of&amp;nbsp;&lt;/span&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;Startup.cs&lt;/span&gt;&lt;/code&gt;&lt;span&gt;. Optimizely Graph depends on Content Delivery API, this is the minimum configuration.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.ConfigureContentApiOptions(o =&amp;gt;
  {
    o.IncludeInternalContentRoots = true;
    o.IncludeSiteHosts = true;
    //o.EnablePreviewFeatures = true;// optional
  });
services.AddContentDeliveryApi(); // required, for further configurations, see https://docs.developers.optimizely.com/content-cloud/v1.5.0-content-delivery-api/docs/configuration
services.AddContentGraph();

//the following is obsolete and is kept for compatibility for now
//services.AddContentGraph(_configuration);&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;The final step is to enable synchronisation, there are two types of synchronisation available, the first is event-driven synchronisation, by default The GraphQL schema &lt;span&gt;stays up-to-date with changes to your site anytime someone edits a content type or one of its properties. The job also synchronizes content to the service any time content is created, updated, or deleted. The second type of synchronisation is via a scheduled job called &quot;Optimizely Content Graph Synchronisation&quot;, normally this would only be run if you have an existing site with pre-existing content that needs to be synchronised.&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now that you have Graph enabled andf content synchronised you are now in a position to start doing semantic searches. You can easily perform semantic searches&lt;span&gt;&amp;nbsp;by changing the value of&amp;nbsp;&lt;/span&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;_ranking&lt;/span&gt;&lt;/code&gt;&lt;span&gt;&amp;nbsp;in the OrderBy&lt;/span&gt;&lt;span&gt;&amp;nbsp;to&amp;nbsp;&lt;/span&gt;&lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;SEMANTIC&lt;/span&gt;&lt;/code&gt; (by default the _ranking field is set to &lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;RELEVANCE&lt;/span&gt;&lt;/code&gt;). In the query shown below, we are performing a semantic search for SitePageData content types where the _fulltext field contains the &#39;search query&#39; specified in the $searchQuery parameter. The data returned is the total number of matching items, and then for each item the name and _fulltext field contents are returned.&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;query SemanticSearch($searchQuery: String)
{
    SitePageData(
        orderBy: { _ranking: SEMANTIC }
        where: { _fulltext: { contains: $searchQuery }})
    {
        total
        items {
            Name
            _fulltext
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;An example of how the data is retured is shown below:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;{
    &quot;data&quot;: {
      &quot;SitePageData&quot;: {
        &quot;total&quot;: 2,
        &quot;items&quot;: [
          {
            &quot;Name&quot;: &quot;Lorem ipsum dolores sit amet.&quot;,
            &quot;_fulltext&quot;: [
              &quot;Lorem ipsum dolores sit amet.&quot;,
              &quot;&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Lorem ipsum dolor&amp;lt;/strong&amp;gt;&amp;lt;em&amp;gt; sit amet consectetur&amp;lt;/em&amp;gt; &amp;lt;span style=\&quot;text-decoration: underline;\&quot;&amp;gt;adipiscing&amp;lt;/span&amp;gt;, &amp;lt;sup&amp;gt;elit&amp;lt;/sup&amp;gt; &amp;lt;sub&amp;gt;sollicitudin&amp;lt;/sub&amp;gt;&amp;lt;/p&amp;gt;\n&amp;lt;p&amp;gt;vivamus congue gravida nunc semper, justo imperdiet interdum litora at. Faucibus integer porttitor odio lacus libero id habitasse vel, mollis fermentum luctus diam parturient eros orci hendrerit, per metus sodales magnis placerat varius lectus. Ultrices scelerisque etiam dapibus in, tincidunt non.&amp;lt;/p&amp;gt;&quot;
            ]
          },
          {
            &quot;Name&quot;: &quot;Fly me home, kid&quot;,
            &quot;_fulltext&quot;: [
              &quot;Fly me home, kid.&quot;,
              &quot;&amp;lt;p&amp;gt;Kid, I&#39;ve flown from one side of this galaxy to the other. I&#39;ve seen a lot of strange stuff, but I&#39;ve never seen anything to make me believe there&#39;s one all-powerful Force controlling everything. There&#39;s no mystical energy field that controls my destiny. It&#39;s all a lot of simple tricks and nonsense. I&#39;m surprised you had the courage to take the responsibility yourself.&amp;lt;/p&amp;gt;&quot;
            ]
          }
        }
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The full code snippet for performing a semantic search against Graph in C# is shown below. This is utilising a NuGet package called &lt;span style=&quot;background-color: #4099ff;&quot;&gt;GraphQL.Client&lt;/span&gt; and to ensure that content is serialized correctly you also need to install the related NuGet package called &lt;code class=&quot;rdmd-code lang- theme-light&quot;&gt;&lt;span class=&quot;cm-s-neo&quot;&gt;GraphQL.Client.Serializer.Newtonsoft&lt;/span&gt;&lt;/code&gt;.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    public async Task&amp;lt;GraphQLResponse&amp;lt;Rootobject&amp;gt;&amp;gt; PerformSemanticSearch(GetChatbotQuery query)
    {
        // Create the GraphQL query using a variable for the search query
        var contentRequest = new GraphQLRequest
        {
            Query = &quot;&quot;&quot;
                    
                                    query SemanticSearch($searchQuery: String)
                                    {
                                        SitePageData(
                                            orderBy: { _ranking: SEMANTIC }
                                            where: { _fulltext: { contains: $searchQuery }})
                                        {
                                            total
                                            items {
                                                Name
                                                _fulltext
                                            }
                                        }
                                    }
                    &quot;&quot;&quot;,
            OperationName = &quot;SemanticSearch&quot;,
            Variables = new
            {
                searchQuery = query.Query
            }
        };

        // Create an instance of the GraphQL client - endpoint hard-coded for this POC
        var graphQlClient = new GraphQLHttpClient(&quot;https://cg.optimizely.com/content/v2?auth=&amp;lt;simplekey&amp;gt;&quot;, new NewtonsoftJsonSerializer());
        
        // The response returned from the GraphQL query
        var graphQlResponse = await graphQlClient.SendQueryAsync&amp;lt;Rootobject&amp;gt;(contentRequest, new CancellationToken());

        return graphQlResponse;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;OpenAI&lt;/h2&gt;
&lt;p&gt;The next step in the process is to utilise whichever LLM you wish to use, this could be OpenAI, Azure OpenAI, etc, and for the purposes of this POC I chose to utilise OpenAI and more specifically the GPT-3.5 Turbo model.&lt;/p&gt;
&lt;h3&gt;What is an LLM&amp;nbsp;&lt;/h3&gt;
&lt;p&gt;A Large Language Model (LLM) is a type of artificial intelligence model designed to understand and generate human-like language on a large scale. These models are typically based on deep learning architectures, specifically transformer architectures, and are trained on massive datasets containing a diverse range of textual information.&lt;/p&gt;
&lt;p&gt;Key characteristics of Large Language Models include:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Scale of Data:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LLMs are trained on vast amounts of text data from diverse sources such as books, articles, websites, and more. This extensive training data helps the model learn the nuances of language and develop a broad understanding of various topics.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Transformer Architecture:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Most LLMs are built on transformer architectures. Transformers are neural network architectures that have proven highly effective for processing sequential data, making them well-suited for natural language processing tasks.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Pre-training and Fine-tuning:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LLMs typically undergo a two-step training process. First, they are pre-trained on a large corpus of text data in an unsupervised manner, learning the statistical patterns and structures of language. After pre-training, the models can be fine-tuned on specific tasks with smaller, task-specific datasets.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Versatility in Language Tasks:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Large Language Models exhibit versatility in performing various language-related tasks, including text generation, completion, summarization, translation, sentiment analysis, question answering, and more. This versatility is a result of the broad and deep knowledge acquired during pre-training.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Contextual Understanding:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;LLMs excel in understanding the context in which words and phrases are used. They can generate contextually relevant responses by considering the entire context of a given input sequence, allowing them to produce more coherent and meaningful outputs.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;GPT-3 Example:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;One prominent example of a Large Language Model is GPT-3 (Generative Pre-trained Transformer 3), developed by OpenAI. GPT-3 is known for its impressive language capabilities, with 175 billion parameters, making it one of the largest language models created.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Below is a snippet of code that performs the following:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;The NuGet package called &quot;Betalgo.OpenAI.GPT3&quot; has been utilised in this POC, this package is deprecated in favour of &quot;Betalgo.OpenAI&quot; however for the purposes of a POC I was happy to utilise this package. Using this package we create an instance of an OpenAPI service client, passing in the OpenAI key taken from the OpenAI account settings.&lt;/li&gt;
&lt;li&gt;The search results returned from the semantic search are processed and saved as rows in a CSV file&lt;/li&gt;
&lt;li&gt;The contents of the CSV file are read, tokenized and returned as a DataFrame.&lt;/li&gt;
&lt;li&gt;OpenAI embeddings are then created from the passed in DataFrame and these are then saved to a separate CSV file.&lt;/li&gt;
&lt;li&gt;Finally the Completion API is called (this API is deprecated and the Chat Completion API should now be used, but for the purposes of the POC I was fine with this) which utilises the initial search query, a prompt and the created embeddings to come up with an answer that relates to the user&#39;s initial intent.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt; // Create OpenAI client (key should be put in config, but fine for POC)
 var openAiService = new OpenAIService(new OpenAiOptions()
 {
         ApiKey = &quot;&amp;lt;openai-key&amp;gt;&quot;
});

// Process the search results, then tokenize the results and finally created embeddings which are saved to a file
SearchResultsProcessor.ProcessSearchResults(semanticSearchResults.Data);
var dataFrame = TextTokenizer.TokenizeTextFile();
await TextEmbedding.CreateEmbeddings(openAiService, dataFrame, &quot;blahblah.com&quot;, 100, 150_000);

// Perform chat completion
var answer = await TextAnswers.AnswerQuestion(openAiService, &quot;blahblah.com&quot;, request.Query);&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Embeddings&lt;/h3&gt;
&lt;p&gt;Embeddings refer to the numerical representations of words, phrases, or sentences that are learned during the training of the model. These embeddings encode semantic information about the language and enable the model to understand the relationships between different words and the context in which they appear.&lt;/p&gt;
&lt;p&gt;Here&#39;s a breakdown of how embeddings work in the context of large language models:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Word Embeddings:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;For individual words, embeddings are vectors in a high-dimensional space. Each word is mapped to a unique vector, and the position of the vector captures information about the word&#39;s meaning. Word embeddings are learned during the pretraining phase of the language model.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Contextual Embeddings:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In large language models like GPT (Generative Pre-trained Transformer), the embeddings are contextual, meaning they take into account the surrounding words in a sentence. The model captures not only the meaning of a word but also how its meaning changes based on the context it appears in. This helps the model generate more contextually relevant responses.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Training Process:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;During the training process, the language model is exposed to a vast amount of text data. It learns to predict the next word in a sequence or fill in missing words based on the context. This process allows the model to develop embeddings that capture the statistical patterns and semantic relationships present in the training data.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Vector Space Representation:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The embeddings result in a vector space where words with similar meanings are closer together in the space. This vector space representation enables the model to perform tasks like language understanding, completion, and generation by manipulating these vectors.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Transfer Learning:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Large language models are often pretrained on a general language understanding task. Once pretrained, they can be fine-tuned for specific tasks with smaller datasets. The embeddings learned during pretraining serve as a foundation of linguistic knowledge that the model can leverage for various downstream applications.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The following code snippet shows how the embeddings are created and then saved to a separate CSV file.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    public static async Task CreateEmbeddings(IOpenAIService openAiService, DataFrame df, string domain, int rpm, int tpm)
    {
        RateLimiter rpmLimiter = new SlidingWindowRateLimiter(
            new SlidingWindowRateLimiterOptions()
            {
                Window = TimeSpan.FromMinutes(1),
                SegmentsPerWindow = 6,
                PermitLimit = rpm,
                QueueLimit = 1,
                QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                AutoReplenishment = true
            }
        );

        RateLimiter tpmLimiter = new TokenBucketRateLimiter(
            new TokenBucketRateLimiterOptions()
            {
                ReplenishmentPeriod = TimeSpan.FromMinutes(1),
                TokensPerPeriod = tpm,
                TokenLimit = tpm,
                QueueLimit = 1,
                QueueProcessingOrder = QueueProcessingOrder.OldestFirst,
                AutoReplenishment = true
            }
        );

        var embeddings = new List&amp;lt;List&amp;lt;double&amp;gt;&amp;gt;();

        for (long rowIndex = 0; rowIndex &amp;lt; df.Rows.Count; rowIndex++)
        {
            var row = df.Rows[rowIndex];
            var text = row[df.Columns.IndexOf(&quot;text&quot;)].ToString();
            var nTokens = int.Parse(row[df.Columns.IndexOf(&quot;n_tokens&quot;)].ToString() ?? string.Empty);

            var leases = await Task.WhenAll(rpmLimiter.AcquireAsync(1).AsTask(), tpmLimiter.AcquireAsync(nTokens).AsTask());

            if (!leases.All(l =&amp;gt; l.IsAcquired))
            {
                Console.WriteLine(&quot;Failed to acquire the permits.&quot;);
                return;
            }
            foreach (RateLimitLease lease in leases)
            {
                lease.Dispose();
            }

            var response = await openAiService.Embeddings.CreateEmbedding(new OpenAI.GPT3.ObjectModels.RequestModels.EmbeddingCreateRequest()
            {
                Input = text,
                Model = &quot;text-embedding-ada-002&quot;
            });
            if ((response?.Data != null) &amp;amp;&amp;amp; (response.Successful))
            {
                embeddings.Add(response.Data[0].Embedding);
            }
            else
            {
                Console.WriteLine(response?.Error?.Message);
                return;
            }

        }

        // Add the token counts to the DataFrame
        var embeddingsColumn = new StringDataFrameColumn(&quot;embeddings&quot;, embeddings.Select(e =&amp;gt; $&quot;[{string.Join(&quot;,&quot;, e)}]&quot;));
        df.Columns.Add(embeddingsColumn);
        DataFrame.SaveCsv(df, $&quot;processed/{domain}/embeddings.csv&quot;);
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Chat Completion&lt;/h3&gt;
&lt;p&gt;The final part of the process is to perform the completion of the question that was asked and the snippet of code below shows how this can be achieved.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;First we create a context, this is an important part of the completion process as it reads in the initial embeddings, and also creates a new embedding based on the original search query, from this the calculations are performed for each embedding which at a high-level detail how close the embedding is to the original question embedding, these are all returned as an IEnumerable list of doubles.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;A prompt is created which basically tells the LLM what to do. In the case of this POC the following prompt is created:&lt;br /&gt;&lt;br /&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;Answer the question based on the context below and provide reference links, and if the question can&#39;t be answered based on the context, say \&quot;I don&#39;t know\&quot;\n\nContext: {context}\n\n---\n\nQuestion: {question}\nAnswer&lt;/code&gt;&lt;/pre&gt;
&lt;br /&gt;As you can see the context created in step 1 is added to the prompt along with the original question.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;li&gt;The OpenAI completion API endpoint is then called which returns a completion response and from this we retrieve the answer.&lt;/li&gt;
&lt;/ol&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    public static async Task&amp;lt;string&amp;gt; AnswerQuestion(
            IOpenAIService openAiService,
        string domain,
        string? question,
        string model = &quot;text-davinci-003&quot;,
        int maxLen = 1800,
        string size = &quot;ada&quot;,
        bool debug = false,
        int maxTokens = 150,
        string? stopSequence = null)
    {
        if (question == null)
        {
            return string.Empty;
        }

        string context = await CreateContext(openAiService, question, GetEmbeddings(domain), maxLen, size);

        if (debug)
        {
            Console.WriteLine(&quot;Context:\n&quot; + context);
            Console.WriteLine(&quot;\n\n&quot;);
        }

        try
        {
            var prompt = $&quot;Answer the question based on the context below and provide reference links, and if the question can&#39;t be answered based on the context, say \&quot;I don&#39;t know\&quot;\n\nContext: {context}\n\n---\n\nQuestion: {question}\nAnswer:&quot;;
            var completionRequest = new CompletionCreateRequest()
            {
                Prompt = prompt,
                Temperature = 0,
                MaxTokens = maxTokens,
                TopP = 1,
                FrequencyPenalty = 0,
                PresencePenalty = 0,
                StopAsList = stopSequence != null ? new[] { stopSequence } : null,
                Model = model
            };

            var completionResponse = await openAiService.Completions.CreateCompletion(completionRequest);
            return completionResponse.Choices[0].Text.Trim();
        }
        catch (Exception e)
        {
            Console.WriteLine(e);
            return string.Empty;
        }
    }

    private static async Task&amp;lt;string&amp;gt; CreateContext(IOpenAIService openAiService, string question, DataFrame df, int maxLen = 1800, string size = &quot;ada&quot;)
    {
        List&amp;lt;List&amp;lt;double&amp;gt;&amp;gt; embeddings = df.Rows.Select(row =&amp;gt; row[df.Columns.IndexOf(&quot;embeddings&quot;)].ToString().Trim(&#39;[&#39;, &#39;]&#39;).Split(&quot;,&quot;).Select(double.Parse).ToList()).ToList();

        var response = await openAiService.Embeddings.CreateEmbedding(new EmbeddingCreateRequest()
        {
            Input = question,
            Model = &quot;text-embedding-ada-002&quot;
        });

        if (!response.Successful)
        {
            return string.Empty;
        }

        var qEmbeddings = response.Data[0].Embedding;


        IEnumerable&amp;lt;double&amp;gt; distances = DistancesFromEmbeddings(qEmbeddings, embeddings);

        var distancesColumn = new PrimitiveDataFrameColumn&amp;lt;double&amp;gt;(&quot;distances&quot;, distances);
        df.Columns.Add(distancesColumn);

        DataFrame sortedDf = df.OrderBy(&quot;distances&quot;);

        List&amp;lt;string?&amp;gt; returns = new();
        int curLen = 0;

        foreach (DataFrameRow row in sortedDf.Rows)
        {
            curLen += int.Parse(row[df.Columns.IndexOf(&quot;n_tokens&quot;)].ToString() ?? string.Empty) + 4;

            if (curLen &amp;gt; maxLen)
            {
                break;
            }

            returns.Add(row[df.Columns.IndexOf(&quot;text&quot;)].ToString());
        }

        return string.Join(&quot;\n\n###\n\n&quot;, returns);
    }

    private static IEnumerable&amp;lt;double&amp;gt; DistancesFromEmbeddings(IEnumerable&amp;lt;double&amp;gt; qEmbeddings, IEnumerable&amp;lt;IEnumerable&amp;lt;double&amp;gt;&amp;gt; embeddings, string distanceMetric = &quot;cosine&quot;)
    {

        Vector&amp;lt;double&amp;gt; questionVector = Vector&amp;lt;double&amp;gt;.Build.DenseOfArray(qEmbeddings.ToArray());

        int numEmbeddings = embeddings.Count();
        double[] distances = new double[numEmbeddings];

        int index = 0;
        foreach (var embedding in embeddings)
        {
            double[] currentEmbedding = embedding.ToArray();
            Vector&amp;lt;double&amp;gt; currentVector = Vector&amp;lt;double&amp;gt;.Build.DenseOfArray(currentEmbedding);

            if (distanceMetric == &quot;cosine&quot;)
            {
                double cosineDistance = 1 - (questionVector * currentVector) / (questionVector.L2Norm() * currentVector.L2Norm());
                distances[index++] = cosineDistance;
            }
            else
            {
                throw new ArgumentException(&quot;Unsupported distance metric&quot;);
            }
        }

        return distances;
    }

    private static DataFrame GetEmbeddings(string domain)
    {
        string csvFilePath = $&quot;processed/{domain}/embeddings.csv&quot;;
        DataFrame df = DataFrame.LoadCsv(csvFilePath);

        return df;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;This is the first time I have really started to look into and explore the capabilities of AI and how it can be used in conjunction with the Optimizely suite of products. The pairing of Graph, Semantic Search and OpenAI means that you can easily create an AI powered conversational chatbot that will give real value to your customers and allow them to ask questions and get returned answers that are inline with what the user&#39;s intent was, there is a lot further that this approach can be taken but for the purposes of a POC I feel that the brief was fully realised.&lt;/p&gt;
&lt;h3&gt;References&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;em&gt;&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://cookbook.openai.com/&quot;&gt;https://cookbook.openai.com/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/dotnet/azure/ai/get-started-app-chat-template?tabs=github-codespaces&quot;&gt;https://learn.microsoft.com/en-us/dotnet/azure/ai/get-started-app-chat-template?tabs=github-codespaces&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/platform-optimizely/v1.4.0-optimizely-graph/docs/installation-and-configuration&quot;&gt;https://docs.developers.optimizely.com/platform-optimizely/v1.4.0-optimizely-graph/docs/installation-and-configuration&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/platform-optimizely/v1.4.0-optimizely-graph/docs/event-driven-synchronization&quot;&gt;https://docs.developers.optimizely.com/platform-optimizely/v1.4.0-optimizely-graph/docs/event-driven-synchronization&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/platform-optimizely/v1.4.0-optimizely-graph/docs/scheduled-synchronization&quot;&gt;https://docs.developers.optimizely.com/platform-optimizely/v1.4.0-optimizely-graph/docs/scheduled-synchronization&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/platform-optimizely/v1.4.0-optimizely-graph/docs/semantic-search&quot;&gt;https://docs.developers.optimizely.com/platform-optimizely/v1.4.0-optimizely-graph/docs/semantic-search&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://openai.com/&quot;&gt;https://openai.com/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;author__image col-sm-5&quot;&gt;&lt;img src=&quot;https://assets-eu-01.kc-usercontent.com/1e387446-ba57-010e-8dbf-944631f19d11/d003b6bf-e48d-43b5-ae36-ace9342bcecb/GrahamCarr_680x454.jpg?w=500&amp;amp;h=1000&amp;amp;auto=format&quot; /&gt;&lt;/div&gt;
&lt;div class=&quot;author__content col-sm-7 keep-margin-bottom&quot;&gt;
&lt;h2&gt;Graham Carr, Lead .NET Developer&lt;/h2&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;I am an experienced Lead .Net Developer with over 25 years&amp;rsquo; experience in a wide range of products and technologies. I have helped companies deliver their digital vision from concept all the way through to delivery. I have a particular passion for DXPs (Digital Experience Platforms) and am a certified developer for products such as Optimizely, Umbraco, Kontent.ai and more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2024-01-01T21:26:23.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - Optimizely CMS 12: The advantages and considerations when exploring an upgrade</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2023/3/a-day-in-the-life-of-an-optimizely-developer---upgrading-cms11-to-cms12/" /><id>&lt;div class=&quot;small blog-post__detail&quot;&gt;&lt;strong&gt;GRAHAM CARR - LEAD .NET DEVELOPER,&amp;nbsp;28&amp;nbsp;Nov&amp;nbsp;2023&lt;/strong&gt;&lt;/div&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;&lt;br /&gt;In 2022, Optimizely released CMS 12 as part of its ongoing evolution of the platform to help provide users with the best-in-class DXP tools. Compared with recent updates, the scale of changes is huge, meaning a more complex upgrade process. It&#39;s worth it, though!&lt;/p&gt;
&lt;p&gt;Here I will talk you through the opportunities and benefits of CMS 12 and explore some of the key considerations around the upgrade process.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Why upgrade to CMS 12?&lt;/strong&gt;&lt;/h2&gt;
&lt;h4&gt;&lt;strong&gt;1. Performance and speed&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Optimizely CMS 12&amp;nbsp;incorporates cutting edge technology which provides performance enhancements (up to 1,200% in certain areas) that result in faster website page load times. This not only improves the user experience but also contributes to better SEO rankings and increased conversion rates. Faster websites tend to have lower bounce rates, keeping visitors engaged with your content for longer periods.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;2. Enhanced user experience&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Optimizely CMS 12 enhances user experience and usability. The user interface has been refined to make it more intuitive and user-friendly. Content editors and administrators will appreciate the streamlined workflows and improved content management tools for faster content updates and improved overall productivity.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;3. Easier integration&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;Optimizely CMS 12 offers seamless integration with third-party tools and services. This makes it easier to connect your CMS with other systems, such as marketing automation platforms, analytics tools, and ecommerce solutions. Integration capabilities can help streamline your digital marketing efforts and provide valuable insights into your website&#39;s performance.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;What do I need to consider during the upgrade process?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Upgrading to CMS 12 isn&amp;rsquo;t a minor task. You&amp;rsquo;ll need careful planning, involving developers, testers, content creators, and the buy-in of key stakeholders, to deliver the upgrade successfully. Here are some factors you&amp;rsquo;ll need to consider:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;Data migration:&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Moving content, media files, and data from your existing CMS 11 install to the new CMS 12 can be complex. Some data structures and database schemas have changed, requiring careful planning and execution to ensure a smooth migration.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Custom code and extensions&lt;/strong&gt;: Optimizely CMS 11 was built on .Net Framework which has now been replaced in favour of .Net Core in Optimizely CMS 12, so if your current CMS implementation includes custom code or extensions, you&amp;rsquo;ll want to check that they are compatible with the new version to avoid any conflicts. If there are conflicts, you may need to redevelop or modify custom functionality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Template and theme compatibility:&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;CMS 12 may introduce changes to template structures and theming &amp;ndash; so this is worth bearing in mind if you currently have customised templates or themes in CMS 11.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Compatibility with add-ons:&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;If your website relies on various add-ons or plugins, you&#39;ll need to verify that these are compatible with CMS 12. Some add-ons may need to be updated or replaced with alternatives.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Third-party integrations:&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Any third-party integrations for analytics, ecommerce, marketing automation, or other services, will also need to be reviewed and verified for compatibility. Some integrations will likely need to be updated or reconfigured to work with CMS 12.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Content revalidation:&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Content that worked well in CMS 11 may require revalidation in CMS 12. Content elements, formatting, and layout may behave differently, necessitating manual adjustments to maintain the desired appearance and functionality.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Training and familiarisation:&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;The user interface and workflow in CMS 12 is different from what your team is accustomed to in CMS 11. Training and familiarisation with the new CMS are essential to ensure your team can efficiently manage content and utilise exciting new features.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Downtime and testing:&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;The upgrade process itself will require reworks and thorough testing to identify and resolve any issues that may arise during the process. This can be time-consuming but is essential to make sure the upgraded version is robust once its live.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Budget and resources:&lt;/strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;Upgrading will have a number of associated costs including development, testing, and potential downtime. You&#39;ll need to allocate resources and budget for the upgrade project accordingly.&lt;/li&gt;
&lt;/ol&gt;
&lt;h2&gt;&lt;strong&gt;I&amp;rsquo;ve heard there are several different technical approaches. What are they?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;As well as making sure the challenges are considered, it&amp;rsquo;s important the technical approach is decided on before you start. There are three clear options:&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;CMS 11 &amp;ndash; CMS 12 direct upgrade&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;This involves running the Optimizely Upgrade Assistant on all the projects contained within the codebase. This approach will require a large amount of effort on re-factoring, fixing and testing to get the website upgraded to CMS 12.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;CMS 12 - Vanilla install upgrade​&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;This approach starts with a brand-new CMS 12 installation. ​A &amp;lsquo;lift and shift&amp;rsquo; of both the front-end and back-end functionality is then performed. This approach will still require re-factoring to be performed through the process especially when pulling back-end code over, to ensure that it is in alignment with Optimizely CMS 12.&lt;/p&gt;
&lt;h4&gt;&lt;strong&gt;CMS 12 - Website rebuild&lt;/strong&gt;&lt;/h4&gt;
&lt;p&gt;According to research, the average lifespan of a website is 2 years and 7 months, so depending on the age and complexity of your website, upgrading to Optimizely CMS 12 might be the perfect opportunity to consider a full redesign and rebuild of your website.&lt;/p&gt;
&lt;p&gt;If a full rebuild is not your chosen path, then I recommend a CMS 12 vanilla install upgrade. This method ensures that all of your website is migrated in the most efficient manner whilst at the same time leveraging the benefits of refactoring your code specifically for CMS 12 as you are going along.&lt;/p&gt;
&lt;h2&gt;&lt;strong&gt;Is the effort required worth it?&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;Absolutely.&lt;strong&gt;&lt;span&gt;&amp;nbsp;&lt;/span&gt;&lt;/strong&gt;Whilst upgrading from Optimizely CMS 11 to CMS 12 will require time, effort and budget, it is a strategic move that can significantly benefit your organisation. From enhanced performance, security, and content personalisation, along with improved user experience, and mobile-friendliness, Optimizely CMS 12 brings many advantages drive competitive advantage in the digital landscape.&lt;/p&gt;
&lt;p&gt;As technology continues to evolve, keeping your CMS up to date is essential for meeting the demands of your audience and achieving your marketing and business goals. I believe that making the transition to Optimizely CMS 12 will ultimately propel your digital presence to new heights. And the longer you delay essential updates, the more technical debt you&amp;rsquo;ll accumulate and the harder the process will get.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;div class=&quot;author__image col-sm-5&quot;&gt;&lt;img src=&quot;https://assets-eu-01.kc-usercontent.com/1e387446-ba57-010e-8dbf-944631f19d11/d003b6bf-e48d-43b5-ae36-ace9342bcecb/GrahamCarr_680x454.jpg?w=500&amp;amp;h=1000&amp;amp;auto=format&quot; /&gt;&lt;/div&gt;
&lt;div class=&quot;author__content col-sm-7 keep-margin-bottom&quot;&gt;
&lt;h2&gt;Graham Carr, Lead .NET Developer&lt;/h2&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;I am an experienced Lead .Net Developer with over 25 years&amp;rsquo; experience in a wide range of products and technologies. I have helped companies deliver their digital vision from concept all the way through to delivery. I have a particular passion for DXPs (Digital Experience Platforms) and am a certified developer for products such as Optimizely, Umbraco, Kontent.ai and more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2023-11-28T08:19:21.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - OptiUKNorth Meetup January 2024</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2023/11/a-day-in-the-life-of-an-optimizely-developer---optiuknorth-meetup-january-2024/" /><id>&lt;p&gt;It&#39;s time for another UK North Optimizely meet up!&lt;br /&gt;&lt;br /&gt;After the success of the last one, Ibrar Hussain (26) and Paul Gruffydd (Kin + Carta) will be hosting again at the same venue - Everyman Cinema, Manchester (see some pics below!).&lt;span class=&quot;white-space-pre&quot;&gt; &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This event will commence on the evening of January 11th 2024.&lt;br /&gt;&lt;br /&gt;&#128226;&amp;nbsp;&#128226;&amp;nbsp;CALL FOR SPEAKERS &#128226;&amp;nbsp;&#128226;&lt;span class=&quot;white-space-pre&quot;&gt; &lt;/span&gt;&lt;br /&gt;If anybody is interested in speaking at the event (we should be able to fit around 4-5 talks in) then please DM Ibrar or Paul.&lt;br /&gt;&lt;br /&gt;We are really excited to push this forward so if you are interested in attending then please register via the following link - &lt;a href=&quot;https://www.optimizely.com/local-dev-meetups&quot;&gt;https://www.optimizely.com/local-dev-meetups&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;&lt;span&gt;Optimizely #OptimizelyUKNorth&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;/link/7876425badeb434d939f909398fab724.aspx&quot; width=&quot;294&quot; alt=&quot;&quot; height=&quot;393&quot; /&gt; &lt;img src=&quot;/link/af4e44867cf94375aa07ab4abfd7783c.aspx&quot; width=&quot;295&quot; alt=&quot;&quot; height=&quot;393&quot; /&gt; &lt;/span&gt;&lt;/h1&gt;
&lt;h1&gt;&lt;span&gt;&lt;img src=&quot;/link/cadbd66550c4408a943e550d3499094b.aspx&quot; width=&quot;522&quot; alt=&quot;&quot; height=&quot;392&quot; /&gt;&lt;br /&gt;&lt;br /&gt;&lt;img src=&quot;/link/2ffabb11cb87477a8a7fc6372cc61f7a.aspx&quot; width=&quot;572&quot; alt=&quot;&quot; height=&quot;422&quot; /&gt; &lt;/span&gt;&lt;/h1&gt;
&lt;h1&gt;&lt;span&gt;&lt;img src=&quot;/link/0a1d4dfba7c64365b08c7e1dd60b03f8.aspx&quot; width=&quot;563&quot; alt=&quot;&quot; height=&quot;422&quot; /&gt;&lt;/span&gt;&lt;/h1&gt;
&lt;div class=&quot;author__image col-sm-5&quot;&gt;&lt;img src=&quot;https://assets-eu-01.kc-usercontent.com/1e387446-ba57-010e-8dbf-944631f19d11/d003b6bf-e48d-43b5-ae36-ace9342bcecb/GrahamCarr_680x454.jpg?w=500&amp;amp;h=1000&amp;amp;auto=format&quot; /&gt;&lt;/div&gt;
&lt;div class=&quot;author__content col-sm-7 keep-margin-bottom&quot;&gt;
&lt;h2&gt;Graham Carr, Lead .NET Developer&lt;/h2&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;I am an experienced Lead .Net Developer with over 25 years&amp;rsquo; experience in a wide range of products and technologies. I have helped companies deliver their digital vision from concept all the way through to delivery. I have a particular passion for DXPs (Digital Experience Platforms) and am a certified developer for products such as Optimizely, Umbraco, Kontent.ai and more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2023-11-28T08:06:18.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - Vertical Slicing in CMS12</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2023/3/a-day-in-the-life-of-an-optimizely-developer---feature-slicing-in-cms12/" /><id>&lt;p&gt;There is such a vast choice these days in how you can build a website, aside from all of the different programming languages out there, there are many different methodologies and patterns that can be used.&lt;/p&gt;
&lt;p&gt;In this blog post, I cover off Vertical Slicing, which is a method that we&amp;nbsp;adopt widely in all of our CMS 12 builds. I personally believe this is a way of ensuring we stick to the important concept of SRP (Single Responsibility Principle) as well as being one of the better ways of structuring projects within an Agile delivery program.&lt;/p&gt;
&lt;h2&gt;Horizontal Layering&amp;nbsp;&lt;/h2&gt;
&lt;p&gt;The traditional way of building .Net applications is via a concept called the Horizontal Layering Approach. This is a software design pattern that divides an application into distinct layers, each with a specific responsibility, to promote separation of concerns, improve maintainability, and facilitate testing and scalability.&lt;/p&gt;
&lt;p&gt;The following are the common layers of a typical .Net Core application:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Presentation Layer: This is the topmost layer of the application that deals with user interface components such as forms, pages, and controls. It is responsible for receiving user inputs and displaying the results to the user. It communicates with the business logic layer to perform actions and retrieve data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Business Logic Layer: This layer contains the business logic of the application, which is responsible for processing the data and applying business rules. It contains the application&#39;s core functionality and domain-specific logic. The business logic layer communicates with the data access layer to retrieve or store data.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Data Access Layer: This layer provides an interface to access the data store, such as a database or file system. It is responsible for querying and retrieving data from the data store and providing it to the business logic layer. The data access layer also handles data validation, caching, and transaction management.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;By separating the application into these distinct layers, developers can better manage complexity, maintain code quality, and achieve greater flexibility and scalability. Changes made in one layer do not affect the other layers, allowing for easier maintenance and modification. Additionally, each layer can be tested independently, which helps to identify issues early in the development process.&lt;/p&gt;
&lt;h3&gt;Optimizely CMS12 Example&lt;/h3&gt;
&lt;p&gt;As CMS 12 is a pre-built application, we do not have the data access layer as described above, however as you can see from the screenshot below of the out-of-the-box AlloyCMS example, the way in which the code is structured does still have distinct horizontal layering.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Business - this folder contains business logic used by the different blocks, pages and other general components&lt;/li&gt;
&lt;li&gt;Controllers - this folder contains the individual controllers for the page types of the website&lt;/li&gt;
&lt;li&gt;Models - this folder contains all of the models used by Content Types (Pages/Blocks), ViewModels, etc.&lt;/li&gt;
&lt;li&gt;Views - this folder contains all of the views for pages, blocks, etc.&amp;nbsp;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/link/6148f3dfdbc34471af4c6e7341db0813.aspx&quot; width=&quot;277&quot; height=&quot;392&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The functionality for a specific feature is clearly spread across multiple folders within the solution and thus increases complexity, testing overhead and can lead to perfomance issues if not implemented correctly.&lt;/p&gt;
&lt;h2&gt;Vertical slicing&lt;/h2&gt;
&lt;p&gt;Vertical slicing is a software development approach where a feature is implemented in a single vertical slice of the application&#39;s architecture, spanning the user interface down to the data access layer. In ASP.NET Core applications, this approach is often used to build small, independent, and self-contained parts of a larger application.&lt;/p&gt;
&lt;p&gt;The idea behind vertical slicing is to create a clear separation of concerns within the application, where each slice represents a specific feature or business capability. Each slice includes all the layers required to implement the feature, such as the user interface, business logic, data access, and data storage. By doing this, the developer can work on a specific feature end-to-end, without being blocked by other parts of the application.&lt;/p&gt;
&lt;p&gt;Some of the benefits of vertical slicing in ASP.NET Core applications include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;&lt;span class=&quot;ui-provider cnc cnd c d e f g h i j k l m n o p q r s t cne cnf w x y z ab ac ae af ag ah ai aj ak&quot;&gt;Easier to maintain, all the code is in one place and does not have to be hunted down.&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;&lt;span class=&quot;ui-provider cnc cnd c d e f g h i j k l m n o p q r s t cne cnf w x y z ab ac ae af ag ah ai aj ak&quot;&gt;Reduced test surface when changing a single feature&lt;/span&gt;&lt;/span&gt;
&lt;ul&gt;
&lt;li&gt;Due to decoupling between features while coupling tightly within a feature&lt;/li&gt;
&lt;li&gt;Has a cost of duplication of some code while maintaining that decoupled natu&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;CMS 12 Example&lt;/h3&gt;
&lt;p&gt;In the example CMS 12 solution structure below (taken from one of our client builds), you can see that we have a &quot;Features&quot; project, this contains a &quot;Common&quot; folder which contains common functionality that is either utilised by a number of different components or is functionality global to Optimizely, examples being Editor Descriptors, Api Controllers, Extensions, Helpers, etc.&lt;/p&gt;
&lt;p&gt;The other folder in this solution (although not required, this is just for additional nesting) is the &quot;Components&quot; folder, this has the following sub-folders:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Blocks - this contains sub-folders for each block content type in the application, each folder encapsulating all of the functionality that the block requires&lt;/li&gt;
&lt;li&gt;Pages - this contains sub-folders for each page content type in the application, each folder encapsulating all of the functionality that the page requires&lt;/li&gt;
&lt;li&gt;Global - this contains sub-folders for each global feature within the application, each folder encapsulating all of the functionality for that feature, examples being footer, header, navigation, breadcrumb, etc.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the example below, we have the AccordionBlock folder, this contains:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;AccordionBlock.cs - this is the model class for the accordion block content type&lt;/li&gt;
&lt;li&gt;AccordionBlockValidator.cs - this is the IValidate class for validation of the accordion block fields&lt;/li&gt;
&lt;li&gt;AccordionContainerBlock.cs - this is the model class for the accordion container block content type (this block contains one or more accordion block content types)&lt;/li&gt;
&lt;li&gt;AccordionContainerBlockViewComponent - this is the ViewComponent class which encapsulate all of the functionality for the accordion block feature&lt;/li&gt;
&lt;li&gt;AccordionContainerViewModel - this is the view model that is passed into the View file&lt;/li&gt;
&lt;li&gt;AccordionViewModel - this is the view model that is passed into the View file as part of AccordionContainerViewModel&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;img src=&quot;/link/99728b3ec68c4560a4f8a41542752194.aspx&quot; width=&quot;294&quot; height=&quot;273&quot; /&gt;&lt;/p&gt;
&lt;p&gt;The next screenshot shows the &quot;Web&quot; project, this contains the standard &quot;Views&quot; folder, with sub-folders for the different pages in the application, there is also a &quot;Components&quot; folder (although not required, this is just for additional nesting) which contains folders for all of the components (blocks and global) that exist in the features project. Within each of these folders is a single Index.cshtml file which is the View file for the related View Component.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/1ed72cf345a6445fafe8579c57390c71.aspx&quot; width=&quot;293&quot; height=&quot;408&quot; /&gt;&lt;/p&gt;
&lt;p&gt;It is clear to see that this method of structuring your applications, provides a much cleaner and more concise way of grouping all of the functionality and related files for a feature into easily distinguishable folders.&lt;/p&gt;
&lt;h2&gt;Summary&lt;/h2&gt;
&lt;p&gt;In summary, while the layered approach to building a .Net Core application does have many benefits, it also has some drawbacks that developers should be aware of. Here are some potential cons to consider:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Increased complexity: The layered approach can make the application more complex as it requires more code and more layers of abstraction. This can lead to increased development time and greater difficulty in maintaining the application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Performance issues: The layered approach can lead to performance issues if not implemented correctly. Each layer adds an overhead that can slow down the application. Additionally, excessive or inefficient data access calls can cause delays in data retrieval. Also performance issues can arise due to repositories and services doing more than they need to do for the intended usage.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Over-engineering: The layered approach can lead to over-engineering if the application does not require a high level of complexity. This can lead to unnecessary code and can make the application difficult to understand and maintain.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Testing overhead: While testing each layer separately can help identify issues early on, it can also lead to increased testing overhead. Testing each layer separately can be time-consuming and may require more resources.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Lack of flexibility: The layered approach can make the application less flexible as it can be difficult to make changes that affect multiple layers. This can lead to code duplication and increased maintenance costs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;Lots of model mappers needed for moving between layers&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The main benefit of a layered approach is that:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;&lt;span class=&quot;ui-provider cnc cnd c d e f g h i j k l m n o p q r s t cne cnf w x y z ab ac ae af ag ah ai aj ak&quot;&gt;You are able to swap out a layer, namely swap out presentation or database while keeping the rest, although usages of this are extremely few and far between&lt;/span&gt;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;When we look at Vertical Slicing however we can see that it has the following pros:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Faster feedback: With vertical slicing, developers can quickly get feedback on the feature they are building as they work through all layers of the application. This helps to identify issues early and address them before they become bigger problems.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Better user experience: Vertical slicing ensures that features are built from end to end, which helps to ensure a seamless user experience. This can lead to higher user satisfaction and increased adoption of the application.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Greater agility: Vertical slicing enables developers to quickly deliver features and respond to changing requirements. As each feature is built from end to end, developers can quickly make changes to any layer of the application without affecting other features.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Improved collaboration: Vertical slicing promotes collaboration among developers as they work together to build features from end to end. This approach also helps to ensure that developers have a better understanding of how all layers of the application work together.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Better maintainability: Vertical slicing can lead to better maintainability as developers can quickly understand how a feature is built and make changes as needed. This can help to reduce the amount of technical debt in the application.&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;So in conclusion, while the layered approach has its benefits, vertical slicing can be a useful alternative approach for .NET developers, particularly in projects where speed, user experience, and agility are critical.&lt;/p&gt;
&lt;h2&gt;Resources&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://code-maze.com/vertical-slice-architecture-aspnet-core/&quot;&gt;https://code-maze.com/vertical-slice-architecture-aspnet-core/&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://dev.to/htech/exploring-vertical-slices-in-dotnet-core-3mik/&quot;&gt;https://dev.to/htech/exploring-vertical-slices-in-dotnet-core-3mik/&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://awesome-architecture.com/vertical-slice-architecture/&quot;&gt;https://awesome-architecture.com/vertical-slice-architecture/&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://medium.com/aspnetrun/layered-architecture-with-asp-net-core-entity-framework-core-and-razor-pages-53a54c4028e3/&quot;&gt;https://medium.com/aspnetrun/layered-architecture-with-asp-net-core-entity-framework-core-and-razor-pages-53a54c4028e3/&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://www.c-sharpcorner.com/article/three-tier-architecture-in-asp-net-core-6-web-api/&quot;&gt;https://www.c-sharpcorner.com/article/three-tier-architecture-in-asp-net-core-6-web-api/&lt;/a&gt;&amp;nbsp;&lt;/p&gt;

&lt;div class=&quot;author__image col-sm-5&quot;&gt;&lt;img src=&quot;https://assets-eu-01.kc-usercontent.com/1e387446-ba57-010e-8dbf-944631f19d11/d003b6bf-e48d-43b5-ae36-ace9342bcecb/GrahamCarr_680x454.jpg?w=500&amp;amp;h=1000&amp;amp;auto=format&quot; /&gt;&lt;/div&gt;
&lt;div class=&quot;author__content col-sm-7 keep-margin-bottom&quot;&gt;
&lt;h2&gt;Graham Carr, Lead .NET Developer&lt;/h2&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;I am an experienced Lead .Net Developer with over 25 years&amp;rsquo; experience in a wide range of products and technologies. I have helped companies deliver their digital vision from concept all the way through to delivery. I have a particular passion for DXPs (Digital Experience Platforms) and am a certified developer for products such as Optimizely, Umbraco, Kontent.ai and more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2023-03-20T14:05:51.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - OptiNorth Meetup March 2023</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2023/3/a-day-in-the-life-of-an-optimizely-developer---optinorth-meetup-march-203/" /><id>&lt;p&gt;Hello and welcome to another instalment of A Day In The Life Of An Optimizely Developer.&amp;nbsp;Last night (1st March 2023) I was excited to have attended the March 2023 OptiNorth Meetup in Manchester and in this blog post I will give an overview of the evening and what my learnings and main takeaways were.&lt;/p&gt;
&lt;h2&gt;The Venue&lt;/h2&gt;
&lt;p&gt;The meetup location was the Everyman Cinema located on Quay Street, Manchester. I have never been to an Everyman Cinema and was very impressed by the venue, in terms of facilities and comfort. I arrived at 5:15 allowing 45 minutes for networking before the talks began at 6pm.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/7bd28f07d7e3432fae91f882b9c64bf5.aspx&quot; width=&quot;569&quot; height=&quot;759&quot; /&gt;
&lt;figcaption&gt;Outside the venue&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;The networking for the area took place in the bar area of the Everyman Cinema and was a perfect and relaxing area to chat with the attendees and speakers both prior to the presentations and during the mid-point break and after the presentations (also helped by both the open bar tab and food).&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/66c189dffbd940b6bf8888dff028007e.aspx&quot; width=&quot;796&quot; height=&quot;597&quot; style=&quot;width: 789px; height: 592px;&quot; /&gt;
&lt;figcaption&gt;Pre-talk networking in the bar area&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;As you can see by the next image, the presentation room was in one of the cinema rooms, having never been to an Everyman Cinema before I have to say that I was impressed by the use of sofas and cushions and proved to be both small enough to hear and see everything but also comfy and relaxing at the same time.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/7e244a075a044edc988ad9b157d65bc9.aspx&quot; width=&quot;1478&quot; alt=&quot;&quot; height=&quot;1108&quot; style=&quot;width: 789px; height: 592px;&quot; /&gt;
&lt;figcaption&gt;Comfy sofas and cushions&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Introductions&lt;/h2&gt;
&lt;p&gt;The presentations kicked off with an introduction by the sponsors of the meeting, our very own Ibrar Hussain, Technical Director at &lt;a href=&quot;https://www.26-agency.com&quot;&gt;26&lt;/a&gt; and &lt;span&gt;Paul Gruffydd, Technical Director at &lt;a href=&quot;https://www.kinandcarta.com&quot;&gt;Kin + Carta&lt;/a&gt; - they both gave a brief overview of who they were and what their job roles were, and gave a small introduction to the speakers of the evening and what the talks were about.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/da8022183a264cfeabff954de21ce9a4.aspx&quot; width=&quot;789&quot; alt=&quot;&quot; height=&quot;582&quot; /&gt;
&lt;figcaption&gt;Ibrar Hussain, Technical Director at &lt;a href=&quot;https://www.26-agency.com&quot;&gt;26&lt;/a&gt; and &lt;span&gt;Paul Gruffydd, Technical Director at &lt;a href=&quot;https://www.kinandcarta.com&quot;&gt;Kin + Carta&lt;/a&gt;&lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;Simplifying a new website build on CMS12&lt;/h2&gt;
&lt;p&gt;The first talk kicked off by one of my work colleagues at &lt;a href=&quot;https://www.26-agency.com&quot;&gt;26&lt;/a&gt; Mark Stott, who is our Lead Optimizely Developer as well as an &lt;a href=&quot;/link/ed828821aeb74380ba334ce78ad022f5.aspx&quot;&gt;OMVP&lt;/a&gt; - the content of his talk was on how we can simplify new website builds when utilising Optimizely CMS12.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/ce1930d92ea9492c9e1f7907e81e2f45.aspx&quot; width=&quot;789&quot; alt=&quot;&quot; height=&quot;592&quot; /&gt;
&lt;figcaption&gt;Simplifying new CMS12 builds&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;The content of this talk covered the following areas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What is great about CMS 12, including the use of .Net 6 architecture and therefore benefiting from the performance and security improvements this new framework provides&lt;/li&gt;
&lt;li&gt;How we can utilise Razor Class Libraries to create NuGet packages for specific areas of functionality that are generally repeated across many website builds (e.g. News functionality, Events functionality, etc.)
&lt;ul&gt;
&lt;li&gt;These packages can contain all of the generic properties, functionality, associated JS and razor views, stylesheets could be added but as the layout and styling will differ per site it is recommended not add these&lt;/li&gt;
&lt;li&gt;Once the package has been added to the project you can override the classes to hide properties that might not apply for a specific client and you can also override the razor views to provide a different layout/structure if that is also required, at this point CSS files can also be added to provide the unique styling&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;Some thought has to be put into what is put into the razor class library, but it needs to be made as generic as possible to be useful for many different web projects&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mark then went into a demo of this showing an example razor class library to provide news functionality, this was then added as a package to a CMS12 build, and he then showed how we can utilise and then override the functionality and view(s)&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/eebf47f777f64609a905ab474d3fe224.aspx&quot; width=&quot;790&quot; alt=&quot;&quot; height=&quot;593&quot; /&gt;
&lt;figcaption&gt;Mark doing a demo of utilising Razor Class Libraries&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;In his summary he made it clear that the use of Razor Class Libraries can help you to build out features set to an exceptional standard that can be installed as packages.&lt;/p&gt;
&lt;h2&gt;Liquid Templating&lt;/h2&gt;
&lt;p&gt;The next talk was done by &lt;span&gt;Mark Everard who is an Optimizely Consultant and owner of the company FTT (First Three Things). His talk was on liquid templating, for those of you who have never heard of Liquid, it is an open-source templating language that was created by and is used in production by Shopify.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/c9151c38f9704c0da98f73a67dc213a6.aspx&quot; width=&quot;789&quot; alt=&quot;&quot; height=&quot;592&quot; /&gt;
&lt;figcaption&gt;Liquid Templating&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;During his talk, Mark covered off the following areas, however the reasoning behind providing Liquid Templating is that Optimizely are trying to move away from relying on C# skills to build out fazor views and associated functionality. There are development teams spread across the globe who might not have any C# resource, therefore providing Liquid Templating allows non-C# developers to build out functionality in Liquid Templates whilst at the same time utilising the helper methods that it provides.&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What liquid templating is, it&#39;s benefits and why Optimizely are pushing for different view engines&lt;/li&gt;
&lt;li&gt;An overview of the Liquid Templating NuGet package that Mark created in conjunction with Optimizely&lt;/li&gt;
&lt;li&gt;An overview of the helper methods that the package also provides&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Mark then went on to do a demo of the package, which included how to create liquid templates, how they get added in the Optimizely solution and some examples of utilising the various helper method classes that are available.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/da4385d43fad4256b04a02fd084efdf7.aspx&quot; width=&quot;789&quot; alt=&quot;&quot; height=&quot;592&quot; /&gt;
&lt;figcaption&gt;Liquid Templating Optimizely Package Demo&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;In his summary he re-iterated the direction that Optimizely want to be heading and why the Liquid Templating package is useful for certain development teams.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;When the talk and question time finished, we took a break for food and more networking (who doesn&#39;t like free food and drink at an event!!)&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;GraphQL &amp;amp; Optimizely Content Graph&lt;/h2&gt;
&lt;p&gt;After the break, the next person to talk was &lt;span&gt;Paul Gruffydd, Technical Director at &lt;a href=&quot;https://www.kinandcarta.com&quot;&gt;Kin + Carta&lt;/a&gt;&lt;/span&gt; who covered GraphQL and Optimizely Content Graph.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/44ba1aad452f4598aeca51025b5162ff.aspx&quot; width=&quot;789&quot; alt=&quot;&quot; height=&quot;592&quot; /&gt;
&lt;figcaption&gt;GraphQL and Optimizely Content Graph&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;The talk that Paul did started with an overview of what GraphQL is and why it is useful compared to REST API&#39;s, for instance GraphQL allows you to retrieve specific information from an object whenever you like, whereas REST Apis generally need to return the full model of an object to be useful for different use cases.&lt;/p&gt;
&lt;p&gt;As an overview, the following was covered during this talk:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;What GraphQL is and it&#39;s use cases&lt;/li&gt;
&lt;li&gt;How GraphQL has been implemented and made available by Optimizely Content Graph&lt;/li&gt;
&lt;li&gt;The difference in speed between GraphQL queries and traditional REST Api calls&lt;/li&gt;
&lt;li&gt;How the Strawberry Shake GraphQL client for Visual Studio can be used&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Paul then did a demo of creating and running some GraphQL queries within Optimizely, whilst at the same time showing how much faster GraphQL queries are compared to REST Api calls. He also showed how the Strawberry Shake Visual Studio plugin can be used to create GraphQL clients.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/9ccc5832a1764a12932b3c7d37693afa.aspx&quot; width=&quot;789&quot; alt=&quot;&quot; height=&quot;592&quot; /&gt;
&lt;figcaption&gt;Demo time&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2&gt;How to run successful experimentation projects with Optimizely&lt;/h2&gt;
&lt;p&gt;The final talk was done by Optimizely&#39;s own Simon Chapman who is a &lt;span&gt;Lead Solution Architect and his talk was on how to run successful experimentation projects with Optimizely.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/5178a1d58ff343768cfc18b66c0a77b3.aspx&quot; width=&quot;789&quot; alt=&quot;&quot; height=&quot;592&quot; /&gt;
&lt;figcaption&gt;Running successful experimentation projects with Optimizely&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;Simon provided an overview of what Optimizely Experimentation is and how it fits into the landscape of the Optimizely product suite as well as the following areas:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The integration roadmap and how it can integrate with things such as BigQuery and an upcoming integration with GA4 v1.1 and v1.2&lt;/li&gt;
&lt;li&gt;Design best practices when planning for experiments such as using unique ids for elements, avoid using HTML tables for layouts, etc.&lt;/li&gt;
&lt;li&gt;Improving site performance for experimentation tests, such as snippet placement, increase the Cache Expiration (TTL), deploy the snippet synchronously, etc.&lt;/li&gt;
&lt;li&gt;An important note about using the show/hide elements to deliver substantial changes outside of Optimizely Wev Experimentation, e.g. embedding images and HTML in the native HTML tags and then using show/hide to create the versions of the pages you are testing.&lt;/li&gt;
&lt;li&gt;A comparison chart of different experimentation platforms that shows Optimizely&#39;s experimentation is the best in the class&lt;/li&gt;
&lt;li&gt;A brief overview of Optimizely Connect Platform (OCP) which is one point of integration for the Optimizely ecosystem and 3rd party platforms, and a showcase of the OCP App Marketplace.&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/4f4f4cb97a1745ff8c6efeed0591d9b6.aspx&quot; width=&quot;1901&quot; alt=&quot;&quot; height=&quot;1426&quot; style=&quot;width: 789px; height: 592px;&quot; /&gt;
&lt;figcaption&gt;How and where experimentation sits in the Optimizely space&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/709d112ff45e486f8f2078d116f2b7d4.aspx&quot; width=&quot;789&quot; alt=&quot;&quot; height=&quot;592&quot; /&gt;
&lt;figcaption&gt;Optimizely Experiementation Comparison&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;Simon then finished off his talk by showing some examples of how to setup some experimentations and how they are then run and data captured to be analysed so you can determine the results of the tests.&lt;/p&gt;
&lt;h2&gt;Main Takeaways and Learnings&lt;/h2&gt;
&lt;p&gt;All in all the event was very insightful and gave me a lot of food for thought in terms of how we could utilise some of these practices and technologies in the Optimizely builds we do at &lt;a href=&quot;https://www.26-agency.com&quot;&gt;26&lt;/a&gt; - the main points that I take away from this event are as follows:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;How Razor Class Libraries can be utilised to create specific features that are regularly used in CMS builds, packaged up as NuGet packages and utilised and overridden in CMS builds, feature slicing is an important concept that I believe should be used wherever possible and this goes a long way to helping with this, it also helps you provide value rather than features.&lt;/li&gt;
&lt;li&gt;What Liquid Templating is and why it is the direction that Optimizely want to be heading, it was also made clear how it comes in useful for non-C# development teams, I particularly liked seeing the demo and how much thought had gone into providing helper methods.&lt;/li&gt;
&lt;li&gt;What GraphQL is and why it can be preferable to REST Apis, the demo was a great showcase of its possibilities and showcasing the speed compared to REST Apis was quite an eye opener.&lt;/li&gt;
&lt;li&gt;My knowledge of Optimizely Experimentation is now much more improved and I was particularly impressed by how blazing fast it is and how it outdoes it&#39;s competitors. It was also interesting to hear about the deprecation of Google Optimize and the cross-over special offer Optimizely have created to help customers move from Optimize to Optimizely Experimentation.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;Below are a list of links to further information on areas of the talks by all four speakers.&lt;/p&gt;
&lt;h3&gt;Simplifying CMS12 Builds&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/GeekInTheNorth&quot;&gt;https://github.com/GeekInTheNorth&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://www.linkedin.com/in/mark-antony-stott/&quot;&gt;https://www.linkedin.com/in/mark-antony-stott/&lt;/a&gt;&amp;nbsp;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-7.0&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;tabs=visual-studio&quot;&gt;https://learn.microsoft.com/en-us/aspnet/core/razor-pages/ui-class?view=aspnetcore-7.0&amp;amp;tabs=visual-studio&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://learn.microsoft.com/en-us/aspnet/core/blazor/components/class-libraries?view=aspnetcore-7.0&amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;amp;tabs=visual-studio&quot;&gt;https://learn.microsoft.com/en-us/aspnet/core/blazor/components/class-libraries?view=aspnetcore-7.0&amp;amp;tabs=visual-studio&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://medium.com/swlh/using-razor-class-library-rcl-to-generate-a-common-ui-for-all-your-dotnet-web-projects-be970d4a82a0&quot;&gt;https://medium.com/swlh/using-razor-class-library-rcl-to-generate-a-common-ui-for-all-your-dotnet-web-projects-be970d4a82a0&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Liquid Templating&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/markeverard&quot;&gt;https://github.com/markeverard&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.linkedin.com/in/everard/&quot;&gt;https://www.linkedin.com/in/everard/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://github.com/episerver/liquid-templating-cms&quot;&gt;https://github.com/episerver/liquid-templating-cms&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;/link/72f9dc98320d484c860be38dcee469ef.aspx&quot;&gt;https://world.optimizely.com/blogs/deane-barker/dates/2023/1/introducing-liquid-templating/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://shopify.github.io/liquid/&quot;&gt;https://shopify.github.io/liquid/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://nuget.optimizely.com/package/?id=Optimizely.CMS.Labs.LiquidTemplating&quot;&gt;https://nuget.optimizely.com/package/?id=Optimizely.CMS.Labs.LiquidTemplating&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;GraphQL and Optimizely Content Graph&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/paulgruffydd&quot;&gt;https://www.linkedin.com/in/paulgruffydd&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://github.com/PaulGruffyddAmaze&quot;&gt;https://github.com/PaulGruffyddAmaze&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/digital-experience-platform/v1.4.0-content-graph/docs/project-graphql&quot;&gt;https://docs.developers.optimizely.com/digital-experience-platform/v1.4.0-content-graph/docs/project-graphql&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/digital-experience-platform/v1.4.0-content-graph/docs/using-the-graphql-api&quot;&gt;https://docs.developers.optimizely.com/digital-experience-platform/v1.4.0-content-graph/docs/using-the-graphql-api&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/digital-experience-platform/v1.4.0-content-graph/docs&quot;&gt;https://docs.developers.optimizely.com/digital-experience-platform/v1.4.0-content-graph/docs&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://graphql.org/&quot;&gt;https://graphql.org/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://chillicream.com/docs/strawberryshake/v13&quot;&gt;https://chillicream.com/docs/strawberryshake/v13&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://marketplace.visualstudio.com/items?itemName=ChilliCream.strawberryshake-visualstudio&quot;&gt;https://marketplace.visualstudio.com/items?itemName=ChilliCream.strawberryshake-visualstudio&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;h3&gt;Successful Experimentation Projects with Optimizely&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://www.linkedin.com/in/sgchapman/&quot;&gt;https://www.linkedin.com/in/sgchapman/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.optimizely.com/products/experiment/feature-experimentation/&quot;&gt;https://www.optimizely.com/products/experiment/feature-experimentation/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/experimentation&quot;&gt;https://docs.developers.optimizely.com/experimentation&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/experimentation/v10.0.0-web/docs&quot;&gt;https://docs.developers.optimizely.com/experimentation/v10.0.0-web/docs&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.optimizely.com/insights/feature-experimentation-demo/&quot;&gt;https://www.optimizely.com/insights/feature-experimentation-demo/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.optimizely.com/insights/experimentation-series-dev/&quot;&gt;https://www.optimizely.com/insights/experimentation-series-dev/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://www.optimizely.com/google/optimize/&quot;&gt;https://www.optimizely.com/google/optimize/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/experimentation/v3.1.0-full-stack/docs&quot;&gt;https://docs.developers.optimizely.com/experimentation/v3.1.0-full-stack/docs&lt;/a&gt;&amp;nbsp;&lt;/p&gt;
&lt;div class=&quot;author__image col-sm-5&quot;&gt;&lt;img src=&quot;https://assets-eu-01.kc-usercontent.com/1e387446-ba57-010e-8dbf-944631f19d11/d003b6bf-e48d-43b5-ae36-ace9342bcecb/GrahamCarr_680x454.jpg?w=500&amp;amp;h=1000&amp;amp;auto=format&quot; /&gt;&lt;/div&gt;
&lt;div class=&quot;author__content col-sm-7 keep-margin-bottom&quot;&gt;
&lt;h2&gt;Graham Carr, Lead .NET Developer&lt;/h2&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;I am an experienced Lead .Net Developer with over 25 years&amp;rsquo; experience in a wide range of products and technologies. I have helped companies deliver their digital vision from concept all the way through to delivery. I have a particular passion for DXPs (Digital Experience Platforms) and am a certified developer for products such as Optimizely, Umbraco, Kontent.ai and more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2023-03-03T14:47:52.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - Implementing Identity Server 4 and ASP.Net Identity</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2023/2/a-day-in-the-life-of-an-optimizely-developer---implementing-identity-server-4-and-asp-net-identity/" /><id>&lt;p&gt;Hello and welcome to another instalment of A Day In The Life Of An Optimizely Developer.&lt;/p&gt;
&lt;p&gt;Recently on a CMS 12 build that I was doing for a client I was faced with the challenge of implementing Identity Server 4 for the website user login, whilst still retaining the default ASP.Net Identity login for Optimizely CMS. At the outset this sounded quite easy, but reality showed me otherwise, therefore I have written this blog post to provide reader&#39;s with an overview of how you setup two different authentication schemes at the same time.&lt;/p&gt;
&lt;p&gt;In this implementation, I needed to integrate with a 3rd party SSO solution that was running on Identity Server 4. For those not aware of Identity Server, combining OpenID Connect and OAuth 2.0 is considered one of the best approaches to securing modern applications and Identity Server 4 is an implementation of these two protocols. I won&#39;t delve too deep into what Identity Server 4 is and how it is used, I have added some links in the reference section at the end of this blog post that provide more information if you fancy some bedtime reading.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://docs.wso2.com/download/attachments/60493891/OAuth%20grant%20types%20-%20AuthorizationCode%20%281%29.png?version=1&amp;amp;amp;amp;amp;amp;amp;amp;modificationDate=1510603077000&amp;amp;amp;amp;amp;amp;amp;amp;api=v2&quot; width=&quot;601&quot; height=&quot;385&quot; /&gt;&lt;/p&gt;
&lt;p&gt;Before we start with the implementation we first need to add a reference to the Microsoft.AspNetCore.Authentication.OpenIdConnect NuGet package, this allows us to use OpenIdConnect for our implementation with Identity Server 4. The official documentation describes OpenID Connect as:&lt;/p&gt;
&lt;p&gt;&lt;em&gt;&quot;OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;OpenID Connect allows clients of all types, including Web-based, mobile, and JavaScript clients, to request and receive information about authenticated sessions and end-users. The specification suite is extensible, allowing participants to use optional features such as encryption of identity data, discovery of OpenID Providers, and logout, when it makes sense for them.&quot;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/56702db27567454fadb15138fac57f5c.aspx&quot; /&gt;&lt;/p&gt;
&lt;p&gt;So moving onto the implementation of this, the first step is to add a new class called &quot;UserAuthenticationServiceExtensions&quot; which will act as the middleware that you inject in the Startup.cs file (detailed later). We first need to add the constructor for the AddUserAuthentication class, this needs to call the AddCmsAspNetIdentity method that adds the authentication scheme for the CMS logins as Asp.Net Identity, the next call is to a private method AddIdentityServer that adds the OpenID Connect and IdentityServer scheme functionality.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    public static IServiceCollection AddUserAuthentication(
        this IServiceCollection services,
        IWebHostEnvironment environment,
        IConfiguration configuration)
    {
        services.AddCmsAspNetIdentity&amp;lt;ApplicationUser&amp;gt;();
        services.AddIdentityServer(configuration);

        return services;
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Within the AddIdentityServer method we first need to a add couple of constants that define both an Authentication and Challenge scheme to be used in the Identity Server implementation utilising OpenID Connect.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;    private const string AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme; // CookieAuthenticationDefaults.AuthenticationScheme = 
 &quot;Cookies&quot;

    private const string ChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; // OpenIdConnectDefaults.AuthenticationScheme = &quot;OpenIdConnect&quot;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next step is to add the call to the AddAuthentication method to define the default Authentication and Challenge schemes. We can see that the default challenge scheme is set to &quot;policy-scheme&quot;, this is a custom scheme that is defined later in the class and is the important part for ensuring the application can determine when the two different authentication schemes are to be used.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddAuthentication(options =&amp;gt;
{
       options.DefaultScheme = AuthenticationScheme;
       options.DefaultChallengeScheme = &quot;policy-scheme&quot;;
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;We next need to add the two cookies required for both authentication schemes. The first cookie is the one that will be utilised by the Asp.Net Identity authentication scheme and the second cookie is the one that will be used by the OpenID Connect authentications scheme.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;.AddCookie(AuthenticationScheme, options =&amp;gt;
{
     // Defines a path to redirect the user to if they don&#39;t have access to a page.
     // This page should return a 200 response so as to not cause authentication loops.
     options.AccessDeniedPath = new PathString(&quot;/no-access&quot;);
})
.AddCookie(ChallengeScheme)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next part of the implementation is to add the OpenID Connect specific functionality calling the &quot;AddOpenIdConnect&quot; method. I have just highlighted the important parts to call out of this functionality as the rest is pretty standard implementation and also depends very much on how your Identity Server 4 client has been setup.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;So in this call we can see that we pass in the name of the authentication scheme we want to associate with OpenID Connect, in this case &quot;IdentityServer&quot;, next we define the default Sign In and Sign Out scheme which is set to the ChallengeScheme constant we created earlier. We next specify the response type, in this case the Identity Server client has been setup for AuthorizationCode flow (Identity Server has five different flows (more information on flows in the links at the end of this blog). The callback path is also set and for OpenID Connect should be set to &quot;/signin-oidc&quot;. UsePkce is set to false in this case, but this depends on how your client has been setup (Pkce stands for Proof Key for Code Exchange standard and is detailed in the references section)&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;.AddOpenIdConnect(&quot;IdentityServer&quot;, options =&amp;gt;
{
    options.SignInScheme = ChallengeScheme;
    options.SignOutScheme = ChallengeScheme;
    options.ResponseType = OpenIdConnectResponseType.Code;
    options.CallbackPath = &quot;/signin-oidc&quot;;
    options.UsePkce = false;

    options.Authority = authority;
    options.RequireHttpsMetadata = requireHttpsMetadata;
    options.ClientId = clientId;
    options.ClientSecret = clientSecret;
    ....
})&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The final part and indeed the most important part is to define the custom policy scheme that we referenced earlier. We call the &quot;AddPolicyScheme&quot; method for this, passing in the name of the new scheme. Next we need to define the paths that determine which authentication scheme should be used. If the path starts with &quot;/episerver&quot; or &quot;/util&quot; we know this is a user trying to login to the CMS and therefore we return the scheme that is used by Asp.Net Identity, in this case &quot;Identity.Application&quot;, for all other paths we just return &quot;IdentityServer&quot; which in this case is the scheme used by OpenId Connect.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;.AddPolicyScheme(&quot;policy-scheme&quot;, null, options =&amp;gt;
{
    options.ForwardDefaultSelector = ctx =&amp;gt;
    {
        if (ctx.Request.Path.StartsWithSegments(&quot;/episerver&quot;, StringComparison.OrdinalIgnoreCase) ||
        ctx.Request.Path.StartsWithSegments(&quot;/util&quot;, StringComparison.OrdinalIgnoreCase))
        {
            return IdentityConstants.ApplicationScheme; // IdentityConstants.ApplicationScheme = &quot;Identity.Application&quot;
        }

        return &quot;IdentityServer&quot;;
    };
});&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The full code of the UserAuthentication class is provided below:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using System.Text;

using EPiServer.Cms.UI.AspNetIdentity;

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;

public static class UserAuthenticationServiceExtensions
{
    private const string AuthenticationScheme = CookieAuthenticationDefaults.AuthenticationScheme; // CookieAuthenticationDefaults.AuthenticationScheme = 
 &quot;Cookies&quot;

    private const string ChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; // OpenIdConnectDefaults.AuthenticationScheme = &quot;OpenIdConnect&quot;

    /// &amp;lt;summary&amp;gt;
    /// Sets up authentication based on one of the following schemes:
    /// Optimizely CMS Identities for the CMS login using AspNet Identity.
    /// Identity Server using Open ID connect for front-end user login.
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&quot;services&quot;&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&quot;environment&quot;&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&quot;configuration&quot;&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public static IServiceCollection AddUserAuthentication(
        this IServiceCollection services,
        IWebHostEnvironment environment,
        IConfiguration configuration)
    {
        services.AddCmsAspNetIdentity&amp;lt;ApplicationUser&amp;gt;();
        services.AddIdentityServer(configuration);

        return services;
    }

    /// &amp;lt;summary&amp;gt;
    /// Sets up authentication based on Identity Server 4 using Open ID Connect
    /// &amp;lt;/summary&amp;gt;
    /// &amp;lt;param name=&quot;services&quot;&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;param name=&quot;configuration&quot;&amp;gt;&amp;lt;/param&amp;gt;
    /// &amp;lt;returns&amp;gt;&amp;lt;/returns&amp;gt;
    public static void AddIdentityServer(this IServiceCollection services, IConfiguration configuration)
    {
        var identityServerSettings = configuration.GetSection(nameof(IdentityServerSettings)).Get&amp;lt;IdentityServerSettings&amp;gt;();
        var authority = identityServerSettings?.Authority ?? string.Empty;
        _ = bool.TryParse(identityServerSettings?.RequireHttpsMetadata ?? &quot;true&quot;, out bool requireHttpsMetadata);
        var clientId = identityServerSettings?.ClientId ?? string.Empty;
        var clientSecret = identityServerSettings?.ClientSecret ?? string.Empty;

        services.AddAuthentication(options =&amp;gt;
                {
                    options.DefaultScheme = AuthenticationScheme;
                    options.DefaultChallengeScheme = &quot;policy-scheme&quot;;
                })
                .AddCookie(AuthenticationScheme, options =&amp;gt;
                {
                   // Defines a path to redirect the user to if they don&#39;t have access to a page.
                   // This page should return a 200 response so as to not cause authentication loops.
                   options.AccessDeniedPath = new PathString(&quot;/no-access&quot;);
                })
                .AddCookie(ChallengeScheme)
                .AddOpenIdConnect(&quot;IdentityServer&quot;, options =&amp;gt;
                {
                    options.SignInScheme = ChallengeScheme;
                    options.SignOutScheme = ChallengeScheme;
                    options.ResponseType = OpenIdConnectResponseType.Code;
                    options.CallbackPath = &quot;/signin-oidc&quot;;
                    options.UsePkce = false;

                    options.Authority = authority;
                    options.RequireHttpsMetadata = requireHttpsMetadata;
                    options.ClientId = clientId;
                    options.ClientSecret = clientSecret;

                    options.Scope.Clear();
                    options.Scope.Add(OpenIdConnectScope.OpenId);
                    options.Scope.Add(&quot;xxx&quot;);
                    options.MapInboundClaims = false;

                    options.Events.OnRedirectToIdentityProvider = context =&amp;gt;
                    {
                        // Prevent redirect loop
                        if (context.Response.StatusCode == 401)
                        {
                            context.HandleResponse();
                        }

                        if (context.ProtocolMessage.RequestType == OpenIdConnectRequestType.Logout)
                        {
                            var idTokenHint = context.HttpContext.User.FindFirst(&quot;id_token&quot;);
                            if (idTokenHint != null)
                            {
                                context.ProtocolMessage.IdTokenHint = idTokenHint.Value;
                            }

                        }

                        return Task.CompletedTask;
                    };

                    options.Events.OnAuthenticationFailed = async context =&amp;gt;
                    {
                        context.HandleResponse();

                        await context.Response.BodyWriter.WriteAsync(Encoding.ASCII.GetBytes(context.Exception.Message));
                    };
                })
                .AddPolicyScheme(&quot;policy-scheme&quot;, null, options =&amp;gt;
                {
                   options.ForwardDefaultSelector = ctx =&amp;gt;
                   {
                       if (ctx.Request.Path.StartsWithSegments(&quot;/episerver&quot;, StringComparison.OrdinalIgnoreCase) ||
                        ctx.Request.Path.StartsWithSegments(&quot;/util&quot;, StringComparison.OrdinalIgnoreCase))
                       {
                           return IdentityConstants.ApplicationScheme; // IdentityConstants.ApplicationScheme = &quot;Identity.Application&quot;
                       }

                       return &quot;IdentityServer&quot;;
                   };
                });
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The next step is to add the new configuration section to our appsettings.json file, in this case we have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Authority - this is the Identity Server 4 URI&lt;/li&gt;
&lt;li&gt;Client Id - this is the id of the client that has been setup within Identity Server 4&lt;/li&gt;
&lt;li&gt;Client Secret - this is the secret of the client that has been setup within Identity Server 4&lt;/li&gt;
&lt;li&gt;RequireHttpsMetadata&amp;nbsp; - this determines if http or https should be required, generally this should be set to true&lt;/li&gt;
&lt;/ul&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;  &quot;IdentityServerSettings&quot;: {
    &quot;Authority&quot;: &quot;https://xxx.xx.com/identity&quot;,
    &quot;ClientId&quot;: &quot;xxx&quot;,
    &quot;ClientSecret&quot;: &quot;xxx&quot;,
    &quot;RequireHttpsMetadata&quot;: true
  }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Next we need to register the new user authentication middleware in the ConfigureServices method of the Startup.cs file:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddUserAuthentication(_webHostingEnvironment, _configuration)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;The following also needs adding in the Configure method of the Startup.cs file:&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;app.UseAuthentication();
app.UseAuthorization();&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now we need to implement the authentication controller, registering the Login and Logout routes that the user&#39;s of the website are to be redirected to.&lt;/p&gt;
&lt;p&gt;For the login method, we need to decorate it with an Authorize attribute, this needs to return a ChallengeResult that is an ActionResult that on execution invokes HttpContext.ChallengeAsync for the challenge scheme(s) passed in which in this case is a single scheme called &quot;IdentityServer&quot;.&lt;/p&gt;
&lt;p&gt;In terms of the logout method, we need to ensure we call the SignOutAsync method of the current HttpContext passing in the Authentication Scheme we want to logout, in this case the &quot;OpenIdConnect&quot; scheme. We then redirect back to the website homepage.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using System.Globalization;

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.AspNetCore.Mvc;

public sealed class AuthenticationController
{
    [Authorize(AuthenticationSchemes = &quot;IdentityServer&quot;)]
    [HttpGet]
    [Route(&quot;/login&quot;)]
    public IActionResult? Login()
    {        
        return new ChallengeResult(&quot;IdentityServer&quot;, new AuthenticationProperties { RedirectUri = &quot;/&quot; });
    }

    [HttpGet]
    [Route(&quot;/logout&quot;)]
    public IActionResult? Logout()
    {
        HttpContext.SignOutAsync(OpenIdConnectDefaults.AuthenticationScheme); // OpenIdConnectDefaults.AuthenticationScheme = &quot;OpenIdConnect&quot;
        return Redirect(&quot;/&quot;);
    }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Finally (and this is one part that confused me for a while) is providing the ability for both anonymous and logged in user&#39;s access to a page, to do this we needed to add the same Authorize attribute as for the login method but also add the &quot;AllowAnonymous&quot; attribute. For pages that we don&#39;t want non-logged in users to access, we can simply omit this attribute.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[Authorize(AuthenticationSchemes = &quot;IdentityServer&quot;)]
[AllowAnonymous]&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I hope this blog post provides an insight into how implementing login for multiple authentication schemes can be achieved, I know in this case it is heavily leaning towards Identity Server 4 but changing the provider to something like Azure AD should be relatively simple, both for the website user login and/or the CMS login.&lt;/p&gt;
&lt;h3&gt;References&lt;em&gt;&lt;br /&gt;&lt;/em&gt;&lt;em&gt;&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://identityserver4.readthedocs.io/en/latest/intro/terminology.html&quot;&gt;https://identityserver4.readthedocs.io/en/latest/intro/terminology.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://identityserver4.readthedocs.io/en/latest/topics/clients.html&quot;&gt;https://identityserver4.readthedocs.io/en/latest/topics/clients.html&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://docs.wso2.com/display/IS530/Authorization+Code+Grant&quot;&gt;https://docs.wso2.com/display/IS530/Authorization+Code+Grant&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-cloud/v12.0.0-content-cloud/docs/mixed-mode-authentication&quot;&gt;https://docs.developers.optimizely.com/content-cloud/v12.0.0-content-cloud/docs/mixed-mode-authentication&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://docs.developers.optimizely.com/content-cloud/v12.0.0-content-cloud/docs/integrate-azure-ad-using-openid-connect&quot;&gt;https://docs.developers.optimizely.com/content-cloud/v12.0.0-content-cloud/docs/integrate-azure-ad-using-openid-connect&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://gist.github.com/jawadatgithub/638c11f08ecc0d76b05c&quot;&gt;https://gist.github.com/jawadatgithub/638c11f08ecc0d76b05c&lt;/a&gt;&amp;nbsp;&lt;br /&gt;&lt;a href=&quot;https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-proof-key-for-code-exchange-pkce&quot;&gt;https://auth0.com/docs/get-started/authentication-and-authorization-flow/authorization-code-flow-with-proof-key-for-code-exchange-pkce&lt;/a&gt;&amp;nbsp;&lt;/p&gt;

&lt;div class=&quot;author__image col-sm-5&quot;&gt;&lt;img src=&quot;https://assets-eu-01.kc-usercontent.com/1e387446-ba57-010e-8dbf-944631f19d11/d003b6bf-e48d-43b5-ae36-ace9342bcecb/GrahamCarr_680x454.jpg?w=500&amp;amp;h=1000&amp;amp;auto=format&quot; /&gt;&lt;/div&gt;
&lt;div class=&quot;author__content col-sm-7 keep-margin-bottom&quot;&gt;
&lt;h2&gt;Graham Carr, Lead .NET Developer&lt;/h2&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;I am an experienced Lead .Net Developer with over 25 years&amp;rsquo; experience in a wide range of products and technologies. I have helped companies deliver their digital vision from concept all the way through to delivery. I have a particular passion for DXPs (Digital Experience Platforms) and am a certified developer for products such as Optimizely, Umbraco, Kontent.ai and more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2023-03-01T09:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>A day in the life of an Optimizely Developer - Opticon London 2022</title><link href="https://world.optimizely.com/blogs/allthingsopti/dates/2022/11/a-day-in-the-life-of-an-optimizely-developer---opticon-london-2022/" /><id>&lt;p&gt;Arriving at the train station in Leeds on Thursday, the evening before Opticon London 2022, excited for the journey ahead on what was promising to be a great day full of all things Optimizely, of course I should have expected to fall foul of the dreaded &amp;ldquo;train delays&amp;rdquo; - what should have been a 2hr 15min journey to King&amp;rsquo;s cross turned into a 4hr nightmare journey with many un-planned stops and bleary eyed and extremely tired children running up and down the aisles, thank god for my wireless ear buds!!&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Eventually I arrived at King&amp;rsquo;s cross and after a 30 minute underground journey and a short walk I finally arrived at the hotel at 11pm. I wasted no time getting into bed and fell asleep with thoughts and images of the day to come. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;The next morning arrived and after a short walk from the hotel I arrived at the location of Opticon London 2022 - Tobacco Dock. As a brief history, originally built in 1812 as a hub for precious cargo arriving from the New World, such as wine and, of course, tobacco, Tobacco Dock originally spanned 70 acres. Now occupying just two-fifths of the original site, the Grade 1 listed building still offers a generous 57 spaces over 16,000 sqm.&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/1e9256cb061a4ecea9222ab431989977.aspx&quot; /&gt;
&lt;figcaption&gt;Entrance to Opticon London 2022&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;Upon entering the building I was warmly greeted and directed to the registration where I electronically signed in and received my printed Optimizely badge for the day. After dropping my coat off at the cloakroom I entered the main room (or should I say hall) where the Optimizely and sponsor stands (&lt;/span&gt;&lt;em&gt;Microsoft, Google Cloud, Valtech and Siteimprove&lt;/em&gt;&lt;span&gt;) were situated, along with the music stage, plenty of nibbles, tea and coffee and even a sweetie cart with Optimizely branded bags!! (#thankyouopti)&amp;nbsp;&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/f1ae0bc2529c4b9c813e2fc1f29ff287.aspx&quot; width=&quot;732&quot; height=&quot;549&quot; /&gt;
&lt;figcaption&gt;Main networking hall, music stage and stands&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/56e4245a30a2439daaf514d150da1479.aspx&quot; width=&quot;732&quot; height=&quot;549&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Optimizely branded sweetie bags &lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;After looking at the sponsor stands I made my way over to the Optimizely stand where you had the chance to talk about anything Opti, I was particularly interested in the image they had on the stand display that provided a logical architecture of DXP and clearly showed how important components such as the &lt;/span&gt;&lt;strong&gt;Optimizely Data Platform (ODP)&lt;/strong&gt;&lt;span&gt;, &lt;/span&gt;&lt;strong&gt;Content Marketing&lt;/strong&gt;&lt;span&gt; and &lt;/span&gt;&lt;strong&gt;Feature Experimentation&lt;/strong&gt;&lt;span&gt; sat within the DXP architecture. From the agenda it looked as though these were the areas that were being given greatest focus across the day.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/ee9232edb94847fab65db4ab430f1c00.aspx&quot; width=&quot;735&quot; height=&quot;551&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Optimizely Stand - DXP Logical Architecture Diagram &lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;After a bit of networking I made my way to the room where the Keynote speech was delivered by &lt;/span&gt;&lt;em&gt;Alex Atzberger (CEO, Optimizely)&lt;/em&gt;&lt;span&gt;. He gave a very interesting speech with the headline of &amp;ldquo;&lt;strong&gt;The future is boundless&lt;/strong&gt;&amp;rdquo;, this covered how the digital landscape is currently emerging and how Optimizely and it&#39;s various current and more importantly upcoming components such as Feature Experimentation and Content Marketing can deliver Boundless Digital Invention to help marketers with the challenges they currently face working across disparate tools and systems, collaborating with an ever growing number of teams such as engineering, product, etc and receiving ever decreasing budgets whilst at the same time customer expectations are forever increasing. Boundless Digital Invention is driven by three core principles:&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Orchestrate&lt;/strong&gt;&lt;span&gt;&lt;strong&gt; &lt;/strong&gt;- A single platform that has all of the tools to help manage the entire content lifecycle&lt;br /&gt;&lt;/span&gt;&lt;strong&gt;Monetize&lt;/strong&gt;&lt;span&gt; - Modern and relevant commerce experiences can help drive the experiences that customers expect as well as increasing revenue and growth, this is all made possible by the B2C and B2B Commerce platforms&lt;br /&gt;&lt;/span&gt;&lt;strong&gt;Experiment&lt;/strong&gt;&lt;span&gt;&lt;strong&gt; &lt;/strong&gt;- Using the tools available within Feature Experimentation such as A/B testing, Personalisation, etc. marketers are able to provide experiences that are optimized and can drive business growth.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Marcella Pasqualucci (Head of Experimentation, Sky)&lt;/em&gt;&lt;span&gt; was then welcomed onto the stage where he discussed how the Web Experimentation features within Optimizely allowed Sky to experiment at a fast pace allowing them to learn from experimentation tests quickly and adapt to what a consumer is looking for in an ever changing digital world, the experimentation evolved from simple web experiments (button colors), to more advanced server-side and mobile experiments.. This has helped drive customer satisfaction whilst at the same time increasing product adoption by consumers.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/e5c84b08ba594ccdafcaf7ce0699d214.aspx&quot; width=&quot;733&quot; height=&quot;550&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Alex Atzberger &amp;amp; Marcella Pasqualucci discuss experimentation at Sky&lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;We then moved onto a presentation titled &amp;ldquo;&lt;/span&gt;&lt;strong&gt;Driving digital forward: The Road to revolutionary experiences&lt;/strong&gt;&lt;span&gt;&amp;rdquo;. This was presented by &lt;/span&gt;&lt;em&gt;Justin Anovick (CPO, Optimizely)&lt;/em&gt;&lt;span&gt; and he was joined on stage by &lt;/span&gt;&lt;span&gt;&lt;em&gt;Nazanin Ramezani (Chief of Staff, Optimizely)&lt;/em&gt; and &lt;em&gt;Jacob Khan (GVP, Solution Architect, Optimizely)&lt;/em&gt;&lt;/span&gt;&lt;span&gt; all sporting groovy jackets covered in Optimizely client logos, Naz and Jacob&amp;rsquo;s were particularly noteworthy in their bright orange and green colour!&quot;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The presentation covered the struggles that a current marketer (role-played by Naz) face when creating new content, making changes to existing content, trying to gather insights on customer experiences, etc. and Naz acted as the role of that marketer. We then saw how a marketer (role-played by Jacob) who has access to Optimizely Content Marketing, Feature Experimentation and Data Platform could quickly and efficiently create content, get changes made and approved, as well as being able to gather data and insights on everything customers were doing, and acting on these insights by incorporating personalisation and experimentation.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/d9ad5b98636e4168b4e6393dc9ab16ec.aspx&quot; width=&quot;743&quot; height=&quot;557&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Justin Anovick presenting on stage&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;The final presentation of the keynote session was titled &amp;ldquo;&lt;/span&gt;&lt;strong&gt;Reinventing how marketing works: A radically new way of creating digital experiences&lt;/strong&gt;&lt;span&gt;&amp;rdquo; and was presented by &lt;/span&gt;&lt;span&gt;&lt;em&gt;Kirsten Allegri-Williams (CMO, Optimizely)&lt;/em&gt; &lt;/span&gt;&lt;span&gt;she was joined on stage by &lt;/span&gt;&lt;em&gt;Veronica Saha (Head of Analytics, Zoopla). &lt;/em&gt;This session discussed how Optimizely can help provide a new ways of creating digital experiences, allowing inclusive collaboration with unified calendar views and digital asset management, confident content creation via iterative experiments, clear insights and embedded AI and finally customer foresight where access to insightful data alllows customer understanding as well as delivering exclusive experiences, product recommendations, to name but a few.&lt;/p&gt;
&lt;p&gt;A short coffee break came next where I had chance to do a bit more networking as well as saying hello to some of the clients of the company that I work for (&lt;a href=&quot;https://www.twentysixdigital.com&quot;&gt;#twentysix&lt;/a&gt;)&lt;span&gt; - I always find being courteous and chatting with existing clients is as important as speaking with new people who might become possible future contacts to learn from or gain leads from. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Next up was the sponsor breakout sessions, these were all held in separate rooms spread across the floor where Opticon was being hosted and you chose to attend the session that interested you the most. I opted for the session titled &amp;ldquo;&lt;/span&gt;&lt;strong&gt;Unlock new possibilities by taking your Optimizely Digital Experience Platform to the next level&lt;/strong&gt;&lt;span&gt;&amp;rdquo;, this was presented by &lt;/span&gt;&lt;span&gt;&lt;em&gt;Michelle Azzopardi (Digital &amp;amp; App innovation GTMM UK Microsoft)&lt;/em&gt;. &lt;/span&gt;&lt;span&gt;This session was the most technical session of the day covering Azure, .Net and the Optimizely DXP Cloud Service.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/5da74e31987e42c5ae2b4e136d732d86.aspx&quot; width=&quot;737&quot; height=&quot;553&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Microsoft discuss the Optimizely Azure cloud architecture and use of .Net 6/7 &lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;The first area that was covered was on how customisable Optimizely is, more specifically:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;800+ digital agencies&lt;/strong&gt;&lt;span&gt; use Optimizely as there preferred DXP &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;40k developers&lt;/strong&gt;&lt;span&gt; are using Optimizely &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;87 OMVPs&lt;/strong&gt;&lt;span&gt; current exist across the world &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;300+ add-ons&lt;/strong&gt;&lt;span&gt; are currently available &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Infinite possibilities&lt;/strong&gt;&lt;span&gt; exist with the use of Optimizely &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span&gt;The session then went on to cover the what Microsoft are currently doing in terms of reducing carbon emissions, paying an increasing amount of carbon tax, reducing energy consumption within data centers, reducing water usage, accelerating carbon reduction, etc. This leads to four commitments which are: &lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Carbon Negative&lt;/strong&gt;&lt;span&gt; by 2030 &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Zero Waste&lt;/strong&gt;&lt;span&gt; by 2030 &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Water Positive&lt;/strong&gt;&lt;span&gt; by 2030 &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Build the &lt;/span&gt;&lt;strong&gt;Planetary Computer&lt;/strong&gt;&lt;span&gt; &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span&gt;The session then moved onto how Optimizely are using Microsoft Azure for their DXP Cloud Services. It discussed how the services in use are helping to protect &lt;/span&gt;&lt;strong&gt;29K&lt;/strong&gt;&lt;span&gt; sites and projects in 120 countries and how &lt;/span&gt;&lt;strong&gt;7B+&lt;/strong&gt;&lt;span&gt; attacks were blocked last year alone.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The talk then moved onto the momentum that is occuring within .Net and we were told:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;5.4M .Net Developers&lt;/strong&gt;&lt;span&gt; current exist in the Visual Studio Family&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;#1 Most Loved Framework&lt;/strong&gt;&lt;span&gt; (2019, 20, 21) .Net Core/.Net 5 &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;gt;6.9K Community Contributors&lt;/strong&gt;&lt;span&gt; to .Net 6 &lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;&amp;gt;21K Community Contributions&lt;/strong&gt;&lt;span&gt; to .Net 6 &lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;CMS12 was the next thing to be discussed, including some of the new features of CMS12 that have been released and some others that are currently in development. It was also worth noting that the DXP packages now support the very recently released .NET 7.&lt;/p&gt;
&lt;h3&gt;New features on CMS 12&lt;/h3&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Released&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;In Development&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Welcome DAM Integration&lt;/td&gt;
&lt;td&gt;Tag helpers&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Welcome Structured Content integration (Private Beta)&lt;/td&gt;
&lt;td&gt;List property support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headless editing&lt;/td&gt;
&lt;td&gt;OptiID&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Optimizely Data Platform integration&lt;/td&gt;
&lt;td&gt;TinyMCE6 upgrade&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Liquid templates support (Labs)&lt;/td&gt;
&lt;td&gt;Out-of-the-box dashboard&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Advanced admin functionalities&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Improved accessibility&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;The self-service migration tool was then covered, this is a tool that is now available within Paasportal (&lt;/span&gt;&lt;span&gt;&lt;a href=&quot;https://paasportal.episerver.net/&quot;&gt;https://paasportal.episerver.net/&lt;/a&gt;). Upgrading to CMS12 requires changes to the underlying Azure infrastructure, and as customers have no direct control over the service infrastructure then this tool was created so that a customer can confidently migrate to CMS12 and Commerce 14 with no assistance from Optimizely. The tool provides parallel project support to allow independently finalizing the migration process without disrupting current environments, content can be copied on-demand from a source CMS11/Commerce 13 project and once you are happy when you are able to easily switch over hostnames to the new project whilst ensuring data consistency.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Next on the agenda was the first set of the Optimizely breakout sessions. I decided to join the session titled &amp;ldquo;&lt;/span&gt;&lt;strong&gt;Get more from your digital experience platform with Optimizely Data Platform&lt;/strong&gt;&lt;span&gt;&amp;rdquo; and was presented by &lt;/span&gt;&lt;span&gt;&lt;em&gt;Nazanin Ramezani (Chief of Staff, Optimizely)&lt;/em&gt; and &lt;em&gt;Jacob Khan (GVP, Solution Architect, Optimizely)&lt;/em&gt; &lt;/span&gt;&lt;span&gt;with Naz having decided to drop the groovy green Optimizely jacket for a more fashionable black one&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The session started off by discussing how there is more customer data than ever in the current digital landscape due to the many different touchpoints that exist across channels and devices. They also went on to discuss how new privacy laws and an ever expanding customer expectation for personalisation meant that both insightful, relevant and up-to date data are more important than ever.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/8566abe1d0a546f0a862edc094634c19.aspx&quot; width=&quot;702&quot; height=&quot;527&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Naz and Jacob discuss Optimizely Data Platform capabilities&lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;This then led us on to a discussion on how the Optimizely Data Platform helps to make complex data simple for marketers, as it acts as a centralised hub to turn customer data into data science profiles ready. This is seen across two different personas, namely developers and marketers:&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Developer&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Marketer&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Easy to use APIs for custom integration scenarios&lt;/td&gt;
&lt;td&gt;Start immediately with unified profiles and predictive analytics&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GraphQL providing complete and understandable description of the data in the API&lt;/td&gt;
&lt;td&gt;Act on real-time segments within any of experimentation, CMS or Commerce&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Real time segments to instantly act on any data collected&lt;/td&gt;
&lt;td&gt;Unlock more value from experimentation by adding the customer context&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;They finally went on to discuss how the Optimizely Data Platform will be joined in January 2023 by the Optimizely Connector Platform that will enable both out-of-the-box and custom integrations with many third-parties. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;After what was an excellent morning of sessions where a good insight and learnings into some of the main components of the DXP architecture were made it was time for lunch. Once again this took place in the main hall and gave plenty of time for further networking as well as feasting on the amazing lunch that was provided.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;After being fully topped up on Latte&amp;rsquo;s from the barista stand, I felt invigorated for the afternoons sessions. Next up was the second set of Optimizely breakout sessions where I opted to attend the session titled &amp;ldquo;&lt;/span&gt;&lt;strong&gt;Scale your experimentation program with Feature Experimentation&lt;/strong&gt;&lt;span&gt;&amp;rdquo; which was presented by &lt;em&gt;Joey Moore &lt;/em&gt;&lt;/span&gt;&lt;em&gt;(Associate Vice President, Product, Optimizely)&lt;/em&gt;&lt;span&gt; and who was joined on stage by guest speaker &lt;/span&gt;&lt;span&gt;&lt;em&gt;Stewart Ehoff (Head of Experimentation, RS Components)&lt;/em&gt; &lt;/span&gt;&lt;span&gt;and consisted of a deep dive into feature experimentation by taking a look into the future of experimentation and feature management.&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/9461fe569d274ab5b4b47d4772da0a85.aspx&quot; width=&quot;689&quot; height=&quot;517&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Joey Moore - Feature Experimentation Deep Dive&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;The concept of feature experimentation was split into separate areas and included the Delivery Platform, Optimisation Layer and Data Layer.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;The Delivery Platform&lt;/strong&gt; covered the tools in place to provide things such as environments, rules engine, flexible architecture, webhooks, rollouts, API first and many more.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;The Optimisation Layer&amp;nbsp;&lt;/strong&gt;covered the tools available such as concurrent A/B tests, Personlisation, Metrics, Data Integrations, Audiences and many more&lt;/li&gt;
&lt;li&gt;The final layer related to &lt;strong&gt;Optmizely Data Platform&lt;/strong&gt; and the upcoming &lt;strong&gt;Optimizely Connect Platform&lt;/strong&gt;.&lt;br /&gt;&lt;br /&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/c1b1cb9baac4493bb7be9d2f7b16a7d5.aspx&quot; width=&quot;692&quot; height=&quot;519&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Joey joined on stage by Stewart Ehoff &lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;Joey then started interviewing Stewart on the stage asking him how experimentation has evolved at RS Components. When asked how a company can get into experimentation, Stewart made a good point that the most important thing is actually doing an experimentation, no matter how small or trivial, a lot of the time with experimentation, you might have a few wins but 70% of the time will be fails, but these aren&#39;t truly fails and a lot can be learnt from them to help direct the approach taken on the next set of experiments that are performed. Joey finished by talking about the big ideas that Optimizely have concerning data capabilities and a collaboration with Google Cloud Platform to allow improved data sharing, data import capabilities, advanced metrics and data science capabilities.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;After this session it was onto the final set of Optimizely breakout sessions and this time I opted for the session titled &amp;ldquo;&lt;/span&gt;&lt;strong&gt;Building a powerhouse commerce engine&lt;/strong&gt;&lt;span&gt;&amp;rdquo; which was presented by &lt;/span&gt;&lt;span&gt;J&lt;em&gt;osh Schoonmaker (Global VP of Product, Optimizely)&lt;br /&gt;&lt;br /&gt;&lt;/em&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/954329b40feb4c658b329ac5051107a3.aspx&quot; width=&quot;695&quot; height=&quot;521&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Josh Schoonmaker presenting on stage &lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;Josh gave an insightful presentation talking about competitive pressure and how 90% of surveyed leaders say they are investing in additional capabilities to drive digital growth. He talked about how Commerce currently exists today, from a social media perspective through to personalisation and loyalty. Concerning personalisation in Commerce:&lt;/span&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;span&gt;70% of consumers would willingly share data for a more personalised experience&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;72% only engage with personalised messaging&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;71% of consumers expect personalised interactions&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;76% of consumers get frustrated when this doesn&#39;t happen&amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp; &amp;nbsp;&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span&gt;Another set of interesting points he made were concerning Gen Z preferences in that 37% value personalisation over all else and 52% value personalisation so highly that they are willing to share more information with brands if it means a more personalised shopping experience.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;At the end of this presentation, there was a short break before we all congregated back in the main keynote room for the prestigious customer and partner awards.&lt;/span&gt;&lt;span&gt; &lt;/span&gt;&lt;span&gt;The awards along with winners were presented in the following order:&lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Customer Awards&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Most Innovative Digital Experience&lt;/strong&gt;&lt;span&gt;&lt;strong&gt; &lt;/strong&gt;- EPG Health &lt;br /&gt;&lt;/span&gt;&lt;strong&gt;Best Experimentation Practice&lt;/strong&gt;&lt;span&gt;&lt;strong&gt; &lt;/strong&gt;- Channel 4&lt;/span&gt;&lt;span&gt; &lt;br /&gt;&lt;/span&gt;&lt;strong&gt;Most Customer-Centric Experience&lt;/strong&gt;&lt;span&gt;&lt;strong&gt; &lt;/strong&gt;- Mazda Motor Europe&lt;/span&gt;&lt;span&gt; &lt;br /&gt;&lt;/span&gt;&lt;strong&gt;Best Buying Experience&lt;/strong&gt;&lt;span&gt; - Farrow &amp;amp; Ball in partnership with Kin+Carta &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;Partner Awards&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;Experimentation Partner of the Year&lt;/strong&gt;&lt;span&gt; - Kin+Carta &lt;br /&gt;&lt;/span&gt;&lt;strong&gt;Digital Experience Solution Partner of the Year&lt;/strong&gt;&lt;span&gt; - Unrivald &lt;br /&gt;&lt;/span&gt;&lt;strong&gt;Rising Star Solution Partner of the Year&lt;/strong&gt;&lt;span&gt; - Mando &lt;br /&gt;&lt;/span&gt;&lt;strong&gt;Customers&#39; Choice Partner of the Year&lt;/strong&gt;&lt;span&gt; - Netcel &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;The final award was the prestigious &lt;strong&gt;2022 Solution Partner of the Year&lt;/strong&gt; and both myself and my fellow twentysix colleagues were extremely happy to be named as the winners of this award. This award is honors the winner as &lt;/span&gt;&lt;span&gt;a top-performing partner that has demonstrated outstanding business performance and excellence in both sales and delivery of Optimizely solutions. (&lt;/span&gt;&lt;em&gt;&lt;strong&gt;twentysix &lt;/strong&gt;part of the &lt;strong&gt;MSQ Group&lt;/strong&gt;&lt;/em&gt;&lt;span&gt; - &lt;a href=&quot;https://www.twentysixdigital.com&quot;&gt;https://www.twentysixdigital.com&lt;/a&gt;)&lt;br /&gt;&lt;br /&gt;&lt;/span&gt;&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/e146a721268d4a1db0bb69eabe94a99f.aspx&quot; width=&quot;706&quot; height=&quot;942&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;2022 Solution Partner of the Year trophy &lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/b252d9066ec04190abbc5be60dd9672e.aspx&quot; width=&quot;708&quot; height=&quot;944&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Myself and my fellow colleagues proudly sporting our trophy &lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/720d7f32e66948679b566392b2743c9c.aspx&quot; width=&quot;707&quot; height=&quot;530&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;Winners of the 2022 Optimizely Partner Awards&lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;span&gt;&lt;br /&gt;After the awards were the closing remarks presented by &lt;/span&gt;&lt;span&gt;Alex Atzberger &lt;/span&gt;&lt;span&gt;where he gave an overview of the day and also discussed what we could look forward to in 2023. &lt;/span&gt;The after party then commenced where drinks were available along with canap&amp;eacute;s and you were left free to network all the while listening to the excellent live music being played in tandem with a very talented saxophone player.&lt;/p&gt;
&lt;figure class=&quot;image&quot;&gt;&lt;img src=&quot;/link/779853c62ed149549cbc4b1559e3ebec.aspx?1668106979604&quot; width=&quot;647&quot; height=&quot;485&quot; style=&quot;width: 707px; height: 530px;&quot; /&gt;
&lt;figcaption&gt;&lt;span&gt;After party with live music&lt;/span&gt;&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;&lt;br /&gt;After an hour or two it was time to head back to King&amp;rsquo;s Cross for the journey back to Leeds where I had plenty of time to absorb what had been covered in the day along with getting notes down whilst still fresh in my memory which would allow me to write this blog post.&lt;/p&gt;
&lt;h2&gt;Final Thoughts&lt;/h2&gt;
&lt;p&gt;&lt;span&gt;So after attending the event and absorbing the information that was provided across the day, firstly I would highly recommend attending this event in 2023 regardless of whether you attend the main Opticon event as it gives you a different angle to look from and also provides you with great networking with like-minded UK customers and technology experts. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;My main takeaways from the event were that Optimizely are pushing &quot;&lt;strong&gt;Boundless Digital Invention&lt;/strong&gt;&quot; which is delivered by Optimizely DXP but heavily focussed in three additional areas. The first is &lt;strong&gt;Optimizely Data Platform (ODP)&lt;/strong&gt; and how it is able to store big data whilst providing an easy way of querying the data via GraphQL as well as enabling an ever growing library of integrations via the &lt;strong&gt;Optimizely Connect Platform&lt;/strong&gt; coming in January 2023.&lt;/p&gt;
&lt;p&gt;The second area of focus was &lt;strong&gt;Optimizely Content Marketing&lt;/strong&gt; formerly Welcome where the day showcased the features and what can be achieved from this platform and how it will help provide excellent marketing capabilities.&lt;/p&gt;
&lt;p&gt;The final area of focus was on &lt;strong&gt;Optimizely Feature Experimentation&lt;/strong&gt; formerly referred to as Full Stack and covered a lot of how the experimentation features can enable fast experimentation, allowing ideas to be tried out quickly therefore keeping up with the ever demanding consumer.&lt;/p&gt;
&lt;p&gt;As 70-80% of the people attending the event were customers who were either thinking of using Optimizely or are already using Optimizely then it makes sense for the focus on how Optimizely products can help customer drive their digital landscape through Boundless Digital Invention.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;p&gt;Boundless Digital Invention - &lt;a href=&quot;https://www.optimizely.com/unlimit-yourself/&quot;&gt;&lt;span&gt;https://www.optimizely.com/unlimit-yourself/&lt;/span&gt;&lt;/a&gt; &lt;br /&gt;Optimizely Data Platform (ODP) - &lt;a href=&quot;https://www.optimizely.com/products/intelligence/data-platform/&quot;&gt;&lt;span&gt;https://www.optimizely.com/products/intelligence/data-platform/&lt;/span&gt;&lt;/a&gt; &lt;br /&gt;Optimizely Content Marketing - &lt;a href=&quot;https://www.optimizely.com/products/content-marketing/&quot;&gt;https://www.optimizely.com/products/content-marketing/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;Optimizely Feature Experimentation - &lt;a href=&quot;https://www.optimizely.com/products/intelligence/full-stack-experimentation/&quot;&gt;https://www.optimizely.com/products/intelligence/full-stack-experimentation/&lt;/a&gt;&amp;nbsp;&lt;br /&gt;CMS12 Self-Service Migration - &lt;a href=&quot;https://docs.developers.optimizely.com/digital-experience-platform/v1.3.0-DXP-for-CMS11-COM13/docs/migration-to-cms-12-commerce-14&quot;&gt;https://docs.developers.optimizely.com/digital-experience-platform/v1.3.0-DXP-for-CMS11-COM13/docs/migration-to-cms-12-commerce-14&lt;/a&gt;&amp;nbsp;&lt;br /&gt;DXP Cloud Architecture - &lt;a href=&quot;https://docs.developers.optimizely.com/content-cloud/v12.0.0-content-cloud/docs/architecture&quot;&gt;https://docs.developers.optimizely.com/content-cloud/v12.0.0-content-cloud/docs/architecture&lt;/a&gt;&amp;nbsp;&lt;br /&gt;Zoopla - &lt;a href=&quot;https://www.optimizely.com/insights/zoopla-refines-personalization-strategy-to-enhance-the-homebuyers-experience/&quot;&gt;https://www.optimizely.com/insights/zoopla-refines-personalization-strategy-to-enhance-the-homebuyers-experience/&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://www.optimizely.com/insights/zoopla-refines-personalization-strategy-to-enhance-the-homebuyers-experience/&quot;&gt;&lt;/a&gt;Microsoft Commitments to Sustainability - &lt;a href=&quot;https://www.microsoft.com/en-us/corporate-responsibility/sustainability&quot;&gt;https://www.microsoft.com/en-us/corporate-responsibility/sustainability&lt;/a&gt;&amp;nbsp;&lt;/p&gt;

&lt;div class=&quot;author__image col-sm-5&quot;&gt;&lt;img src=&quot;https://assets-eu-01.kc-usercontent.com/1e387446-ba57-010e-8dbf-944631f19d11/d003b6bf-e48d-43b5-ae36-ace9342bcecb/GrahamCarr_680x454.jpg?w=500&amp;amp;h=1000&amp;amp;auto=format&quot; /&gt;&lt;/div&gt;
&lt;div class=&quot;author__content col-sm-7 keep-margin-bottom&quot;&gt;
&lt;h2&gt;Graham Carr, Lead .NET Developer&lt;/h2&gt;
&lt;div class=&quot;rich-text aos-init aos-animate&quot;&gt;
&lt;p&gt;I am an experienced Lead .Net Developer with over 25 years&amp;rsquo; experience in a wide range of products and technologies. I have helped companies deliver their digital vision from concept all the way through to delivery. I have a particular passion for DXPs (Digital Experience Platforms) and am a certified developer for products such as Optimizely, Umbraco, Kontent.ai and more.&lt;/p&gt;
&lt;/div&gt;
&lt;/div&gt;</id><updated>2022-11-10T19:53:20.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>