In today’s mobile-first world, delivering personalized experiences to visitors using mobile devices is crucial for maximizing engagement and conversions. Optimizely’s powerful experimentation and personalization platform allows you to define custom audience criteria to target mobile users effectively.
By leveraging Optimizely’s audience segmentation, you can create tailored experiences based on factors such as device type, operating system, screen size, and user behavior. Whether you want to optimize mobile UX, test different layouts, or personalize content for Android vs. iOS users, understanding how to define mobile-specific audience criteria can help you drive better results.
In this blog, we’ll explore how to set up simple custom audience criteria for mobile visitors in Optimizely, the key benefits of mobile targeting, and the best practices to enhance user experiences across devices. Let’s dive in!
This solution is based on Example – Create audience criteria, which you can find in the Optimizely documentation.
Create the settings and criterion classes
First, we need to create two classes in our solution:
Class VisitorDeviceTypeCriterionSettings
needs to inherit CriterionModelBase
class, and we need only one property (settings) to determine if the visitor is using a desktop or a mobile device.
public bool IsMobile { get; set; }
The abstract CriterionModelBase
class requires you to implement the Copy()
method. Because you are not using complex reference types, you can implement it by returning a shallow copy as shown (see Create custom audience criteria):
public override ICriterionModel Copy() { return base.ShallowCopy(); }
The entire class will look something like this:
using EPiServer.Data.Dynamic; using EPiServer.Personalization.VisitorGroups; namespace AlloyTest.Personalization.Criteria { [EPiServerDataStore(AutomaticallyRemapStore = true)] public class VisitorDeviceTypeCriterionSettings : CriterionModelBase { public bool IsMobile { get; set; } public override ICriterionModel Copy() { // if this class has reference types that require deep copying, then // that implementation belongs here. Otherwise, you can just rely on // shallow copy from the base class return base.ShallowCopy(); } } }
Now, we need to implement the criterion class VisitorDeviceTypeCriterion
and inherit the abstract CriterionBase
class with the settings class as the type parameter:
public class VisitorDeviceTypeCriterion : CriterionBase<VisitorDeviceTypeCriterionSettings>
Add a VisitorGroupCriterion
attribute to set the category, name, and description of the criterion (for more available VisitorGroupCriterion
properties, see Create custom audience criteria:
[VisitorGroupCriterion( Category = "MyCustom", DisplayName = "Device Type", Description = "Criterion that matches type of the user's device" )]
The abstract CriterionBase
class requires you to implement an IsMatch()
method that determines whether the current user matches this audience criterion. In this case, we need to determine from which device the visitor is accessing our site. Because Optimizely doesn’t provide this out of the box, we need to figure out that part.
One of the solutions is to use information from the request header, from the User-Agent
field and analyze it to determine the OS and device type. We can do that by writing our match method:
public virtual bool MatchBrowserType(string userAgent) { var os = new Regex( @"(android|bb\d+|meego).+mobile|avantgo|bada\/|blackberry|blazer|compal|elaine|fennec|hiptop|iemobile|ip(hone|od|ad)|iris|kindle|lge |maemo|midp|mmp|mobile.+firefox|netfront|opera m(ob|in)i|palm( os)?|phone|p(ixi|re)\/|plucker|pocket|psp|series(4|6)0|symbian|treo|up\.(browser|link)|vodafone|wap|windows ce|xda|xiino", RegexOptions.IgnoreCase | RegexOptions.Multiline); var device = new Regex( @"1207|6310|6590|3gso|4thp|50[1-6]i|770s|802s|a wa|abac|ac(er|oo|s\-)|ai(ko|rn)|al(av|ca|co)|amoi|an(ex|ny|yw)|aptu|ar(ch|go)|as(te|us)|attw|au(di|\-m|r |s )|avan|be(ck|ll|nq)|bi(lb|rd)|bl(ac|az)|br(e|v)w|bumb|bw\-(n|u)|c55\/|capi|ccwa|cdm\-|cell|chtm|cldc|cmd\-|co(mp|nd)|craw|da(it|ll|ng)|dbte|dc\-s|devi|dica|dmob|do(c|p)o|ds(12|\-d)|el(49|ai)|em(l2|ul)|er(ic|k0)|esl8|ez([4-7]0|os|wa|ze)|fetc|fly(\-|_)|g1 u|g560|gene|gf\-5|g\-mo|go(\.w|od)|gr(ad|un)|haie|hcit|hd\-(m|p|t)|hei\-|hi(pt|ta)|hp( i|ip)|hs\-c|ht(c(\-| |_|a|g|p|s|t)|tp)|hu(aw|tc)|i\-(20|go|ma)|i230|iac( |\-|\/)|ibro|idea|ig01|ikom|im1k|inno|ipaq|iris|ja(t|v)a|jbro|jemu|jigs|kddi|keji|kgt( |\/)|klon|kpt |kwc\-|kyo(c|k)|le(no|xi)|lg( g|\/(k|l|u)|50|54|\-[a-w])|libw|lynx|m1\-w|m3ga|m50\/|ma(te|ui|xo)|mc(01|21|ca)|m\-cr|me(rc|ri)|mi(o8|oa|ts)|mmef|mo(01|02|bi|de|do|t(\-| |o|v)|zz)|mt(50|p1|v )|mwbp|mywa|n10[0-2]|n20[2-3]|n30(0|2)|n50(0|2|5)|n7(0(0|1)|10)|ne((c|m)\-|on|tf|wf|wg|wt)|nok(6|i)|nzph|o2im|op(ti|wv)|oran|owg1|p800|pan(a|d|t)|pdxg|pg(13|\-([1-8]|c))|phil|pire|pl(ay|uc)|pn\-2|po(ck|rt|se)|prox|psio|pt\-g|qa\-a|qc(07|12|21|32|60|\-[2-7]|i\-)|qtek|r380|r600|raks|rim9|ro(ve|zo)|s55\/|sa(ge|ma|mm|ms|ny|va)|sc(01|h\-|oo|p\-)|sdk\/|se(c(\-|0|1)|47|mc|nd|ri)|sgh\-|shar|sie(\-|m)|sk\-0|sl(45|id)|sm(al|ar|b3|it|t5)|so(ft|ny)|sp(01|h\-|v\-|v )|sy(01|mb)|t2(18|50)|t6(00|10|18)|ta(gt|lk)|tcl\-|tdg\-|tel(i|m)|tim\-|t\-mo|to(pl|sh)|ts(70|m\-|m3|m5)|tx\-9|up(\.b|g1|si)|utst|v400|v750|veri|vi(rg|te)|vk(40|5[0-3]|\-v)|vm40|voda|vulc|vx(52|53|60|61|70|80|81|83|85|98)|w3c(\-| )|webc|whit|wi(g |nc|nw)|wmlb|wonu|x700|yas\-|your|zeto|zte\-", RegexOptions.IgnoreCase | RegexOptions.Multiline); var deviceInfo = string.Empty; if (os.IsMatch(userAgent)) { deviceInfo = os.Match(userAgent).Groups[0].Value; } if (device.IsMatch(userAgent.Substring(0, 4))) { deviceInfo += device.Match(userAgent).Groups[0].Value; } if (!string.IsNullOrEmpty(deviceInfo)) { return true; } return false; }
Now, we can go back and implement the IsMatch()
method that is required by CriterionBase
abstract class.
public override bool IsMatch(IPrincipal principal, HttpContext httpContext) { return MatchBrowserType(httpContext.Request.Headers["User-Agent"].ToString()); }
Test the criterion
In the CMS we need to create a new audience criterion. When you click on the ‘Add Criteria’ button, there will be ‘MyCustom’ criteria group with our criteria:
When you select the ‘Device Type’ criteria, you will see something like this:
We can easily add a label for the checkbox by using Optimizely’s translation functionality. Create a new XML file VisitorGroupCriterion.xml
and place it in your translations folder where your translation files are, like this:
Put this into the file that you created:
<?xml version="1.0" encoding="utf-8" standalone="yes"?> <languages> <language name="English" id="en-us"> <visitorgroups> <criteria> <ismobile> <key>Is Mobile Device (Use this setting to show content only on Mobile)</key> </ismobile> </criteria> </visitorgroups> </language> </languages>
There is one more thing to do. In VisitorDeviceTypeCriterionSettings.cs,
decorate the IsMobile
property with the translation definition. Add this attribute:
[CriterionPropertyEditor(LabelTranslationKey = "/visitorgroups/criteria/ismobile/key")]
It should look like this:
Now, in the editor view, we have a label for the checkbox.
Personalize the content by setting the content for this visitor group.
Desktop view:
Mobile view:
You can see that there is content that is only visible if you access the site with a mobile device.
And that’s it!
Great article. Definitely useful information.