Personalisation of website content is a theme we are hearing more and more from both our clients and in our project team conversations as we scope out the features for the sites we build at Zone. Whether it be an e-commerce site looking to put the right products in front of customers or a charity looking to lead with the appropriate content for a given user persona, there's regularly a need to go beyond just a single view of content per page.
When we dig into these requirements a little further, it's often the case that the need is something quite particular. For example we recently discussed presenting "pollen counts in your area" for visitors to the website of a charity dedicated to asthma sufferers. That kind of thing will always need custom development and isn't something any content management system (CMS) will provide out of the box.
Often though, the requirement is something that could be provided through a more generic personalisation service - involving the definition of various criteria for grouping visitors and subsequently showing, hiding or otherwise customising particular pieces of content for them. We're finding it a factor in CMS selection decisions for our clients and, as things stand, unfortunately Umbraco currently doesn't bring a great deal to the table for this.
I was lucky enough to attend the recent retreat - a get together of a small number of the Umbraco core team and community members - where this was a topic under discussion. The outcome of which was that this type of feature is now on the Umbraco road-map as was presented for feedback in the key-note at the recent Codegarden conference.
So a little down the track we should see more features for personalisation in the core, which I'll discuss in a little more detail in this article. Firstly though, I wanted to introduce a couple of packages that are available now for supporting this type of requirement.
Personalisation Groups
The first one, called Personalisation groups is one I've put together in recent weeks. It's still fairly early days and hasn't yet had much in the way of production usage that I'm aware, but already offers features that allow for a general way to personalise your website content plus being extensible to meet particular personalisation requirements that a given project may have.
Creating groups for personalisation
To install, you can add the package to your Umbraco installation in the standard way: download from the project page on our.umbraco.org and install via the back-office Developer section.
The package contains a couple of document types and data types that allow you to create group definitions. These definitions are made up of one or more criteria.
Criteria are the features of a given site visitor that you use to identify them for targeting. This might be things about the environment (e.g. the current day or time), their request (e.g. session or cookie values, whether they are logged in or not) or their Umbraco member details (e.g. their type, group or a profile setting).
You then group one or more criteria to create your group definition. So for example you might have a Weekday morning visitors definition that is targeted using the Day of week and Time of day criteria with the appropriate days and time ranges selected.
Targeting content to site visitors
With these group definitions set up you can associate them with your pages. The package provides a simple picker data type that you can add to any document type and thus make it available to your editors. They can pick the group or groups that they want to target a given node to and the node will be considered as matching the visitor if they are determined to be in at least one of the groups.
So we now have the group definitions set up and content associated with them but there's one last step for the developer to complete to make use of this. Within the Razor templates you'll find a new extension method on all instances of IPublishedContent called ShowToVisitor(). Using that you can add the necessary behaviour to your templates to show or hide content based on the details of the current visitor.
How you do that will depending on the particular details of the node structure you have on your site, but the following are a couple of examples of how it can be used.
One simple example, would be to only show certain instances of repeated content that match the current site visitor's profile - which you could do like this:
@foreach (var post in Model.Content.Children.Where(x => x.ShowToVisitor()))
{
<h2><a href="@post.Url">@post.Name</a></h2>
<p>@post.GetPropertyValue<string>("excerpt")</p>
}
With a little more work you can also personalise an individual page. One way to do this would be to create child nodes of a page of a new type called e.g. "Text Page Variation". This document type should contain all the fields common to the parent page that you might want to personalise - e.g. title, body text, image - and an instance of the "Personalisation group picker". You could then implement some logic on the parent page template to pull back the first of the sub-nodes that match the current site visitor. If one is found, you can display the content from that sub-node rather than what's defined for the page. And if not, display the default content for the page. Something like:
@{
var personalisedContent = Model.Content.Children.Where(x => x.ShowToVisitor()).FirstOrDefault();
string title, bodyText;
if (personalisedContent != null)
{
title = personalisedContent.Name;
bodyText = personalisedContent.GetPropertyValue<string>("bodyText");
}
else
{
title = Model.Content.Name;
bodyText = Model.Content.GetPropertyValue<string>("bodyText");
}
}
<h1>@title</h1>
<p>@bodyText</p>
If creating child nodes for the page doesn't appeal - and it's not ideal in many cases as it interferes with your page hierarchy - you could use picked nodes using a multi-node tree picker here, or even an instance of Nested Content. Basically anything that returns a collection of IPublishedContent will work as the extension method applies to that.
How it works
The core of the package is the definition of the personalisation group shown in the screenshots above. This is implemented as a custom Umbraco property editor using angularjs. Each criteria also consists of an angular view and controller, along with an additional service used for translating the internal representation of the group definition to something readable by a content editor.
Importantly though for extensibility as I'll discuss below, on the server-side each criteria implements an interface called IPersonalisationGroupCriteria. As well as some properties to describe the criteria, there's a single method that must be implemented by all criteria with functionality to determine if a particular aspect of the current visitor matches the criteria definition. So for example the "day of week" criteria checks what the current day is to determine a match.
When a Umbraco application using the package starts-up, all assemblies are scanned for classes that implement this interface and they are added as criteria that the editor can select from.
Extending the package
The package itself already comes with a number of criteria, including:
- Authentication status
- Cookie and session key
- Country (via IP matching)
- Day of week and time of day
- Pages viewed
- Referrer
- Umbraco member group, type and profile field
But I wanted to make sure it could be extended to add further criteria without necessarily including them in the package itself.
There are two ways to extend the package to meet any particular requirements you may have. The most simple, but not quite so elegant, means is to make use of one of the two lower-level criteria - the ones for cookie and session value. As the developer of the site you would need to implement some code to set a cookie or session value following a given event on your website, such as perhaps the completion of an order. You can then create a personalisation group that uses one of these criteria with the appropriate key and value settings, that editors can make use of.
The more sophisticated way would be to create your own criteria based on whatever basis you need. You can do this by following the conventions of the built-in ones - implementing the interface and creating the appropriately named angularjs client-side assets. When the application starts and the assemblies are scanned for criteria, your custom one will be picked up.
To summarise
I'm quite sure this package is a long way from the perfect solution to personalisation in Umbraco. It's particular drawbacks are that it's not completely seamless for the editor to use - it still requires the developer to amend the templates to make use of the personalisation features. And as it's targeted at the node level, it's not quite as easy as it could be to have finer personalisation control that you might want to do at a field level. But certainly as a stop-gap whilst we wait for personalisation features in the core, I feel it could be a useful addition to a number of website projects.
To read more about the features and technology behind this package - and of course to view and perhaps contribute to the source - please see the following GitHub page.
Footprint
Another recent effort to plug the gap in this area is a upcoming package called Footprint put together by the developers at Novicell. Recent attendees at Codegarden may have seen their talk where they demonstrated this and if not you can catch up online. With this package installed, via a new section in the the back-office you are able to to combine various properties derived from site visitor behaviour and request details into segments that you will use to group your visitors by and personalise their experience.
There's a nice user interface (UI) for this along with a useful feature that allows you to see how many of your current site visitors match the segment as you are creating it. Thus you can see at a glance the numbers and percentages of people that would fit into the segment and thus see any content that was associated with it.
They've also put together a UI for the content editors that'll look familiar to anyone who has used the Vorto package for multi-lingual websites built by Matt Brailsford. They wrap Umbraco data types with a custom property editor, that from an editor perspective provides a tabbed interface around the standard Umbraco type for the entry of alternate content for each activated segment. In the Umbraco views you can use an extension method the package provides named GetSegmentedValue() in place of the standard GetPropertyValue() to retrieve the segmented content for the current visitor.
Finally there's an API that you can call from your views or custom controllers that allow you to associate values for the current site visitor with any of your properties as they browse around your site. Having done that, they'll then be associated with the appropriate segments that have been defined as well as becoming part of the analytics presented in the back-office.
Behind the scenes as well as the standard Umbraco package elements such as custom property editors and the like, the tool utilises a MongoDB back-end for the storage of definitions and segments and their association with site visitors.
Overall it's a slightly different approach to the way I've come up with but obviously attempting to solve a very similar problem. Certainly on the UI level both for the developers and editors it's a nicer experience and the addition of the analytics information is a valuable addition. They are also able to segment given properties on a content node, which gives tighter control than the Personalisation Groups package offers which is only at the level of the node itself.
To support the analytics feature it would require you to have a dependency on MongoDB for your application though, which might be something that not everyone would want to take on. Some basic footprinting features like segmented content based of query string parameters would be available without the MongoDB setup. But the advanced profiling across multiple sessions needs this persistence mechanism to store the large amounts of session data.
As they make clear in their talk, it's an early stage product but they have clear plans for improving it - from a feature, UI polish and performance perspective. Nonetheless it already looks like it will be a useful option for implementing personalisation features that would repay further investigation once it gets an official release.
Personalisation in the Core
So that's a quick overview of a couple of options that, even if relatively new, are either available now or due shortly for implementation of personalisation features in Umbraco. I suspect though that whilst useful, they may have a limited shelf-life, or at least become less essential, as there are plans to include such features in the core.
Anyone who was at Codegarden in 2014 may remember a demo in the keynote presenting a feature called "segments & variations" (if not, you can still see it here - wind forward to around 70 minutes in). Obviously other priorities took over for the last year or so for core development but it demonstrates that the ideas have been kicking around for a little while. Fortunately though the plans were revived again in this years Codegarden and at the retreat prior, so hopefully they or something similar will see the light in an upcoming Umbraco release.
In the discussions we had at the retreat it was clear that the core ideas are not dissimilar to those presented in the packages above. They would likely take things further though by implementing personalisation at a couple of levels. Firstly at the page level, there would be variants based on language. These would apply to the whole page allowing you to create a variant of that page for a given language. The idea is that this would provide a better and more flexible means than currently available from the core for implementing one-to-one multi-lingual sites (those where mostly every page exists in mostly every language).
On top of that would be the field level variations that could be targeted to user segments. This would likely use a similar property editor wrapping technique and UI as employed by Vorto and Footprint, such that there would be for example a "Segmented Textstring" in addition the standard Textstring. And thus provide finer control over the parts of the page that are customised for the site visitor.
Lastly the feature is intended to be extensible, allowing project and package developers to implement their own personalisation segment criteria via custom providers.
Wrapping Up
In summary, I've discussed here a couple of options for the present for implementation of personalisation features with Umbraco, and had a peek into what might be coming in the not too distant future. As I noted at the start of the article, it's my experience that requirements in this area are becoming more and more requested by website project stakeholders. From the packages discussed and the ideas for implementation in the core, it's clear a number of people in the Umbraco community are recognising this and thinking along similar lines. Hopefully these packages can serve to bridge the gap whilst Umbraco core itself is developed to offer features in this area out of the box.