Sanjay Kumar
Mar 30, 2020
  2953
(3 votes)

Episerver A/B testing and visitor group (personalization) metadata into an analytics payload for consumption with the Google Analytics

The purpose of this blog post is to retrieve the real-time A/B testing and visitor group (personalization) details and feed into the Google Analytics for tracking real-time content item progress on your website.

A/B TESTING

A/B Testing is the variations of content items and that compares which variation performs best. When A/B testing running then majors number the conversions for the A and B version, one the gets the best result then wins.

Episerver CMS and Episerver Commerce each have own three conversion goals and developer can define custom conversion goals using KPI interface. A/B testing is distributed as free AddOn which you can download from NuGet but you need to add http://nuget.episerver.com/feed/packages.svc/ in Nuget package manager before download. The name of NuGet package that installs under the ~/module folder is EPiServer.Marketing.Testing after installation you need to update Episerver database schema.

Episerver CMS Conversions Goals:

  1. Landing page: The goal for the visitor to navigate the specify page and only click is counted as a conversion.
  2. Site Stickiness: The A/B test counts a conversion if a visitor goes from the target page to any other page on the site during the set time period (1-60 minutes).
  3. Time on Page: Visitors spend some time on the page for specifying numbers second.

Episerver Commerce Conversions Goals:

  1. Add to cart: Create a visitor group for the specific product and then the visitor adds that product to a cart, it is counted as a conversion.
  2. Purchase product: If a site visitor buys the added products on the cart, then it is counted as a conversion.
  3. Average order: The conversion goal to track completed orders on each of the test pages. The conversion goal totals up the values of all Episerver Commerce carts created by visitors included in the A/B test. The test determines which page variant creates the highest average value for all those carts when picking a winner. If a visitor creates multiple carts, all the (purchased) carts are included in the total, which means that the visitor can “convert” many times in the test duration. On Episerver Commerce websites using different currencies, the test converts all carts to the same currency.

Note:

  • Developers can create own custom conversions which known as KPI (Key performance indicator)
  • For the Commerce-related conversion goals, you required Episerver Commerce and then you can create commerce-related visitor groups criteria for personalization

PERSONALIZATION

Personalization in Episerver target the website content to selected visitor groups. The personalization feature is based on customized visitor groups that you create based on a set of personalization criteria. Episerver provides two types of criteria one for CMS and another for commerce.

List of CMS and Commerce visitor group criteria, you can see the difference in both.

Let's create visitor groups (personalization) for the CMS and Commerce following the below steps.

Episerver CMS visitor group

  • Go to visitor group area and click to create button
  • Tap on Time and Place criteria options and drag `Time on Site` from the right section in `Drop new creation here` in the left section.
  • Enter specific time in seconds e.g. 10
  • Enter the visitor group name e.g. Time On-Site Visitor Group
  • Click to Save.

Episerver Commerce visitor group

  • Go to visitor group area and click to create button
  • Tap on Commerce criteria options and `Product in Cart or Wish List` from the right section in `Drop new creation here` in the left section.
  • Enter the specific product codes. e.g. 123456
  • Enter visitor group name e.g. Add to cart visitor group
  • Click to Save.

The below screenshot is an example of the cart page AB testing where you can see CMS and Commerce related conversion goals with personalization.

CODE

Using the below code you can retrieve the real-time A/B testing and visitor group (personalization) details. I have divided the code into four main part. 

  • View Model
  • Factory or Service
  • Controller
  • Assign the payload result into Google Analytics
View Model

Create two view models with the name AnalyticsViewModel and VisitorGroupViewModel.

The AnalyticsViewModel view model is the payload response view model that returns the real-time A/B testing and personalization details into the response of payload.

public class AnalyticsViewModel 
{

     public bool AbTestRunning { get; set; }

     public string AbTestId { get; set; }

     public string AbTestVariant { get; set; }

     public bool PersonalizationRunning { get; set; }

     public string PersonalizationId { get; set; }

     public string PersonalizationType { get; set; }

}

The VisitorGroupViewModel view model that helps to get the visitor group details into the created factory class.

public class VisitorGroupViewModel
{
public string Id { get; set; }

public string Name { get; set; }
}
Factory or Service

Create a factory class with name AnalyticsViewModelFactory within this factory you need to inject the following dependency that I listed below which helps to get visitor group (personalization) and A/B testing variation details for the current session and feed into the payload response.

  • IVisitorGroupRepository
  • IVisitorGroupRoleRepository
  • ITestManager
public class AnalyticsViewModelFactory
{
private readonly IVisitorGroupRepository _visitorGroupRepository;
private readonly IVisitorGroupRoleRepository _visitorGroupRoleRepository;
private readonly ITestManager _testManager;

public AnalyticsViewModelFactory(
IVisitorGroupRepository visitorGroupRepository,
IVisitorGroupRoleRepository visitorGroupRoleRepository,
ITestManager testManager)
{
_visitorGroupRepository = visitorGroupRepository ?? throw new ArgumentNullException(nameof(visitorGroupRepository));
_visitorGroupRoleRepository = visitorGroupRoleRepository ?? throw new ArgumentNullException(nameof(visitorGroupRoleRepository));
_testManager = testManager ?? throw new ArgumentNullException(nameof(testManager));
}

public AnalyticsViewModel Create(HttpContextBase httpContext)
{
var visitorGroups = this.GetVisitorGroupsByCurrentUser(httpContext);
var visitorIds = visitorGroups?.Select(x => x.Id).ToList();
var visitorNames = visitorGroups?.Select(x => x.Name).ToList();

var activeTests = _testManager?.GetActiveTests();
var variantNames = activeTests?.Select(x => x.Title).ToList();
var testIds = activeTests?.Select(x => x?.Id.ToString()).ToList();

return new AnalyticsViewModel
{
AbTestRunning = activeTests?.Count > decimal.Zero,
AbTestId = string.Join(",", testIds ?? new List<string>()),
AbTestVariant = string.Join(",", variantNames ?? new List<string>()),
PersonalizationRunning = visitorIds?.Count > decimal.Zero,
PersonalizationId = string.Join(",", visitorIds ?? new List<string>()),
PersonalizationType = string.Join(",", visitorNames ?? new List<string>())
};
}

private List<VisitorGroupViewModel> GetVisitorGroupsByCurrentUser(HttpContextBase httpContext)
{
var visitorGroupList = new List<VisitorGroupViewModel>();
var user = httpContext.User;
var visitorGroups = _visitorGroupRepository.List();

foreach (var visitorGroup in visitorGroups)
{
if (_visitorGroupRoleRepository.TryGetRole(visitorGroup.Name, out var virtualRoleObject))
{
if (virtualRoleObject.IsMatch(user, httpContext))
{
var viewModel = new VisitorGroupViewModel
{
Id = visitorGroup.Id.ToString(),
Name = visitorGroup.Name
};

visitorGroupList.Add(viewModel);
}
}
}

return visitorGroupList;
}
}
Controller

Create an endpoint v1/google/analytics using a controller with the name of AnalyticsController where you will inject the factory/service to load the data into the payload.

  [RoutePrefix("v1/google/analytics")]
  public class AnalyticsController : Controller
  {
        private readonly AnalyticsViewModelFactory _analyticsViewModelFactory;
        public AnalyticsController(AnalyticsViewModelFactory analyticsViewModelFactory)
        {
            _analyticsViewModelFactory = analyticsViewModelFactory ?? throw new ArgumentNullException(nameof(analyticsViewModelFactory));
        }

        [HttpGet]
        public JsonResult GetAnalytics()
        {
            return this.JsonNet(_analyticsViewModelFactory.Create(this.HttpContext));
        }
  }
Assign the payload result into Google Analytics

When you will hit the v1/google/analytics endpoint then you get a result similar like below and then pass into the Google Analytics script datalayer properties.

{
"abTestRunning": true,
"abTestId": "a0a77ae9-31ec-4d74-8952-32a082535bb1,29de7423-f6ba-4212-a913-34e0517ffda3",
"abTestVariant": "Cart A/B Test, AboutUs A/B Test",
"personalizationRunning": true,
"personalizationId": "adb342d2-8ebb-4430-a305-e403c549452a",
"personalizationType": "Time On Site Visitor Group"
}

Thanks for visiting my blog!

Mar 30, 2020

Comments

Please login to comment.
Latest blogs
Copy Optimizely SaaS CMS Settings to ENV Format Via Bookmarklet

Do you work with multiple Optimizely SaaS CMS instances? Use a bookmarklet to automatically copy them to your clipboard, ready to paste into your e...

Daniel Isaacs | Dec 22, 2024 | Syndicated blog

Increase timeout for long running SQL queries using SQL addon

Learn how to increase the timeout for long running SQL queries using the SQL addon.

Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

Overriding the help text for the Name property in Optimizely CMS

I recently received a question about how to override the Help text for the built-in Name property in Optimizely CMS, so I decided to document my...

Tomas Hensrud Gulla | Dec 20, 2024 | Syndicated blog

Resize Images on the Fly with Optimizely DXP's New CDN Feature

With the latest release, you can now resize images on demand using the Content Delivery Network (CDN). This means no more storing multiple versions...

Satata Satez | Dec 19, 2024