<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom"><title type="text">Blog posts by K Khan </title><link href="http://world.optimizely.com" /><updated>2025-12-21T17:31:32.0000000Z</updated><id>https://world.optimizely.com/blogs/K-Khan-/</id> <generator uri="http://world.optimizely.com" version="2.0">Optimizely World</generator> <entry><title>Troubleshooting with Azure Application Insights Using KQL</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2025/12/troubleshooting-with-azure-application-insights-using-kql/" /><id>&lt;p&gt;Users at least get access to Azure Application Insights even within minimum access level if you are requesting access to DXP management portals at https://world.optimizely.com/service-request-forms/access-to-dxp-portal/. Azure Application Insights is a powerful application performance monitoring (APM) service that helps you track the health, performance, and usage of your applications in real time. It offers end‑to‑end observability through telemetry such as requests, dependencies, exceptions, traces, and custom events, enabling developers to quickly detect anomalies, diagnose issues, and understand user behaviour. With built‑in dashboards, analytics, and seamless integration with Azure Monitor, it provides deep insights that improve reliability, optimize performance, and enhance the overall user experience. There will be moments when provided dash board won&#39;t be just enough, Developer will need to do queries to telemetries, Kusto Query Language (KQL) is the engine that unlocks that data. KQL gives you the flexibility to slice and analyze telemetry at scale.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;KQL Basics&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Application Insights stores telemetry in tables such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;requests -Incoming HTTP requests - name, url, duration, resultCode, success&lt;/li&gt;
&lt;li&gt;dependencies - External calls (DB, APIs) - type, target, name, duration, success&lt;/li&gt;
&lt;li&gt;exceptions - Application exceptions - type, message, outerMessage, problemId&lt;/li&gt;
&lt;li&gt;traces - Custom log messages - message, severityLevel&lt;/li&gt;
&lt;li&gt;customMetrics - Custom performance - metrics &amp;nbsp; &amp;nbsp;name, value&lt;/li&gt;
&lt;li&gt;pageViews - Client-side page views - name, url, duration&lt;/li&gt;
&lt;li&gt;traces&lt;/li&gt;
&lt;li&gt;availabilityResults&lt;/li&gt;
&lt;li&gt;customEvents&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Common Operators&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;where - Filter rows&lt;/li&gt;
&lt;li&gt;project - Select specific columns&lt;/li&gt;
&lt;li&gt;summarize - Aggregations (count, avg, percentiles)&lt;/li&gt;
&lt;li&gt;extend - Create calculated fields&lt;/li&gt;
&lt;li&gt;join - Combine tables&lt;/li&gt;
&lt;li&gt;order by - Sort results&lt;/li&gt;
&lt;li&gt;take - Limit rows&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Limitations&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Query Timeout: 3 minutes maximum execution time, Large datasets may require sampling or time filtering.&lt;/li&gt;
&lt;li&gt;Result Set Size: Maximum 500,000 rows returned&lt;/li&gt;
&lt;li&gt;Data Retention: 90 days for detailed data (configurable up to 730 days), Long-term retention requires exporting to Log Analytics or Storage.&lt;/li&gt;
&lt;li&gt;Concurrent Queries: Throttling applied under heavy loads&lt;/li&gt;
&lt;li&gt;Sampling: Application Insights may apply adaptive sampling. This can affect counts unless you use itemCount.&lt;/li&gt;
&lt;li&gt;No Data Modification: KQL is read-only. You cannot update or delete telemetry.&lt;/li&gt;
&lt;li&gt;Join Limitations: Joining large tables can be slow or truncated.&lt;/li&gt;
&lt;li&gt;Query Complexity: Some advanced operations (e.g., recursive logic) are not supported.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Best Practices for Monitoring &amp;amp; Troubleshooting&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;Use Time Filters Early
requests
| where timestamp &amp;gt; ago(1h)
This improves performance dramatically.

Project Only What You Need
| project name, duration
Reduces memory and speeds up queries.

Use Summaries for High-Volume Data
Instead of returning thousands of rows:
| summarize count() by name

Use itemCount When Sampling Is Enabled
| summarize total = sum(itemCount)

Correlate Telemetry Using Operation Id
requests
| join traces on operation_Id&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;strong&gt;KQL References for future refernce&lt;/strong&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;// Basic query pattern
TableName
| where Timestamp &amp;gt; ago(1d)  // Filtering
| where Operation_Name == &quot;HomeController.Index&quot;
| project Column1, Column2    // Selecting columns
| summarize Count = count() by Column1  // Aggregation
| order by Count desc        // Sorting
| limit 10                   // Limiting results

Filtering with where:
requests
| where timestamp &amp;gt; ago(24h)
| where success == false
| where duration &amp;gt; 1000  // Duration in milliseconds

Selecting columns with project:
requests
| project timestamp, name, url, duration, resultCode
| take 100

Aggregation with summarize:
requests
| summarize 
    AvgDuration = avg(duration),
    RequestCount = count(),
    FailedCount = countif(success == false)
    by name, bin(timestamp, 1h)

Top 5 Slowest Requests:
requests
| where timestamp &amp;gt; ago(7d)
| top 5 by duration desc
| project timestamp, name, duration, url, resultCode

Failure Rate Trend:
requests
| where timestamp &amp;gt; ago(30d)
| summarize 
    TotalRequests = count(),
    FailedRequests = countif(success == false)
    by bin(timestamp, 1d)
| extend FailureRate = FailedRequests * 100.0 / TotalRequests
| order by timestamp asc
| render timechart

Exception Analysis:
exceptions
| where timestamp &amp;gt; ago(1d)
| summarize Count = count() by type, innermostMessage
| order by Count desc
| take 20

Alert on Patterns, Not Single Events
Use:
avg(duration)
percentile(duration, 95)
count()

Explore Requests
requests
| summarize count(), avg(duration) by name

Find Failing Dependencies
dependencies
| where success == false
| summarize count() by target, type

Trace-Level Debugging
traces
| where severityLevel &amp;gt;= 3
| order by timestamp desc

Exception Analysis
exceptions
| summarize count() by type, innermostMessage

User Behavior
customEvents
| summarize count() by name

End-to-End Transaction Diagnostics
requests
| where operation_Id == &quot;&amp;lt;operation-id&amp;gt;&quot;

Using parse to Extract Data
traces
| parse message with &quot;User:&quot; userId &quot;, Action:&quot; action

Using bin() for Time Bucketing
requests
| summarize count() by bin(timestamp, 5m)

Using join for Correlation
requests
| join kind=leftouter dependencies on operation_Id

Using make-series for Time-Series Analysis
requests
| make-series count() on timestamp in range(ago(1d), now(), 1h)&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</id><updated>2025-12-21T17:31:32.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Opal Core Concepts</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2025/9/opal-core-concepts/" /><id>&lt;p&gt;Before you dive into the code, it&#39;s crucial to understand the foundational ideas that make Opal tick.&amp;nbsp;Core concepts are consistent across all its SDKs.&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;The Tool Manifest&lt;/h2&gt;
&lt;p&gt;Imagine you&#39;re introducing your tool to the Opal platform for the first time. You need a well-structured document that explains exactly what it is, what it needs, and how to use it. That document is the Tool Manifest. It&amp;rsquo;s the single source of truth that ensures Opal understands your tool perfectly.&lt;/p&gt;
&lt;p&gt;This JSON blueprint contains all the essential details:&lt;br /&gt;&lt;strong&gt;Name &amp;amp; Description&lt;/strong&gt;: The human-readable &quot;elevator pitch&quot; for your tool.&lt;br /&gt;&lt;strong&gt;Parameters&lt;/strong&gt;: A detailed list of every input your tool expects, including their names, data types (string, number, boolean, etc.), and whether they are required or optional.&lt;br /&gt;&lt;strong&gt;How to Invoke&lt;/strong&gt;: The technical instructions: the specific HTTP endpoint (URL) and method (GET/POST) Opal should call to run your tool.&lt;br /&gt;&lt;strong&gt;Authentication Requirements&lt;/strong&gt;: Instructions on what, if any, credentials are needed.&lt;/p&gt;
&lt;h2&gt;&lt;br /&gt;The Discovery Endpoint&lt;/h2&gt;
&lt;p&gt;This is a specific URL your tool service must expose, typically at /discovery. When you register your tool with Opal, this is the first place it will &quot;knock on the door.&quot;&amp;nbsp;Its sole job is to respond to Opal&#39;s call by returning that all-important Tool Manifest we just discussed. This is how Opal dynamically discovers every tool your service offers, without you having to manually configure each one in a UI.&lt;/p&gt;
&lt;p&gt;This endpoint is the critical handshake between your service and the Opal platform. If it&#39;s down, returns an error, or provides a malformed manifest, the conversation stops before it even begins. The SDKs automate its creation, so you can focus on your tool&#39;s logic.&lt;/p&gt;
&lt;h2&gt;Tool Execution&lt;/h2&gt;
&lt;p&gt;This is the main event&amp;mdash;the process where Opal calls your tool to do its actual job.&amp;nbsp;A user or process in Opal triggers your tool.&amp;nbsp;Opal packages up all the provided parameters into a neat HTTP request (a POST with a JSON body).&amp;nbsp;This request is sent to your tool&#39;s designated execution endpoint.&amp;nbsp;Your tool processes the request, performs its task (query a database, call an API, run a calculation, etc.), and then&amp;nbsp;returns a structured response (as JSON) back to Opal.&amp;nbsp;This is the &quot;work&quot; phase. Understanding the expected request format and designing a clear response is key to implementing your tool&#39;s core functionality effectively.&lt;/p&gt;
&lt;h2&gt;Authentication&lt;/h2&gt;
&lt;p&gt;The essential security layer that ensures only authorized requests from Opal can trigger your tools and access their capabilities.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bearer Tokens&lt;/strong&gt;: A simple yet powerful method where Opal passes a secret token in the Authorization header. Your tool&#39;s first job is to validate this token before doing anything else.&lt;br /&gt;&lt;strong&gt;OAuth Flows&lt;/strong&gt;: For tools that interact with third-party services (like Google or Salesforce), your tool can leverage OAuth through Opal to securely access user data.&lt;/p&gt;
&lt;p&gt;The Opal SDKs provide built-in helpers to simplify implementing these critical security measures.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h2&gt;Do you want to learn more?&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/link/4249083e620549929b1c57a60a377190.aspx&quot;&gt;https://world.optimizely.com/blogs/allthingsopti/dates/2025/8/a-day-in-the-life-of-an-optimizely-developer---the-optimizely-opal-tools-sdk-how-to-extend-opal-with-your-own-superpowers/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;</id><updated>2025-09-13T14:10:38.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>API Dcumentation references</title><link href="https://digitalpixie.co.uk/?p=221" /><id>Optimizely provides a wide array of APIs designed to empower developers to create rich, scalable, and personalized digital experiences. Below is an overview of some of the most valuable APIs you might want to explore for your next project, along with a quick summary for each. 1. SaaS CMS Content API (Preview 3)Documentation LinkThis API &amp;#8230; &lt;p class=&quot;link-more&quot;&gt;&lt;a href=&quot;https://digitalpixie.co.uk/api-dcumentation-references&quot; class=&quot;more-link&quot;&gt;Continue reading&lt;span class=&quot;screen-reader-text&quot;&gt; &quot;API Dcumentation references&quot;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</id><updated>2025-08-24T12:00:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Commerce extension points: Order Group Total</title><link href="https://digitalpixie.co.uk/?p=213" /><id>In many business scenarios, calculating the&#160;Order Total&#160;involves complex logic, such as dynamic handling fees based on items, packages, or custom rules. The default&#160;IOrderGroupCalculator&#160;implementation in DefaultOrderGroupCalculator may not suffice for these advanced requirements. DefaultOrderGroupCalculator service computes following and custom class can override related method. Extending the Calculation Logic Instead of fully replacing&#160;IOrderGroupCalculator, you can implement custom &amp;#8230; &lt;p class=&quot;link-more&quot;&gt;&lt;a href=&quot;https://digitalpixie.co.uk/commerce-extension-points-order-group-total&quot; class=&quot;more-link&quot;&gt;Continue reading&lt;span class=&quot;screen-reader-text&quot;&gt; &quot;Commerce extension points: Order Group Total&quot;&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;</id><updated>2025-07-20T15:18:29.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Comerce Connect calatog caching settings</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2025/2/comerce-connect-calatog-caching-settings/" /><id>&lt;p&gt;A critical aspect of Commerce Connect is the caching mechanism for the product catalog, which enhances performance by reducing database load and improving data retrieval times. By effectively configuring and managing the catalog caching mechanisms in Optimizely Commerce Connect, applications can achieve improved performance, reduce server load, and ensure that users receive up-to-date catalog.&lt;/p&gt;
&lt;h1&gt;Catalog Caching Configurations&lt;/h1&gt;
&lt;p&gt;These settings help manage how long different types of catalog data are stored in the cache before expiration, thereby optimizing data retrieval and system performance.&lt;/p&gt;
&lt;h3&gt;Commerce Connect V13&lt;/h3&gt;
&lt;p&gt;Caching for each subsystem, including catalogs and orders, is configured within its respective configuration files. For example, caching for catalogs can be found in &lt;em&gt;ecf.catalog.config&lt;/em&gt; located in the site&#39;s &lt;em&gt;configs&lt;/em&gt; folder.&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;&amp;lt;Cache enabled=&quot;true&quot; 
       collectionTimeout=&quot;0:5:0&quot; 
       entryTimeout=&quot;0:5:0&quot;
       nodeTimeout=&quot;0:5:0&quot; 
       schemaTimeout=&quot;1:0:0&quot;/&amp;gt;&lt;/code&gt;&lt;/pre&gt;
&lt;h3&gt;Commerce Connect V14&lt;/h3&gt;
&lt;p&gt;&amp;nbsp;Cache settings for the Catalogs subsystem, using AppSettings.json&lt;/p&gt;
&lt;pre class=&quot;language-markup&quot;&gt;&lt;code&gt;&quot;EPiServer&quot;: {
       &quot;Commerce&quot;: {
          &quot;CatalogOptions&quot;: {
            &quot;Cache&quot;: {
              &quot;UseCache&quot;: true,
              &quot;ContentVersionCacheExpiration&quot;: &quot;00:05:00&quot;,
              &quot;CollectionCacheExpiration&quot;: &quot;00:05:00&quot;,
              &quot;EntryCacheExpiration&quot;: &quot;00:05:00&quot;,
              &quot;NodeCacheExpiration&quot;: &quot;00:05:00&quot;
            }
          }
       }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Cache settings for the Catalogs subsystem can be used using Startup also.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;public void ConfigureServices(IServiceCollection services)
    {
        services.Configure&amp;lt;CatalogOptions&amp;gt;(o =&amp;gt;
        {
            o.Cache.UseCache = true;
            o.Cache.ContentVersionCacheExpiration = TimeSpan.FromMinutes(05);
            o.Cache.CollectionCacheExpiration = TimeSpan.FromMinutes(05);
            o.Cache.EntryCacheExpiration = TimeSpan.FromMinutes(05);
            o.Cache.NodeCacheExpiration = TimeSpan.FromMinutes(05);
        });
    }&lt;/code&gt;&lt;/pre&gt;
&lt;ul&gt;
&lt;li&gt;UseCache: Enables or disables caching.&lt;/li&gt;
&lt;li&gt;ContentVersionCacheExpiration: Sets the cache duration for content versions.&lt;/li&gt;
&lt;li&gt;CollectionCacheExpiration: Defines the cache duration for an array of entries. The cached data primarily consists of CatalogEntryDto objects. Since the Entry object is derived from the Data Transfer Object (DTO), the DTO itself is cached. However, it is also possible to cache the Entry objects directly instead of the DTO in some cases.&lt;/li&gt;
&lt;li&gt;EntryCacheExpiration: Specifies the cache duration for individual catalog entries. The cached data primarily consists of CatalogEntryDto objects.&lt;/li&gt;
&lt;li&gt;NodeCacheExpiration: Determines the cache duration for catalog nodes.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Cache Invalidation&lt;/h2&gt;
&lt;p&gt;Cache invalidation ensures that outdated or modified data does not persist in the cache, maintaining data consistency. In the catalog subsystem, the cache is invalidated under the following circumstances:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Expiration&lt;/strong&gt;: Cached data is automatically invalidated when it reaches the specified timeout duration.&lt;br /&gt;&lt;strong&gt;Data Updates&lt;/strong&gt;: If a catalog object is updated, the corresponding cache entries are invalidated to reflect the changes.&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;p&gt;References:&amp;nbsp;&lt;a href=&quot;https://docs.developers.optimizely.com/customized-commerce/docs/caching&quot;&gt;https://docs.developers.optimizely.com/customized-commerce/docs/caching&lt;/a&gt;&lt;/p&gt;</id><updated>2025-02-14T11:22:03.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Dynamic packages in Commerce Connect</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2024/11/support-for-dynamic-packages-in-commerce-connect/" /><id>&lt;p&gt;In Optimizely Commerce Connect, you can group different items using packages and bundles.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Package: A package has one or more versions of a product (called variants) and possibly other packages. It has one SKU (a unique code) and one price. When you add a package to a shopping cart, it appears as a single item.&lt;/li&gt;
&lt;li&gt;Bundle: A bundle is a group of packages, products, and variants, each with its price. Unlike packages, each item in a bundle appears separately in the cart, allowing customers to buy several items at once but treat each as its cart item&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;br /&gt;From EPiServer.Commerce 14.29.0 you can have dynamic packages&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Dynamic Package (beta): This is similar to a regular package but gives customers more choices. It includes multiple products, each with one or more variants, and has a single SKU and price. Customers can choose which version (variant) of each product they want in the package. Like a regular package, it shows up as one item in the cart.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Dynamic Packages&amp;nbsp;&lt;/h1&gt;
&lt;p&gt;There are many use cases where dynamic packages help. A very common use case is when customers are selecting some internet service provider along with a phone line or TV, Telecom companies allow users to dynamically create packages based on their service needs, combining internet, cable, and phone services.&lt;/p&gt;
&lt;p&gt;On a travel website, customers can create their travel packages by selecting a combination of flights, hotels, car rentals, and activities. This dynamic packaging enables customers to tailor their trip based on their budget, preferred airlines, hotel standards, and desired experiences.&lt;/p&gt;
&lt;p&gt;The dynamic packages feature in Commerce Connect is currently in beta from 14.29.0. It is disabled by default.&lt;/p&gt;
&lt;p&gt;Developer&#39;s documentation: &lt;a href=&quot;https://docs.developers.optimizely.com/customized-commerce/docs/dynamic-packages&quot;&gt;https://docs.developers.optimizely.com/customized-commerce/docs/dynamic-packages&lt;/a&gt;&amp;nbsp;&lt;/p&gt;</id><updated>2024-11-01T12:22:28.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>keep special characters in URL</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2024/9/keep-special-characters-in-url/" /><id>&lt;p&gt;When creating a page, the default URL segment validation automatically replaces special characters with their standard equivalents (e.g., &quot;&amp;auml;&quot; is replaced with &quot;a&quot;). However, some clients may require these special characters to remain intact in URLs for non-English versions of their website.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;var validChars = &quot;&amp;uuml; &amp;ouml; &amp;auml; &amp;szlig; &amp;oacute; &amp;ntilde; &amp;aacute; &amp;aacute; &amp;eacute; &amp;iacute; &amp;oacute; ő &amp;uacute; &amp;uuml; &amp;ntilde;&quot;; &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For CMS 12&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;//Startup.cs
services.Configure&amp;lt;UrlSegmentOptions&amp;gt;(config =&amp;gt; {
    config.SupportIriCharacters = true;
    config.ValidCharacters = @&quot;A-Za-z0-9\-_~\.\$&quot; + validChars;
}); &lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;For CMS 11&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class UrlSegmentConfigurationModule : IConfigurableModule
{
    public void ConfigureContainer(ServiceConfigurationContext context)
    {
        var validChars = &quot;&amp;uuml; &amp;ouml; &amp;auml; &amp;szlig; &amp;oacute; &amp;ntilde; &amp;aacute; &amp;aacute; &amp;eacute; &amp;iacute; &amp;oacute; ő &amp;uacute; &amp;uuml; &amp;ntilde;&quot;; 
        context.Services.RemoveAll&amp;lt;UrlSegmentOptions&amp;gt;();
        context.Services.AddSingleton&amp;lt;UrlSegmentOptions&amp;gt;(s =&amp;gt; new UrlSegmentOptions
        {
            SupportIriCharacters = true,
            ValidCharacters = @&quot;\p{L}0-9\-_~\.\$&quot; + validChars
        });
    }

    public void Initialize(InitializationEngine context){}

    public void Uninitialize(InitializationEngine context) { }
}&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;References:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://support.optimizely.com/hc/en-us/articles/115005062883-Enable-special-characters-in-URL-Segment&quot;&gt;https://support.optimizely.com/hc/en-us/articles/115005062883-Enable-special-characters-in-URL-Segment&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;/link/a5c3e4adc40b463f91f27b7092631e27.aspx&quot;&gt;https://world.optimizely.com/blogs/Minesh-Shah/Dates/2023/2/url-rewrites-in-cms12--net-6-/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.w3.org/International/articles/idn-and-iri/&quot;&gt;An Introduction to Multilingual Web Addresses&lt;/a&gt;&amp;nbsp;&lt;/li&gt;
&lt;/ul&gt;</id><updated>2024-09-19T16:47:59.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Opti ID overview</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2024/7/opti-id-overview/" /><id>&lt;p&gt;Opti ID allows you to log in once and switch between Optimizely products using Okta, Entra ID, or a local account. You can also manage all your users from one place. you can watch an interactive demo &lt;a href=&quot;https://optimizely.navattic.com/awr50u0h&quot;&gt;here&lt;/a&gt;.&amp;nbsp; The Optimizely platform offers:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A single login (Single Sign-On or SSO) with support for multi-factor authentication (MFA), using your own MFA setup and directory authentication provider.&lt;/li&gt;
&lt;li&gt;The ability to switch between apps without having to log in again.&lt;/li&gt;
&lt;li&gt;The option to manage users, groups, and roles with Opti ID.&lt;/li&gt;
&lt;li&gt;A dashboard for managing account information, usage, and billing.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Opti ID is currently available for the following Optimizely products:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Commerce Connect&lt;/li&gt;
&lt;li&gt;Configured Commerce&lt;/li&gt;
&lt;li&gt;Content Management System (CMS 12)&amp;nbsp;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Optimizely CMS SaaS&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;Content Marketing Platform (CMP)&lt;/li&gt;
&lt;li&gt;Digital Experience Platform (DXP)&lt;/li&gt;
&lt;li&gt;Experimentation&lt;/li&gt;
&lt;li&gt;Experiment Collaboration&lt;/li&gt;
&lt;li&gt;Optimizely Data Platform (ODP)&lt;/li&gt;
&lt;li&gt;Product Information Management (PIM)&lt;/li&gt;
&lt;li&gt;Product Recommendations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;It is easy to set up Opti ID in your solution with the following steps:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Install the NuGet Package:&lt;/strong&gt;&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;dotnet add package EPiServer.OptimizelyIdentity&lt;/code&gt;&lt;/pre&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Enable Opti ID:&lt;/strong&gt; In your Startup.cs file, add the following line in the ConfigureServices method to enable Opti ID globally&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;services.AddOptimizelyIdentity(useAsDefault: true);&lt;/code&gt;&lt;/pre&gt;
This makes Opti ID, active throughout the application, including in shell modules, preview, and edit modes. You can customize authentication schemes using &lt;strong&gt;AuthenticationOptions&lt;/strong&gt; if needed.&amp;nbsp;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Remove Unnecessary Services:&lt;/strong&gt; If you&#39;re not using ASP.NET Identity, remove any calls to &lt;strong&gt;services.AddCmsAspNetIdentity()&lt;/strong&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Virtual Roles:&lt;/strong&gt; Opti ID automatically maps the virtual roles CmsEditors and CmsAdmins.&amp;nbsp;If you already have these mappings, you&#39;ll need to remove them.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Testing:&lt;/strong&gt; Ensure your user is assigned to at least one built-in system role for the CMS before testing. Deploy your changes to DXP or run the application locally with Opti ID set up.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Running Opti ID Locally:&lt;/strong&gt; &lt;a href=&quot;https://localhost:7595&quot;&gt;&lt;/a&gt;To configure local usage, add these settings in your appsettings.json file. These are automatically provided when deploying to the Optimizely Digital Experience Platform (DXP) or can be found in the DXP Management Portal under API &amp;gt; Opti ID dev key&lt;/p&gt;
&lt;div class=&quot;overflow-y-auto p-4&quot;&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;{
  &quot;EPiServer&quot;: {
    &quot;Cms&quot;: {
      &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;Opti ID will work locally with the following ports:&lt;/p&gt;
&lt;p&gt;https://localhost:5000&lt;br /&gt;https://localhost:5096&lt;br /&gt;https://localhost:6921&lt;br /&gt;&lt;a href=&quot;https://localhost:7595&quot;&gt;https://localhost:7595&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;br /&gt;References: https://support.optimizely.com/hc/en-us/articles/12613241464461-Get-started-with-Opti-ID&lt;/p&gt;
&lt;/div&gt;
&lt;/li&gt;
&lt;/ol&gt;</id><updated>2024-07-26T09:35:21.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Optimizely Forms: Safeguarding Your Data</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2024/5/episerver-forms-safeguarding-your-data/" /><id>&lt;p&gt;With the rise of cyber threats and privacy concerns, safeguarding sensitive information has become a top priority for businesses across all industries. As organizations collect and manage data through various channels, ensuring the security of online forms has become crucial. Optimizely Forms, offers a robust solution for creating and managing forms, but how does it fare in terms of security?&lt;/p&gt;
&lt;p&gt;Content authors can design multiple kinds of forms, Whether it&#39;s collecting customer feedback, processing orders, gathering leads, or forms that may contain sensitive data. Sensitive information submitted through forms could be vulnerable to various threats, including data breaches, unauthorized access, and manipulation. Forms can ask users to upload files, a user-uploaded file can also be a threat or a sensitive document.&amp;nbsp;&lt;/p&gt;
&lt;p&gt;Optimizely Forms offers a comprehensive set of security features, customizations, and capabilities to protect user data and mitigate security risks. However, ensuring security is a shared responsibility and requires a proactive approach, encompassing continuous monitoring, updates, and adherence to best practices to safeguard against evolving threats and developers and editor&#39;s training.&lt;/p&gt;
&lt;p&gt;To address security concerns, Optimizely Forms offers several built-in or customizable security features, including &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.2.0-forms/docs/encrypting-form-data&quot;&gt;data encryption&lt;/a&gt;, &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.2.0-forms/docs/creating-new-data-storage-mechanism&quot;&gt;data storage mechanisms&lt;/a&gt;, v&lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.2.0-forms/docs/creating-form-element-with-validator&quot;&gt;alidation and sanitization&lt;/a&gt;, &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.2.0-forms/docs/configuring-optimizely-forms&quot;&gt;limited access control&lt;/a&gt;, CAPTCHA Integration, and &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.2.0-forms/docs/customizing-retention-policies&quot;&gt;data retention policies&lt;/a&gt;. It is &lt;a href=&quot;https://docs.developers.optimizely.com/content-management-system/v1.2.0-forms/docs/webhooks-actor&quot;&gt;not required to store data&lt;/a&gt; within the CMS database. Those should be considered while implementing and using Forms.&lt;/p&gt;
&lt;p&gt;Organizations can enhance the security of Optimizely Forms by following these best practices:&lt;/p&gt;
&lt;p&gt;User Education: Educate users about security best practices, such as creating strong passwords, recognizing phishing attempts, and exercising caution when sharing sensitive information via Optimizely Forms. e.g. If submitted data is stored in Forms, then it will be visible to any editors who have access to CMS regardless the data is related or not. User-uploaded files can appear in Search results within the CMS or globally if not taken care of.&lt;/p&gt;
&lt;p&gt;Regular Updates: Stay vigilant about applying software updates and patches released by Optimizely to address known vulnerabilities and security flaws in Optimizely Forms.&lt;/p&gt;
&lt;p&gt;Strong Authentication: Implement strong authentication mechanisms, such as multi-factor authentication (MFA), to verify the identities of users accessing Optimizely Forms backend interfaces and administrative dashboards.&lt;/p&gt;
&lt;p&gt;Security Testing: Conduct regular security assessments, including penetration testing and vulnerability scanning, to identify and remediate potential security weaknesses in Optimizely Forms implementations.&lt;/p&gt;
&lt;p&gt;Malware Scan for User uploaded files: Implement &lt;a href=&quot;https://learn.microsoft.com/en-us/azure/defender-for-cloud/defender-for-storage-malware-scan&quot;&gt;scanning&lt;/a&gt; of user-uploaded files, solutions will be different, depending on the infrastructure.&lt;/p&gt;</id><updated>2024-05-16T07:48:22.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Top tip: Better, do not save EPiServer.Foms submissions for sensitive data</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2024/3/toptip-stop-indexing-users-uploaded-files/" /><id>&lt;p&gt;&lt;span&gt;If your website utilizes EPiServer.Forms and includes forms where users can upload files, there is a significant probability that the Find/Search Indexing Job will also index those files. Consequently, these files may become accessible through searches facilitated by Find. Editors navigating the Editor area may encounter these files when searching for images, potentially leading to public availability of search results also depending on implementations. To address this issue, a straightforward solution is to cease indexing user-uploaded files. One possible approach to prevent the indexing of uploaded files from forms is outlined in the code below.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;ContentIndexer.Instance.Conventions.ForInstancesOf&amp;lt;IContentMedia&amp;gt;().ShouldIndex(x =&amp;gt; 
     _contentLoader.GetAncestors(documentFileBase.ParentLink).Select(x=&amp;gt;x.Name).Contains( EPiServer.Forms.Constants.FileUploadFolderName));
&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;This will stop indexing users&#39; uploaded files, and certainly slow down the indexing job as we will be loading ancestors.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;It&#39;s important to note that despite this adjustment, users&#39; uploaded files will remain accessible to all editors through the Form Submissions View. Depending on the sensitivity of the uploaded user&#39;s data, it&#39;s imperative to consider this accessibility. Ideally, in cases where user data is sensitive, refrain from saving form submissions within forms due to the limited security associated with form submissions. &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Editors play a pivotal role in designing forms, and their training is crucial, particularly in alignment with the nature of the business, the type of information they will be gathering, and the relevant legislation. Training should ensure that editors understand the intricacies of data collection, its implications, and compliance requirements.&amp;nbsp;&lt;/span&gt;&lt;/p&gt;</id><updated>2024-03-22T10:27:12.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Toptip - what is .well-known folder</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2024/1/toptip----well-known-folder/" /><id>&lt;p&gt;&lt;span&gt;Within your &lt;/span&gt;&lt;code&gt;~/public&lt;/code&gt;&lt;span&gt; folder, you may come across a directory named &quot;.well-known.&quot; This directory is frequently employed in web-based protocols to retrieve &quot;site-wide metadata&quot; related to a host before initiating a request. It&#39;s important to note that the absence of this folder doesn&#39;t necessarily indicate an issue; it simply means it hasn&#39;t been utilized or generated yet.&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Here are some examples of what you might find in the &quot;.well-known&quot; directory:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;.well-known/security.txt:&lt;/strong&gt; Contains information about a website&#39;s security policies and &lt;a href=&quot;https://securitytxt.org/&quot;&gt;contact information for security researchers&lt;/a&gt;.&lt;br /&gt;Please read some helpful blogs on this topic.&lt;br /&gt;&lt;a href=&quot;https://www.gulla.net/en/blog/security.txt&quot;&gt;https://www.gulla.net/en/blog/security.txt&lt;/a&gt;&lt;br /&gt;&lt;a href=&quot;https://optimizely.blog/2023/03/easy-implementation-of-security.txt-with-minimal-api-.net-core&quot;&gt;https://optimizely.blog/2023/03/easy-implementation-of-security.txt-with-minimal-api-.net-core&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;.well-known/apple-app-site-association (AASA):&lt;/strong&gt; Used for &lt;a href=&quot;https://developer.apple.com/library/archive/documentation/General/Conceptual/AppSearch/UniversalLinks.html&quot;&gt;associating iOS apps with websites&lt;/a&gt;, enabling features like Universal Links. This file doesn&#39;t have an extension.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;.well-known/assetlinks.json: &lt;/strong&gt;&lt;span&gt;Used in the context of Android App Links. &lt;a href=&quot;https://developer.android.com/training/app-links/verify-android-applinks&quot;&gt;Android App Links&lt;/a&gt; are a way to associate a website with a specific Android app, allowing the app to open when certain links are clicked, even if the app is not currently installed on the device.&lt;/span&gt;&lt;/li&gt;
&lt;/ol&gt;</id><updated>2024-01-15T12:46:00.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Top tip - Auto Suggestion for editors</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2023/12/top-tip---auto-suggestion-for-editors/" /><id>&lt;p&gt;&lt;span&gt;Auto-suggestion can significantly enhance the efficiency, consistency, and overall quality of content created and managed by editors in a content management system. It serves as a valuable tool that supports editors in maintaining high standards and streamlining their workflow.&amp;nbsp;&lt;/span&gt;This small feature can benefit editors in many ways such as saving time by predicting and suggesting words or phrases for some fields as they type. It can promote consistency in writing style and terminology across the content. Editors will adhere to specific style guides or content standards if required for some fields.&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Developers can add simple built-in auto-suggestions for editors to select when working in the edit view of Optimizely Content Management System (CMS)&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;Create a Custom selection class by inheriting ISelectionQuery e.g.&lt;/span&gt;&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;using System;
    using System.Collections.Generic;
    using System.Linq;
    using EPiServer.ServiceLocation;
    using EPiServer.Shell.ObjectEditing;
     
      namespace EPiServer.Samples
    {
        [ServiceConfiguration(typeof(ISelectionQuery))]
        public class MySelectionQuery : ISelectionQuery
        {
            SelectItem[] _items;
            public MySelectionQuery()
            {
                _items = new SelectItem[] { 
                    new SelectItem() { Text = String.Empty, Value = String.Empty },
                    new SelectItem() { Text = &quot;Alternative1&quot;, Value = &quot;1&quot; },
                    new SelectItem() { Text = &quot;Alternative 2&quot;, Value = &quot;2&quot; } };
            }
           //Will be called when the editor types something in the selection editor.
            public IEnumerable&amp;lt;ISelectItem&amp;gt; GetItems(string query)
            {
                return _items.Where(i =&amp;gt; i.Text.StartsWith(query, StringComparison.OrdinalIgnoreCase));
            }
           //Will be called when initializing an editor with an existing value to get the corresponding text representation.
            public ISelectItem GetItemByValue(string value)
            {
                return _items.FirstOrDefault(i =&amp;gt; i.Value.Equals(value));
            }
        }
    }&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Add the &lt;strong&gt;AutoSuggestionEditor&lt;/strong&gt; attribute with your properties as below and set the &lt;strong&gt;AllowCustomValues&lt;/strong&gt; property to true so that the editor is not forced to select one of the suggested choices. By default, this property is set to false and the editor must select one of the suggested values.&lt;/p&gt;
&lt;pre class=&quot;language-csharp&quot;&gt;&lt;code&gt;[AutoSuggestSelection(typeof(MySelectionQuery))]
public virtual string SelectionEditor1 { get; set; }
    
[AutoSuggestSelection(typeof(MySelectionQuery), AllowCustomValues = true)]
public virtual string SelectionEditor2 { get; set; }&lt;/code&gt;&lt;/pre&gt;</id><updated>2023-12-28T11:22:21.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Top tip - Health Checks</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2023/12/top-tip---health-checks/" /><id>&lt;p&gt;Whether your site is a DXP or an Azure-hosted site, you may need to determine the &lt;span&gt;state of your application as if it&#39;s healthy or unhealthy. EPiServer.Cms.HealthCheck will provide you an endpoint as /epi/health, The Blog (&lt;a href=&quot;/link/e7fd6d67f00e484d94be75b644c597be.aspx&quot;&gt;https://world.optimizely.com/blogs/scott-reed/dates/2023/3/optimizely-dxp-health-checks-and-creating-custom-checks/&lt;/a&gt;) by Scott Reed explains this setup for CMS 12 in detail. It doesn&#39;t limit us to service health only, Service can be extended for many other scenarios such as listing the vulnerabilities, and checking up on some configurations or DB table sizes. The blog is a bit old but still worth reading (&lt;a href=&quot;https://www.codeart.dk/blog/2021/5/new-project-optimizely-episerver-health-checker/&quot;&gt;https://www.codeart.dk/blog/2021/5/new-project-optimizely-episerver-health-checker/&lt;/a&gt;).&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span&gt;&quot;love what you do&quot;&lt;/span&gt;&lt;/p&gt;</id><updated>2023-12-26T14:28:06.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Monolith, JAMStack, SPA, or Composable, Optimizely CMS is the best fit</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2023/10/monolith-jamstack-spa-or-composable-optimizely-cms-is-a-best-fit/" /><id>&lt;p&gt;Each website architecture has its own benefits and challenges.&lt;/p&gt;
&lt;p&gt;Monolith is a traditional and proven architecture to deliver web apps, combining FE and BE.&lt;/p&gt;
&lt;p&gt;To craft a JAMStack site, you employ static-site generation tools such as NextJS or Gatsby. These tools transform your website into HTML during the building process, thus introducing a game-changing shift as pages are constructed at a separate juncture.&lt;/p&gt;
&lt;p&gt;JAMStack is often confused with SPA, but there are a few fundamental differences. A Single Page Application (SPA) is constructed directly within a user&#39;s browser. When a visitor requests a page, the markup and JavaScript are transmitted to the user&#39;s browser, and the webpage is dynamically assembled in real time.&lt;/p&gt;
&lt;p&gt;Composable architecture focuses on Infrastructure as code, infrastructure automation, multi-cloud strategy, and portfolio rationalization.&lt;/p&gt;
&lt;p&gt;Optimizely does not drive the architecture anymore but gives the flexibility to adopt any architecture that suits best to business for all of your content requirements.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://i.ibb.co/Sy4p6fB/architecture.jpg&quot; width=&quot;661&quot; alt=&quot;Options&quot; height=&quot;263&quot; style=&quot;display: block; margin-left: auto; margin-right: auto;&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;SAS Core was introduced on Opticon San Deigo 2023 along with many other exciting enhancements and will be available in early 2024, PAS Core is the CMS that we know to date, We can get content from any source other than the CMS also&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Optimizely Graph (Semantic and flexible search) converts your content into a graph structure. Just as search engines crawl the web to construct graph-based content indices, Optimizely Graph reshapes your CMS content for easy querying. It allows you to explore and manipulate your content using the GraphQL standard&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Builder is a visual editor&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Single source for all of your content needs, consume content anywhere&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;Content will remain available, even if CMS goes down&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;span&gt;PAS/Head solution will be available with or without the Optimizely graph&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;</id><updated>2023-10-14T17:44:53.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Considerations before you decide to use Content Definition API</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2022/12/considerations-before-you-decide-to-use-content-definition-api/" /><id>&lt;p&gt;With the introduction of Content Definition API, it became possible to keep the definitions of the content structures, entirely in Front End and design a true headless solution with complete separation of the back end and front end. We can manage types via API and create new types as blocks and pages even without a release of the backend and create strongly typed typescript objects depending on the solution. Before you decide whether the use of Content Definition API is the right solution for you or not, you will need to consider the following points.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Example projects such as &lt;a href=&quot;https://github.com/episerver/content-delivery-js-sdk&quot;&gt;https://github.com/episerver/content-delivery-js-sdk&lt;/a&gt; rely on a single big manifest.json to define all the types. To achieve strongly typed objects, you will still need extra development efforts, there could be different approaches to achieve this, e.g. &lt;a href=&quot;https://github.com/episerver/Foundation-spa-react/tree/Cms12/&quot;&gt;https://github.com/episerver/Foundation-spa-react/tree/Cms12/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;If you are writing a solution for DXP and considering Content Definition API just for the sake of achieving strongly typed objects, then an alternative approach could be to use Content Graph &lt;a href=&quot;/link/2aefcdfa9169413db278877740df254a.aspx&quot;&gt;https://world.optimizely.com/blogs/Jonas-Bergqvist/Dates/2022/9/strongly-typed-cms-content-with-typescript--react3/&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Types generated via Content Definition API are of Types from DB, the feature available for CMS Editor for Types from code will not be available.&lt;/li&gt;
&lt;li&gt;There is no replacement available for some .Net attributes such as AllowedTypes (e.g. to restrict ContentArea for specific blocks)&lt;/li&gt;
&lt;li&gt;All settings available in the admin UI are not available through the API yet. For example, you cannot manage websites, languages, or translations.&lt;/li&gt;
&lt;li&gt;Since changes could be made to the same content types but from different sources, there may be conflicts that could affect existing content. To reduce the risk of conflicts, you should add version information to the content types. To deal with the conflicts, follow semantic versioning &lt;a href=&quot;https://docs.developers.optimizely.com/content-cloud/v1.7.0-content-definitions-api/docs/semantic-versioning&quot;&gt;https://docs.developers.optimizely.com/content-cloud/v1.7.0-content-definitions-api/docs/semantic-versioning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The Language Branch API is available only in version 3.4.0 or later of the Content Definitions API.&lt;/li&gt;
&lt;/ul&gt;</id><updated>2022-12-30T14:06:19.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>academy.episerver.com - SAP Litmos error</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2021/8/academy-episerver-com---sap-litmos/" /><id>&lt;p&gt;&#39;academy.episerver.com&#39; URL wasn&#39;t working for me, rather showing some confusing message about SAP Litmos... don&#39;t wait that site will come back sooner.&amp;nbsp;Just readjust bookmarks, as &#39;academy.optimizely.com&#39; is the URL to use onwards. Same credentials should work.&lt;br /&gt;&lt;br /&gt;&lt;/p&gt;</id><updated>2021-08-16T07:42:24.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>ODP handy reference guide - Web SDK</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2021/6/odp-handy-reference-guide---web-sdk/" /><id>&lt;p&gt;A quick reference guide, developers might need before starting a new ODP/Zaius implementation based on &lt;a href=&quot;https://docs.developers.zaius.com/&quot;&gt;https://docs.developers.zaius.com/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It will be worthy to watch &lt;a href=&quot;https://www.david-tec.com/2021/05/video-adding-optimizely-data-platform-to-optimizely-commerce-cloud/&quot;&gt;https://www.david-tec.com/2021/05/video-adding-optimizely-data-platform-to-optimizely-commerce-cloud/&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;mce-toc&quot;&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1f8pln9370&quot;&gt;Authentication&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1f8pln9381&quot;&gt;Batch Requests&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1f8pln9382&quot;&gt;Consent&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1f8pln9383&quot;&gt;Messaging Lists&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1f8pln9384&quot;&gt;Customers/Profiles&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1f8pln9385&quot;&gt;Custom event:&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;#mcetoc_1f8pln9386&quot;&gt;Standard events:&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;h2&gt;Authentication&lt;/h2&gt;
&lt;p&gt;ODP/Zaius provides two forms of authentication:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Public (Tracker ID) - is used for most API calls that send data&lt;/li&gt;
&lt;li&gt;Private - is used for querying data&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Keys are scoped at the account level. When you revoke a private API key, your existing key is available for 12 hours as a grace period. Public API Key and Tracker ID are synonymous.&lt;/p&gt;
&lt;h2&gt;Batch Requests&lt;/h2&gt;
&lt;p&gt;Bulk data push should be done in batch, every request can include up to 500 distinct objects. As an example, at 500 customers per request with 10 requests per second as a rate limit, you can process 5,000 customer updates per second. For higher rate limits contact support.&lt;/p&gt;
&lt;h2&gt;Consent&lt;/h2&gt;
&lt;p&gt;Consent may impact attempts to send marketing campaigns to the identifier. If noted as opted-out, certain marketing services or channels may skip the identifier, even when qualified for the campaign. Customers who have opted out cannot receive marketing messages. Only transactional messages will be received by these customers.&lt;/p&gt;
&lt;p&gt;Example:&amp;nbsp;&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.consent({  consent: true,  identifier_field_name: &#39;email&#39;,  identifier_value: &#39;tyler@zaius.com&#39;,  update_reason: &#39;&#39;,  update_ts: 123456789,  event_data: {}  });&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Messaging Lists&lt;/h2&gt;
&lt;p&gt;Group customers for the purposes of tracking their communication preferences.&lt;/p&gt;
&lt;h2&gt;Customers/Profiles&lt;/h2&gt;
&lt;p&gt;To Create/Update/View Customer&amp;rsquo;s profile. Cookie with name &amp;lsquo;vuid&amp;rsquo; contains the reference to profile id.&lt;a href=&quot;https://docs.developers.zaius.com/api/rest-api/customers&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Anonymize - will reset the cookie identifier associated with the browser. Use this when a user logs out or on shared devices between form submissions that include identifiers.&lt;/p&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.customer({
    email: &quot;johnny.zaius@zaius.com&quot;
  },{
    first_name: &quot;Johnny&quot;,
    last_name: &quot;Zaius&quot;,
    gender: &quot;M&quot;
  });&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Events&lt;/p&gt;
&lt;p&gt;Customer behaviors are tracked as events. &lt;span&gt;Events are composed of a Type(a categorical name associated with the event), Action(activity a user did within that event type), and additional metadata via fields on the event,&amp;nbsp;&lt;/span&gt; &lt;span&gt;at minimum, events require an event type and an identifier to associate the event with a customer. &lt;/span&gt;There are two types of events, custom, and standard,&lt;/p&gt;
&lt;h2&gt;Custom event:&lt;/h2&gt;
&lt;p&gt;Example:&lt;/p&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;your_event_type_here&quot;, { 
    action: &quot;your_event_action_here&quot;,
    example_custom_field: &quot;example_value&quot;
});&lt;/code&gt;&lt;/pre&gt;
&lt;h2&gt;Standard events:&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;text-4505230f--TextH400-3033861f--textContentFamily-49a318e1&quot;&gt;&lt;span&gt;These are pre-defined event type/action and expected by Zaius to be accompanied with certain fields. The usage of these events makes the usage of Zaius simpler for common use cases. Zaius does not recommend or formally support Order events via the Web SDK to ensure that ad blockers do not block the purchase event. Zaius only supports sending Order refunds, returns &amp;amp; cancellations via API or CSV to ensure that ad blockers do not block these critical events. &lt;a href=&quot;https://docs.developers.zaius.com/api/&quot;&gt;https://docs.developers.zaius.com/api/&lt;/a&gt;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;table&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Event TYPE&lt;/td&gt;
&lt;td&gt;Activity&lt;/td&gt;
&lt;td&gt;Example&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;https://docs.developers.zaius.com/web-sdk/events/account&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;account&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;login&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;account&quot;, { action: &quot;login&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;logout&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;account&quot;, { action: &quot;logout&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;register&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;account&quot;, { action: &quot;register&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;update&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;account&quot;, { action: &quot;update&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;Anonymize will reset the cookie identifier associated with the browser. Use this when a user logs out or on shared devices between form submissions that include identifiers.&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;anonymise&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.anonymize();
&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span&gt;Zaius will automatically parse the appropriate page path information.&lt;/span&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;pageview&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;pageview&quot;);&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;https://docs.developers.zaius.com/web-sdk/events/navigation&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;navigation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;search&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;navigation&quot;, { 
    action: &quot;search&quot;, 
    search_term:&quot;cameras, vcr&quot;,
    category: &quot;electronics &amp;gt; consumer&quot;
});&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;sort&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;navigation&quot;, { 
    action: &quot;sort&quot;
});&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;filter&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;navigation&quot;, { 
    action: &quot;filter&quot;
});&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;https://docs.developers.zaius.com/web-sdk/customers/consent&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;consent&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;opt-in&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.consent({
  consent: true,
  identifier_field_name: &#39;email&#39;,
  identifier_value: &#39;tyler@zaius.com&#39;,
  update_reason: &#39;&#39;,
  update_ts: 123456789,
  event_data: {}
  });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;opt-out&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;&lt;a href=&quot;https://docs.developers.zaius.com/web-sdk/events/products&quot;&gt;https://docs.developers.zaius.com/web-sdk/events/products&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;product_id is required on all events with an event type of product&lt;/p&gt;
&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;product&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;detail&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;product&quot;, { action: &quot;detail&quot;, product_id: &quot;product-2143&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;add_to_cart&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;product&quot;, { action: &quot;add_to_cart&quot;, product_id: &quot;product-2143&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;remove_from_cart&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;product&quot;, { action: &quot;remove_from_cart&quot;, product_id: &quot;product-2143&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;add_to_wishlist&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;product&quot;, { action: &quot;add_to_wishlist&quot;, product_id: &quot;product-2143&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;remove_from_wishlist&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;product&quot;, { action: &quot;remove_from_wishlist&quot;, product_id: &quot;product-2143&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;https://docs.developers.zaius.com/web-sdk/events/ads&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;advertisement&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;impression&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;advertisement&quot;, { action: &quot;impression&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;click&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;zaius.event(&quot;advertisement&quot;, { action: &quot;click&quot; });&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;p&gt;&lt;span class=&quot;text-4505230f--TextH400-3033861f--textContentFamily-49a318e1&quot;&gt;&lt;span&gt;Messaging Lists allow you to group customers for the purposes of tracking their communication preferences. For example, allowing customers to subscribe to your company newsletter or for holiday news.&amp;nbsp;&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;div class=&quot;reset-3c756112--blockHint-a7403a60&quot;&gt;
&lt;p&gt;&lt;span class=&quot;text-4505230f--TextH400-3033861f--textContentFamily-49a318e1&quot;&gt;&lt;span&gt;Zaius does not require customers to be subscribed to a List to receive emails.&lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;subscribe&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;
&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code&gt;// subscribe johnny@zaius.com to newsletter list
zaius.subscribe({list_id: &#39;newsletter&#39;, email: &#39;johnny@zaius.com&#39;});

// unsubscribe johnny@zaius.com from newsletter list
zaius.unsubscribe({list_id: &#39;newsletter&#39;, email: &#39;johnny@zaius.com&#39;});

// subscribe johnny@zaius.com to three lists at once
zaius.subscribe({
  list_id: [&quot;newsletter&quot;, &quot;promotion&quot;, &quot;product_update&quot;], 
  email: &quot;johnny@zaius.com&quot;
});

// unsubscribe johnny@zaius.com from multiple lists at once
zaius.unsubscribe({
  list_id: [&quot;newsletter&quot;, &quot;product_update&quot;], 
  email: &quot;johnny@zaius.com&quot;
});

zaius.subscribe({
  // subscribe Johnny to all lists
  
  list_id: [&quot;newsletter&quot;, &quot;promotion&quot;, &quot;product_update&quot;],
  email: &quot;johnny@zaius.com&quot;,
  
  // update Johnny&#39;s record to include his full name
  first_name: &quot;Johnny&quot;,
  last_name: &quot;Zaius&quot;,
  
  // store information on the subscribe events
  event_custom_field: &quot;my custom value&quot;,
  custom_number_field: 123
  
});

// zaius.unsubscribe also fully supports this syntax.&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;</id><updated>2021-06-22T11:06:19.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Zaius was destined to Optimizely</title><link href="https://digitalpixie.co.uk/?p=204" /><id>Optimizely(EPiServer)’s CDP journey that started from EPiServer Profile Store, destined to Optimizely Data Platform(Zaius). With the acquisition of Zaius, Optimizely (EPiServer) have a true and one of most sophisticated CDP into their product family. Partners and customers already having licenses of Visitor Intelligence should contact EPiServer/Optimizely support to know more about migrations plans. Visitor Intelligence [&amp;#8230;]</id><updated>2021-05-28T11:27:39.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Security Matters</title><link href="http://digitalpixie.co.uk/?p=125" /><id>No matter what is the size of your website, your project is handling sensitive information or it’s just a feedback form, Cyber Security matters for all. You are a novice or an expert, a developer, QA, or a solution architect, in your team. A team should have basic knowledge of cyber security. In the project [&amp;#8230;]</id><updated>2021-01-21T17:33:02.0000000Z</updated><summary type="html">Blog post</summary></entry> <entry><title>Episerver in microservices paradigm</title><link href="https://world.optimizely.com/blogs/K-Khan-/Dates/2020/6/episerver-in-microservices-paradigm/" /><id>&lt;p&gt;&amp;ldquo;A microservices architecture is an approach to build a server application as a set of small services. That means a microservices architecture is mainly oriented to the back-end, although the approach is also being used for the front end. Each service runs in its own process and communicates with other processes using protocols such as HTTP/HTTPS, WebSockets, or AMQP. Each microservice implements a specific end-to-end domain or business capability within a certain context boundary, and each must be developed autonomously and be deployable independently. Finally, each microservice should own its related domain data model and domain logic and could be based on different data storage technologies (SQL, NoSQL) and different programming languages.&amp;rdquo;[1]&lt;/p&gt;
&lt;p&gt;In Microservices architecture generally, contents are also served as a service, aka CaaS. The term CaaS refers to focus on managing structured contents that some restful/web services or feed that other subscribers or applications could consume. CaaS can be referred to as an abstraction on top of a headless CMS delivered via SaaS. A headless CMS is considered a good candidate to use in a microservices architecture. Generally developing a microservice is simple but overall architecture is complex. Planning a strong architecture is a key in microservices-based architectures. Selecting the right CMS is also one of the complex questions if a business is looking for some advanced CMS with features like personalization, analytics, and AI.&lt;/p&gt;
&lt;h1&gt;Is EPiServer Headless CMS a fit in the microservice landscape?&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;https://i.ibb.co/MhZ6MPs/Microservices.jpg&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;In EPiServer Headless, contents are served as JSON via a restful API so any programming language can consume.&lt;/li&gt;
&lt;li&gt;Provide content for native applications that are not HTML-based and Independence to integrate any new channel as we are not bounded with the CMS functionalities.&lt;/li&gt;
&lt;li&gt;It is Pluggable and configurable web API&lt;/li&gt;
&lt;li&gt;Support localized content and multi-site scenarios.&lt;/li&gt;
&lt;li&gt;Support common querying, filtering, and sorting scenarios,&amp;nbsp;able to query contents through Content Search API providing robust filtering and sorting via OData syntax&lt;/li&gt;
&lt;li&gt;Support returning access-controlled and personalized content where required.&lt;/li&gt;
&lt;li&gt;Scaleable and secure, Docker could be an option but might not be the best option to set up EpiServer Headless CMS. &quot;&lt;span&gt;Episerver chose&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/&quot;&gt;Microsoft Azure&lt;/a&gt;&lt;span&gt;&amp;nbsp;to support its Customer-Centric Digital Experience Platform, using&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/services/kubernetes-service/&quot;&gt;Azure Kubernetes Service (AKS)&lt;/a&gt;&lt;span&gt;&amp;nbsp;as the orchestration engine for high-availability multitenant microservices and&amp;nbsp;&lt;/span&gt;&lt;a href=&quot;https://azure.microsoft.com/en-us/services/app-service/&quot;&gt;Azure App Service&lt;/a&gt;&lt;span&gt;&amp;nbsp;for easily scalable web app deployment&quot;.&amp;nbsp;&lt;/span&gt;By default supports OAuth and cookie-based authentication, However, it is allowed to customize the authorization flow and use your preferred authorization mechanism like AzureAD or GitHub.&lt;/li&gt;
&lt;li&gt;Framework agnostic features such as on Page Editing can be used with any javascript framework such as Angular, React, or Vue.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;EPiServer Headless&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/link/6ffa5cb8173a414eac25740deeafdbc8.aspx&quot;&gt;https://world.episerver.com/documentation/developer-guides/content-delivery-api/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/7ce146c1219c46cfb41062d597a23723.aspx&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h2&gt;Future Of EPiServer Headless&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;/link/be8077bc415c4afca844daf0fb0e83bb.aspx&quot;&gt;https://world.episerver.com/blogs/martin-ottosen/dates/2019/12/asp-net-core-beta-program/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/e64362f8872e492ab4f3191267c0c760.aspx&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;Contextual considerations&lt;/h1&gt;
&lt;p&gt;Conceptually a microservice can be derived as a bounded context in a domain-driven design where each bounded context should have its own model and database. EPiServer CMS as a whole should be considered as a single bounded context. Content in itself can&amp;rsquo;t be divided further into microservices-based into their types (Images, Textual, or Pdfs).&lt;/p&gt;
&lt;p&gt;&amp;nbsp;&lt;/p&gt;
&lt;h1&gt;Content Considerations&lt;/h1&gt;
&lt;p&gt;In EPiServer a content item is not necessarily only a web page, it may not have an addressable URL and it may be just a container for data that can be seen as a database record. Sometimes, the same piece of content can be used on a page, on social media or in print which means the content is no longer assigned to a specific channel. Usually, those kinds of content items are simple with only basic property types and some metadata. Content Manager is available to create this kind of content.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/link/dbbcb8c637ae4dcc80685dd99ca3ae05.aspx&quot;&gt;https://world.episerver.com/blogs/bartosz-sekula/dates/2020/4/content-manager---lightweight-editing-ui/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/a4d4968ba9234975b52bfe6fe9719702.aspx&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/link/d9d8c3d5dc6249f88ad78c93cc70840c.aspx&quot; alt=&quot;&quot; /&gt;&lt;/p&gt;
&lt;h1&gt;SPA implementations with Headless CMS with OPE support&lt;/h1&gt;
&lt;p&gt;&lt;a href=&quot;/link/77c693a1814446ffb2f76af6babbef08.aspx&quot;&gt;https://world.episerver.com/blogs/remko-jantzen/dates/2020/5/introducing-foundation-spa-react/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/episerver/musicfestival-vue-template&quot;&gt;https://github.com/episerver/musicfestival-vue-template&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;References&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;[1] - &lt;a href=&quot;https://docs.microsoft.com/en-us/dotnet/architecture/microservices/&quot;&gt;https://docs.microsoft.com/en-us/dotnet/architecture/microservices/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;/link/dbbcb8c637ae4dcc80685dd99ca3ae05.aspx&quot;&gt;https://world.episerver.com/blogs/bartosz-sekula/dates/2020/4/content-manager---lightweight-editing-ui/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://customers.microsoft.com/en-gb/story/786162-episerver-partner-professional-services-azure&quot;&gt;https://customers.microsoft.com/en-gb/story/786162-episerver-partner-professional-services-azure&lt;/a&gt;&lt;/p&gt;</id><updated>2020-06-02T13:42:12.0000000Z</updated><summary type="html">Blog post</summary></entry></feed>