This is the second in a series of posts that look at some potential ways that the Optimizely and Episerver products can be integrated. In this post we will be updating the code that was created in the first article to include a Full Stack A/B test to determine if an increase in price would affect the number of items added to the cart.
Here are the links to all of the posts in this series (please check back as new articles will be added):
- Part 1 – Full Stack Feature
- Part 2 – Full Stack A/B Test (Current Article)
- Part 3 – Web A/B Test – Coming Soon
- Part 4 – Personalization Campaign – Coming Soon
Setting Up the A/B Test
The first task is to create a Full Stack A/B test in Optimizely. From the Full stack experiments dashboard click on the Create New button and then select A/B Test.
Just like the Feature, this bring up a wizard that will allow the author to define each part of the test. First you provide an experiment name, key, and description.
The next step is to create the variations that the developer will be implementing for the A/B test. This step also provides the basic wrapper code for you to implementing your A/B test in the language of your choice.
The third, and final step, is to create an event (or select an existing event) to track the success of the test.
Selecting the Create New Event takes the author to a new page where an event key can be created to track the success of the event. The back end code to track the event is also provided to the user.
The event that was created will then need to be tied to a metric captured in the experiment.
The last part of the A/B test setup is to set the traffic allocation for the experiment. For the sake of simplicity, we will display this A/B test to everyone.
Adding the Code
Now that our A/B test has been defined in Optimizely, we will need to update the back end code to utilize the test. In part one of this series we updated the ProductVariantListViewModel to include an Optimzely feature flag. This method will be extended further to to provide a method for displaying the price based on the experiment variant. The addition of our DisplayPrice method does this work for us.
In this simple example we will be increasing the price for any user that is mapped to variation 1 by 10%. If the user is mapped to variation B then they will receive a 20% price increase. (
public class ProductVariantListViewModel
{
private Optimizely _optimizely;
private string _userId;
private UserAttributes _userAttributes;
public ProductVariantListViewModel()
{
var configManager = new HttpProjectConfigManager
.Builder()
.WithSdkKey(ConfigurationManager.AppSettings["Optimizely.SdkKey"])
.Build(false); // sync mode
_optimizely = OptimizelyFactory.NewDefaultInstance(configManager);
_userId = UserHelpers.GetUserId();
_userAttributes = new UserAttributes
{
{"browserType", HttpContext.Current.Request.Browser.Type }
};
}
public List<ProductVariantBlock> ProductVariants { get; set; }
public Variation Variation
{
get
{
return _optimizely.Activate("price_increase", _userId);
}
}
public double DisplayPrice(double originalPrice)
{
var variation = _optimizely.Activate("price_increase", _userId);
if (variation != null)
{
if (variation.Key == "variation_1")
{
return originalPrice * 1.1;
}
else if (variation.Key == "variation_2")
{
return originalPrice * 1.2;
}
}
return originalPrice;
}
public bool FeatureEnabled
{
get
{
return _optimizely.IsFeatureEnabled("display_buy_button", _userId, _userAttributes);
}
}
public string ButtonColor
{
get
{
return _optimizely.GetFeatureVariableString("display_buy_button", "button_color", _userId, _userAttributes);
}
}
public string ButtonFontColor
{
get
{
return _optimizely.GetFeatureVariableString("display_buy_button", "button_font_color", _userId, _userAttributes);
}
}
public string ButtonText
{
get
{
return _optimizely.GetFeatureVariableString("display_buy_button", "button_text", _userId, _userAttributes);
}
}
}
Since the user is tied to a piece of unique data, as defined in the first post, they will receive the same variation for each visit.
The following snippet shows the display price method being used in the razor view to display the price on the product detail page for each product variant.
@for (var i = 1; i <= variants.ProductVariants.Count; i++)
{
var id = string.Format("tab-price{0}", i);
var style = i == 1 ? "active show" : string.Empty;
var variant = variants.ProductVariants[i - 1];
<div class="tab-pane fade score-tab-panel @style" data-anchorable="True" data-ux-state="loaded" id="@id">
<div class="bj-variant-price" style="display:flex" @Html.EditAttributes(x => variant.Price)>
<div>
@variants.DisplayPrice(variant.Price).ToString("C2")
</div>
@if (variants.FeatureEnabled)
{
<div style="padding-top: 10px; padding-left: 70px;">
<a class="score-button product-add"
title="@variants.ButtonText"
style="background-color: @variants.ButtonColor; color: @variants.ButtonFontColor"
data-product-id="@variant.Id">
@Html.Raw(variants.ButtonText)
</a>
</div>
}
</div>
<div class="bj-variant-picker-content bj-image-thumbnails-@i" style="display: none;">
@Html.DisplayFor(x => variant.Image)
</div>
</div>
}
The final step is to capture the event. The Add to Cart button has been wired up to post information back to a service to add the variant to the product cart. Inside this service we simply call the Track method passing the event key and the user id.
var configManager = new HttpProjectConfigManager
.Builder()
.WithSdkKey(ConfigurationManager.AppSettings["Optimizely.SdkKey"])
.Build(false); // sync mode
var optimizely = OptimizelyFactory.NewDefaultInstance(configManager);
var userId = UserHelpers.GetUserId();
optimizely.Track("item_added_to_cart", userId);
The A/B test is all wired up and ready to go.
Happy experimenting!!
1 Comment