Giuliano Dore
May 11, 2021
(7 votes)

How to integrate Optimizely Feature Rollout with EPiServer

I have been writing a number of posts about agency clients and use-cases for agencies pain points here on EPiServer World and on other blogging platforms in the past. I also had the chance to work for startups and product companies and I could notice that the process for feature delivery is sometimes a bit different.  

Product companies tend to focus on a small number of products and a large number of deployments for features, micro-features and components. One requirement that is listed is that It must be possible to release specific features for specific targets like markets, user groups or audiences without “corrupting” the integrity of the project.

As an example, social networks with a few billion users in hundreds of countries are regularly publishing different features for different countries with full control over the delivery and no downtime.

I have had the opportunity to play with Optimizely during my free time, and I was very pleased with the capabilities of their latest ‘Feature Rollout’ release.

One of the perks regarding feature rollout is that it helps avoiding messy rollbacks and hotfixes as it is possible to use feature flags to roll out features to users with an option to roll back if needed to reduce the risk using a convenient interface.

Technical limitations

Let’s get back into EPiServer for a second. We have a wonderful system with flags that can be controlled in a separate backoffice. However, due to the nature of c# and the ‘code first’ approach in EPiServer regarding data models, there are items that we cannot ‘roll out’, I listed a few of them:

  • Page & Block types
  • Product types in EPiServer Commerce
  • Selection factories & rules about allowed content
  • New Scheduled jobs

The main reason regarding this limitation is that the flag coming from Optimizely is a Boolean and it is not possible to set wrap ‘if’ statements around classes or attributes.

The default behaviour in EPiServer regarding components like Scheduled Jobs is that they become available once the class is included in the dll.

While we can’t ship pages or blocks as Optimizely “features”; we still have a wide range of opportunities to use feature rollout:

We can use the flag to hide / show new features in a page like new sections of a page:

       var optimizelyClient = OptimizelySDK.OptimizelyFactory.NewDefaultInstance(System.Configuration.ConfigurationManager.AppSettings["Optimizely:sdkKey"]);

       //testing for all clients
       var user = optimizelyClient.CreateUserContext("");

       //feature flag
       var decision = user.Decide("enable_messenger_chat");

       var enableMessengerChat = decision.Enabled;
@if (enableMessengerChat)
         <div>new feature here</div>

We can also use the flag at the page controller level to “disable” pages and blocks from being rendered until the Optimizely feature is marked as enabled:

public class NewFeaturePageController : PageController<NewFeaturePage>
        public ActionResult Index(NewFeaturePage currentPage)
              var optimizelyClient = OptimizelySDK.OptimizelyFactory.NewDefaultInstance(System.Configuration.ConfigurationManager.AppSettings["Optimizely:sdkKey"]);

              var user = optimizelyClient.CreateUserContext("");

              var decision = user.Decide("enable_new_feature");

              var isEnabled = decision.Enabled;
                   return View(currentPage);
                   throw new NotImplementedException();

With this code, even if the page is deployed, users - like the content team - will not be able to see the page until the feature is enabled in Optimizely.

Update: there is a way to "hijack" the creation of pages, blocks and other episerver components using Initialization modules and the right service, solving the "we can't wrap a boolean around a class or an attribute" issue. However this is a lot more advanced and I chose to cover examples that are available using the standard online training classes.


I created a test project in github to review the capabilities of Feature Rollout, the code is available here: - it's an example of a feature (enabling facebook messenger web plugin) using Optimizely Rollout Feature. Most of the code is inside the master layout as I wanted the plugin to be available for all the pages in the web project. The code below shows how to integrate the FB Messenger chat web plugin using Feature Rollout and a variable for the page id:

    Layout = "~/Views/Shared/_Layout.cshtml";

    //setting up Optimizely;
    var optimizelyClient = OptimizelySDK.OptimizelyFactory.NewDefaultInstance(System.Configuration.ConfigurationManager.AppSettings["Optimizely:sdkKey"]);

    var user = optimizelyClient.CreateUserContext("");

    //feature flag
    var decision = user.Decide("enable_messenger_chat");
    var enableMessengerChat = decision.Enabled;

    //retrieving the page id
    var pageId = decision.Variables.GetValue<string>("page_id");

@if (enableMessengerChat & !string.IsNullOrWhiteSpace(pageId))
    <!-- Messenger Chat Plugin Code -->
    <div id="fb-root"></div>
        window.fbAsyncInit = function() {
            xfbml            : true,
            version          : 'v10.0'
        (function(d, s, id) {
          var js, fjs = d.getElementsByTagName(s)[0];
          if (d.getElementById(id)) return;
          js = d.createElement(s); = id;
          js.src = '';
          fjs.parentNode.insertBefore(js, fjs);
        }(document, 'script', 'facebook-jssdk'));

    <!-- Your Chat Plugin code -->
    <div class="fb-customerchat"

Do you have ideas about integrations between Optimizely and EPiServer CMS ? Leave a comment below 😊

May 11, 2021


Paul Gruffydd
Paul Gruffydd May 11, 2021 12:18 PM

Nice. I do like the capabilities of rollouts, particularly for progressive or targetted rollout rather than just switching a feature on or off for everyone.

Interestingly, the topic of dynamically showing/hiding content types that you mention as a limitation came up in conversation with one of my colleagues yesterday and it's certainly possible, you just need to know where to look. I wrote a post on feature switching per language a while back which shows how it can be done:

I suspect the other limitations could be worked around too if you wanted to though I've never tried it.

Giuliano Dore
Giuliano Dore May 11, 2021 01:52 PM

Thank you for your comment Paul 😊 It's an excellent suggestion & article. I added a note about the possibility to "hijack" some of the components that I listed as part of the limitations paragraph. I wanted to keep this article at a level where new developers would be comfortable trying it.

Please login to comment.
Latest blogs
Optimizely finally releases new and improved list properties!

For years, the Generic PropertyList has been widely used, despite it being unsupported. Today a better option is released!

Tomas Hensrud Gulla | Mar 28, 2023 | Syndicated blog

Official List property support

Introduction Until now users were able to store list properties in three ways: Store simple types (int, string, DateTime, double) as native...

Bartosz Sekula | Mar 28, 2023

New dashboard implemented in CMS UI 12.18.0

As part of the CMS UI 12.18.0 release , a new dashboard has been added as a ‘one stop shop’ to enable editors to access all of their content items,...

Matthew Slim | Mar 28, 2023

How to Merge Anonymous Carts When a Customer Logs In with Optimizely Commerce 14

In e-commerce, it is common for users to browse a site anonymously, adding items to their cart without creating an account. Later, when the user...

Francisco Quintanilla | Mar 27, 2023

How to Write an xUnit Test to Verify Unique Content Type Guids in Content Management

When developing an Optimizely CMS solution, it is important to ensure that each content type has a unique GUID. If two or more content types share...

Minesh Shah (Netcel) | Mar 27, 2023

Extend TinyMCE in Optimizely CMS 12

Since technologies are upgraded to newer versions the ways to extend or override the out-of-the-box functionality are also changed a little bit so...

Ravindra S. Rathore | Mar 27, 2023 | Syndicated blog