Google Analytics Tracking and Customization
The new version of the Google Analytics Add-on for EPiServer has some exiting new features that allows you better control over how and what you track with Google Analytics. Also, with the new possibility to install Add-ons through Visual Studio, the install is quick and easy to do, and makes it easy to get started customizing the tracking script.
Installing the Google Analytics Add-on as a Nuget package
Install Google Analytics Add-on as a Nuget package from the EPiServer Nuget feed
install-package EPiServer.GoogleAnalytics
Configure it to connect to your Google Analytics account from Admin Mode:
Select the tracking method that your Google Analytics account supports. Note! Most of the code examples here require Universal Analytics (UA):
If you want to track Ecommerce events, make sure your UA account has Ecommerce tracking turned on in the Google Analytics administration view. If you want to track Enhanced Ecommerce events, also enable “Enhanced Ecommerce Reporting”:
Note! Do not mix Ecommerce and Enhanced Ecommerce tracking on your pages.
Check that the Add-on is installed and working by looking at the source of any of your pages:
You can also install the Google Analytics Debugger extension for Chrome:
https://chrome.google.com/webstore/detail/google-analytics-debugger/jnkmfdileelhofjcijamephohjechhna
It will show debug information in the Chrome console:
More information about troubleshooting Google Analytics: https://developers.google.com/analytics/resources/articles/gaTrackingTroubleshooting
Note! If you plan to customize the tracking, you need to install the add-on through Visual Studio. It will add the necessary reference to the Add-on assembly. You should not add a reference to an assembly installed as an add-on through the Add-on UI as it would break your site if the add-on is uninstalled.
If you have worked with previous versions of the add-on, you’ll now see that the new version has fewer dependencies, which makes for a cleaner install.
Support for Universal Analytics
Google has launched a major update to the Google Analytics offering called Universal Analytics. It is a better tracking script, extensible, easier to use, and most importantly, allows more types of tracking, especially when it comes to Ecommerce.
I recommend reading up on the new possibilities, there are numerous blog posts that shows how and why and can really inspire your imagination. The official documentation is also good reading:
https://developers.google.com/analytics/devguides/collection/analyticsjs/
Unless you have good reasons not too, you should upgrade your site to use Universal Tracking, and use the new script. If you haven’t customized how you track using the previous version of the Add-on, you can install the new one, and change the tracking type:
Make sure you also upgrade your current analytics account in the administration interface for Google Analytics.
Ecommerce Tracking
If the basic page view tracking is not enough, you typically want to extend with more tracking instructions. For an example, if you’re running an EPiServer Commerce site, the new Enhanced Ecommerce tracking that is part of Universal Analytics is a must.
The “old” tracking only allowed tracking purchases, and would show you what products were most popular among people actually buying them. The new Enhanced Ecommerce allow you to track both impressions, detail views, product clicks, adding to the cart, and the whole checkout process, giving you an easy way to see where people fall off.
With all this information about product views, lists, clicks etc. you’ll get a whole new view of how your site is actually performing.
Note! The Add-on will help you add this tracking, but it wont do it for you. As every site is different, it would be hard to add this tracking automatically. Don’t worry, I’ll show you how.
Tracking Basics
The online documentation for the Google Analytics Add-on explains how the add-on works pretty well, so I will not repeat that here. I recommend you browse through that documentation if you have trouble following what I do in the code below.
If you want to add more script lines to the tracking script before the pageview is sent off to Google, you need to work with AnalyticsInteraction classes. This is done through extensions to HttpContext and HttpContextBase (for MVC).
Web Forms:
Page.Context.AddAnalyticsEvent("button", "click", "nav buttons", 4, clearWhenContextChanged: true);
MVC Controller:
ControllerContext.HttpContext.AddAnalyticsEvent("button", "click", "nav buttons", 4, clearWhenContextChanged: true);
The heavy lifting is done in one of the classes inheriting from GASyntax, like the UniversalSyntax class which is responsible for retrieving all registered AnalyticsInteraction objects for a request and render them correctly.
This is also the class you need to change if you want to take full control over the script rendering.
Creating Your Own Syntax Implementation
The Commerce Starter Kit has quite a lot of customized tracking, and has it’s own syntax class. We register it with the service locator like this:
[InitializableModule]
[ModuleDependency(typeof(EPiServer.Web.InitializationModule))]
public class InitializeAnalytics : IConfigurableModule
{
public void Initialize(InitializationEngine context)
{
}
public void Preload(string[] parameters) { }
public void ConfigureContainer(ServiceConfigurationContext context)
{
// Our own syntax implementation
context.Container.Configure(c => c.For<UniversalSyntax>().Use<UniversalSyntaxEx>());
}
public void Uninitialize(InitializationEngine context)
{
}
}
Our enhanced UniversalSyntaxEx looks like this:
public class UniversalSyntaxEx : UniversalSyntax
{
// standard script
protected string _gaScript = "(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){\r\n(i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),\r\nm=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)\r\n})(window,document,'script','//www.google-analytics.com/analytics.js','ga');";
public override string BuildTrackingScript(ScriptBuilderContext appenderContext, SiteTrackerSettings siteSettings,
out bool requiresScriptReference)
{
requiresScriptReference = false;
if (siteSettings == null)
{
return null;
}
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("/* Begin GA Script */");
stringBuilder.AppendLine(_gaScript);
stringBuilder.AppendLine(string.Format("ga('create', '{0}', 'auto');", siteSettings.TrackingId));
stringBuilder.AppendLine("// Extended Tracking");
stringBuilder.AppendLine(AppendExtendedTracking(siteSettings, ref requiresScriptReference));
stringBuilder.AppendLine("// Plugin Script");
stringBuilder.AppendLine(this.GetPluginScript());
if (siteSettings.TrackAuthors && !string.IsNullOrEmpty(appenderContext.Author))
{
stringBuilder.AppendLine("// Custom Author Tracking");
stringBuilder.AppendLine(this.GetCustomDimension("Author", CustomVariables.AuthorVariable, appenderContext.Author));
}
ContentReference contentReference = new ContentReference(appenderContext.PageId);
ICollection<AnalyticsInteraction> interactions = EPiServer.GoogleAnalytics.Helpers.Extensions.GetInteractions(appenderContext.InteractionStore);
// This is where the interesting stuff happens
// All custom interactions are added here
stringBuilder.AppendLine("// Begin Interactions");
foreach (AnalyticsInteraction interaction in interactions)
{
// Skip any interactions that are tied to a specific page
if (ContentReference.IsNullOrEmpty(interaction.ContentLink) == false &&
contentReference.Equals(interaction.ContentLink) == false)
{
continue;
}
stringBuilder.AppendLine(interaction.GetUAScript());
}
stringBuilder.AppendLine("// End Interactions");
// Clear any interactions that should not persist
// across a request
this.ClearRedundantInteractions(interactions);
stringBuilder.AppendLine("ga('send', 'pageview');");
stringBuilder.AppendLine("/* End GA Script */");
return stringBuilder.ToString();
}
protected string AppendExtendedTracking(SiteTrackerSettings siteSettings, ref bool requiresScriptReference)
{
Dictionary<string, object> extendedTracking = this.GetExtendedTracking(siteSettings);
requiresScriptReference = extendedTracking.Count > 0;
return this.SerializeTrackerSettings(extendedTracking, siteSettings.TrackingScriptOption.ToString());
}
private string GetCustomDimension(string dimensionName, string dimensionIndex, string value)
{
return string.Format("ga('set', '{0}{1}', '{2}');", dimensionName, dimensionIndex, value);
}
}
This class will render the script, any plugin, the interactions and then send it off to Google.
Personally, I find that adding AnalyticsInteraction objects using the standard exension methods is a bit tedious. I’d rather have full control over the script instead of using the dictionary, so I created my own AnalyticsInteraction variation:
public class UniversalAnalyticsInteraction : AnalyticsInteraction
{
// We're not using these, but we need the InteractionKey to be unique
// Note! We always mark this for deletion after is has been rendered
// to the page.
public UniversalAnalyticsInteraction() :
base("overridden-interaction", true, Guid.NewGuid().ToString())
{
}
public UniversalAnalyticsInteraction(string script)
: base("overridden-interaction", true, Guid.NewGuid().ToString())
{
Script = script;
}
/// <summary>
/// The javascript to add to the tracking script
/// </summary>
/// <remarks>
/// The javascript must be complete and valid, or it might break
/// the whole analytics tracking feature.
/// </remarks>
public string Script { get; set; }
public override string GetUAScript()
{
return Script;
}
}
If you know how the script should look like, you can use this one, and just set the script directly. You can add it like this:
protected void AddInteraction(HttpContextBase context, string script)
{
var interactions = EPiServer.GoogleAnalytics.Helpers.Extensions.GetInteractions(context);
UniversalAnalyticsInteraction interaction = new UniversalAnalyticsInteraction(script);
interactions.Add(interaction);
}
If we look at the example from the Google Analytics documentation for measuring a product detail view, it could look like this (from a product detail MVC controller):
HttpContextBase context = ControllerContext.HttpContext;
// The plugin is required for tracking enhanced ecommerce
AddInteraction(context, "ga('require', 'ec');"));
// This would come from your commerce product
AddInteraction(context, "ga('ec:addProduct', {'id': 'P12345', 'name': 'Android Warhol T-Shirt', 'category': 'Apparel', 'brand': 'Google', 'variant': 'black'});"));
// This ties the product to the detail action
AddInteraction(context, "ga('ec:setAction', 'detail');");
Note! Since the add-on will end the script with a "send pageview" method, you do not need to include that yourself.
If you plan to use Enhanced Ecommerce actions on most pages on your site, moving the ga('require', 'ec'); script to your own IPluginScript class is a good idea. Add this to your IInitializableModule:
// Add enhanced ecommerce to all pages
context.Container.Configure(c => c.For<IPluginScript>().Use<RequireEnhancedCommercePlugin>());
This is how the RequireEnhancedCommercePlugin look like in the Commerce Starter Kit:
public class RequireEnhancedCommercePlugin : IPluginScript
{
public string GetScript()
{
ICurrentMarket currentMarket = ServiceLocator.Current.GetInstance<ICurrentMarket>();
IMarket market = currentMarket.GetCurrentMarket();
string script = "ga('require', 'ec');\n";
script = script + string.Format("ga('set', '&cu', '{0}');", market.DefaultCurrency);
return script;
}
}
It adds a require statement for the ec plugin. Since the starter kit supports multiple markets it also registers the current currency so any prices or conversions will be tracked correctly in Google Analytics.
Enhanced Ecommerce Helper Library
Getting all the script valid can be a bit cumbersome, there are different field objects for different actions, and some fields are mandatory, others not. To help you out I've create a small helper project to make this easier. You can find it on Github: https://github.com/EPiServerNorway/UniversalTrackingHelper
Adding a require statement for the ec plugin would be done like this with the helper library:
using EPiCode.GoogleAnalyticsTracking;
...
Tracking tracking = new Tracking();
// Get the script
string script = tracking.Require("ec");
// Add it as an interaction (as shown earlier)
AddInteraction(context, script);
See the GoogleAnalyticsTracking class in the Commerce Starter Kit for more examples on how to use the helper library.
Session State storage for AnalyticsInteractions
The analytics interactions are by default stored in Session state, and you can - in theory - add an interaction that spans page requests. I would advise against it as is hard to predict the order of the interactions.
IPluginScript supports only one registration
It is important to be aware that only on IPluginScript should be registered at any one time. Only one will be used, and if you have several registered classes with a ServiceConfiguration attribute, which one is selected cannot be predicted. Make sure you register your own through an IInitializableModule.
Implementation of Google Analytics Tracking in the Commerce Starter Kit
The Commerce Starter Kit uses Enhanced Ecommerce tracking, and the current implementation contains:
- Tracking regular page views
- Tracking the product detail view
- Tracking product impressions from the Configurable Wine Search List
- Reviewing the cart (with products)
- Checkout page (with products)
- Payment page (with products)
- Receipt page with purchase command tracking order total and more
Still remaining:
- Add to cart command (in lists and details view)
- Related products (impressions) on product detail page
- Returns (from Commerce Manager)
- Category view (list pages)
- Click product link
- Add payment method as a checkout option
Interesting Analytics Data
When you start tracking ecommerce, you'll quickly see that you're getting a lot of useful data to base your decisions on. Here are some simple examples:
Checkout Funnel
See Checkout funnel for device categories to find out if your checkout works across devices
Example: if smartphones are not able to purchase due to an error or incompatible payment provider you should see a high abandonment rate on the Checkout Behaviour:
Product List Performance
The start page is important, do you get click-through on all products on the start page, or should you change some of them for something else?
Are people just browsing and not adding anything to the cart? Compare timespans with and without campaigns with discounts, are your customers motivated by price. Is your Cart-to-Detail rate low? How good is the content on your detail pages? Are people seeing what they need in order convert?
Remember, statistics can be misleading, this also applies to your tracking, and if you've got a bug in your tracking code you could be looking at some really strange results. Question your data.
When you have started tracking, you should also think about defining goals and actions in order to meet your goals, and then see how this all ties together. Are your customers behaving the way you think they are on your site? Maybe you need to change how you work, present product information, run campaigns, discount products etc.
And then see conversion rate increase. All with the new Google Analytics add-on for EPiServer. Happy tracking!
Great blog Steve!
Thank you Steve, you really make the GA addon shine with this blog post!
Thx Steve! I can't seem to install google analytics due to GA nuget package that requires older version of EPiServer.Framework.
Updating 'EPiServer.Framework 7.15.0' to 'EPiServer.Framework 7.13.2' failed. Unable to find a version of
'EPiServer.Packaging' that is compatible with 'EPiServer.Framework 7.13.2'.
Do you have any info on when a new one will be out or perhaps this is a bug in the GA, why does it not work with newer versions, shouldn't it be built for the lowest it works on, but still work on the new ones?
Here, it's written that it requires >7.5 and < =8 http://nuget.episerver.com/en/OtherPages/Package/?packageId=EPiServer.GoogleAnalytics
Just a heads up: If tracking is done with Universal Analytics through a Google Tag Manager container most code in this post won't work.
It's still pretty easy to get the Enhanced E-com Tracking working though but you need to build and push the JSON according to your Tag Manager setup instead of calling ga().
Another thing... Is the plugin (still) connecting to GA's API and using that data for something?
Thanks Johan, good point. You still need to render your data layer, and this small lib can help with that: https://github.com/EPiServerNorway/UniversalTrackingHelper
The gadgets (dashboard and page) connects to the GA API (though the need for the Google C# libs is gone).
OK, thanks for the info! Also I put up a blog post on strategies when using GTM: http://krompaco.nu/2015/03/google-analytics-enhanced-ecommerce-features-with-tag-manager/