Sitecore personalization enables you to give your audiences a better experience on your website by delivering them tailored and targeted content. Personalized content can be shown to your audiences based on their browsing history on your website and values such as their age, the date, or their location.

In this post, we’ll show you how you can get information about personalized components from Sitecore and pass it to Google Tag Manager (GTM) with back-end code so you can track the information with Google Analytics.

Before we jump to the back-end implementation, we’ll look at our detailed requirements for how to successfully accomplish this task.

We need to be able to track the number of users that were exposed to a Sitecore personalized component, which component it was, and the name of the personalization that was seen.

To track impressions, data will need to be surfaced in the datalayer for GTM to see it. We can then configure event tracking in GTM that fires based on custom events pushed to the datalayer when users see Sitecore personalized components.

To make this process easier to understand, we’ll break these items down into two main categories. The first one is what we need to know from Sitecore and the second one is what we need to report in Google Analytics.

Within Sitecore, we will need to identify personalized presentation and so it can be tracked:

  • We will need to know which component was personalized.
  • We will need to know the name of the personalization condition.
  • We will need to know the Sitecore item path of the presentation when the presentation (rendering) is personalized.
  • We will need to know the Sitecore item path of the content used when the content is personalized.
  • We will need to know both pieces of information when both the presentation and content are personalized.
     

In Google Analytics, we would like to report on the following:

  • Number of users exposed to personalized components - including the component names,
  • Number of users that clicked on personalized components - including the component names,
  • What pages the personalized components were on when they were viewed or clicked,
  • Session-based metrics (such as goal conversions) to compare between users who received specific personalizations and those who did not.


To understand the code better, we also should understand the definition of the personalization component and the matching fields on GTM side.

This is the script that should be used to pass data to GTM:

window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'Event' : 'Personalized Component Impression',
'Personalized Component' : '{{Component Name}}',
'Personalization Condition' : '{{Condition Name}}',
'Personalization Content' : '{{Personalization Content}}',
'Personalization Rendering' : '{{Personalization Rendering}}',
 'Personalization State' : '{{Personalization State}}'
});

Component Name would be a variable that pulls through the name of the Sitecore component that's personalized. (view #4 in images below)

Condition Name would be a variable that pulls through the name of the Sitecore condition used to personalize the component. (view #1 in images below)

Personalization Content would be a variable that pulls through the Sitecore item path of personalized content from Sitecore if the content has been personalized. (view #3 in images below)

Personalization Rendering would pull through the Sitecore item path of the component’s rendering from Sitecore if the rendering is personalized. (view #2 in images below)

Personalization State would pull through the state(show/hide) of the personalization rule.

If just the content has been personalized to show Personalization Content, and if just the rendering is personalized show Personalization Rendering, and both are personalized, show the value of both variables.

Component Name would be a variable that pulls through the name of the Sitecore component that's personalized. (#4) Condition Name would be a variable that pulls through the name of the Sitecore condition used to personalize the component. (#1)

Component Name would be a variable that pulls through the name of the Sitecore component that's personalized. (#4) Condition Name would be a variable that pulls through the name of the Sitecore condition used to personalize the component. (#1)

Personalization Content would be a variable that pulls through the Sitecore item path of personalized content from Sitecore if the content has been personalized. (#3) Personalization Rendering would pull through the Sitecore item path of the component’s rendering from Sitecore if the rendering is personalized. (#2) Personalization State would pull through the state(show/hide) of the personalization rule.

Personalization Content would be a variable that pulls through the Sitecore item path of personalized content from Sitecore if the content has been personalized. (#3) Personalization Rendering would pull through the Sitecore item path of the component’s rendering from Sitecore if the rendering is personalized. (#2) Personalization State would pull through the state(show/hide) of the personalization rule.

Implementing personalization tracking means it must be added in the Sitecore Personalization pipeline for geoIP details, but these details can be added in a controller if your personalization request is simpler.  

How to Implement Personalization Tracking in Sitecore MVC

To implement this in Sitecore MVC, you will need to override the Sitecore Personalize pipeline.

Sitecore.Mvc.Analytics.Pipelines.Response.CustomizeRendering.Personalize

By overriding the Personalize pipeline, you can evaluate the personalization rules and read the personalized component details.

The code to evaluate the conditions and read the personalization component details can be placed in the Evaluate method.

In the code below, we created a list of personalized components object details and then store it in a session to eventually pass it to the view that will contain the GTM script above.

protected virtual void Evaluate(CustomizeRenderingArgs args)
		{
			Assert.ArgumentNotNull((object)args, nameof(args));
			Item obj = args.PageContext.Item;
			if (obj == null)
				return;
			RenderingReference renderingReference = CustomizeRenderingProcessor.GetRenderingReference(args.Rendering, Context.Language, args.PageContext.Database);
			GetRenderingRulesArgs args1 = new GetRenderingRulesArgs(obj, renderingReference);
			GetRenderingRulesPipeline.Run(args1);
			RuleList<ConditionalRenderingsRuleContext> ruleList = args1.RuleList;
			if (ruleList == null || ruleList.Count == 0)
				return;
			ConditionalRenderingsRuleContext renderingsRuleContext = new ConditionalRenderingsRuleContext(new List<RenderingReference>()
	  {
		renderingReference
	  }, renderingReference);
			renderingsRuleContext.Item = obj;
			ConditionalRenderingsRuleContext context = renderingsRuleContext;
			context.Parameters["mvc.rendering"] = (object)args.Rendering;
			this.RunRules(ruleList, context);
			this.ApplyActions(args, context);
			args.IsCustomized = true;
//The code below is to read the personalization components details
			var personalizedList = new List<PersonalizedComponentObject>();
			foreach (var rule in ruleList.Rules)
			{
//First rule to be evaluated is returned. Check the break at the end
				if (rule.Evaluate(context))
				{
					//The code below gets the personalization details of the component
					var personalizedObj = new PersonalizedComponentObject
					{
						Event = "Personalized Component Impression",
						PersonalizedComponent = renderingReference.WebEditDisplayName,
						PersonalizationCondition = rule.Name,
						PersonalizationState = rule.Actions.Count < 1 ? "Show" : string.Empty
					};
					foreach (var a in rule.Actions)
					{
						personalizedObj.PersonalizationState = a.ToString().Contains("HideRenderingAction") ? "Hide" : "Show";
						var setDataSourceAction =
							a as Sitecore.Rules.ConditionalRenderings.SetDataSourceAction<Sitecore.Rules.
								ConditionalRenderings.ConditionalRenderingsRuleContext>;
						var setRenderingAction =
							a as Sitecore.Rules.ConditionalRenderings.SetRenderingAction<Sitecore.Rules.
								ConditionalRenderings.ConditionalRenderingsRuleContext>;
						if (setDataSourceAction != null) //personalizationContent
						{
							personalizedObj.PersonalizationContent = Sitecore.Context.Database
								.GetItem(new ID(setDataSourceAction.DataSource)).Paths.FullPath;
						}
						else if (setRenderingAction != null)
						{
							personalizedObj.PersonalizationRendering = Sitecore.Context.Database
								.GetItem(setRenderingAction.RenderingItem).Paths.FullPath;
						}
					}
					if (HttpContext.Current.Session["MVCPersonalizedObject"] != null)
					{
						personalizedList =
							HttpContext.Current.Session["MVCPersonalizedObject"] as List<PersonalizedComponentObject>;
						if (personalizedList != null)
							personalizedList.Add(personalizedObj);
					}
					else
					{
						personalizedList.Add(personalizedObj);
					}
                    // storing the object in the session to be able to read it in the controller
					HttpContext.Current.Session["MVCPersonalizedObject"] = personalizedList;
					break;
				}
			}
		}

From the main JS file on the website, add an AJAX call to read the personalization components details from the session. In the successful AJAX call, we push the returned personalized components details to the datalayer.

$(document).ready(function () {
  $.ajax({
      url: '/api/GetPersonalizedComponents', type: "GET", dataType: "json",
      success: function (data) {
        window.dataLayer = window.dataLayer || []; 
        window.dataLayer.push(
          {
            'event': 'Personalization Impressions',
            'Personalization Impressions Data': data
          } 
        );
      },
      error: function (xhr, status, error) {
      }
    });
});

The controller action would look like this.

public class AnalyticsController : Controller
    {
		// GET
		public string GetPersonalizedComponents()
		{
			if (Session["MVCPersonalizedObject"] != null)
			{
				var PersonalizedComponents = Session["MVCPersonalizedObject"] as List<PersonalizedComponentObject>;
				PersonalizedComponents = PersonalizedComponents.DistinctBy(o => o.PersonalizationCondition).ToList();
				Session["MVCPersonalizedObject"] = null;
				var obj = JsonConvert.SerializeObject(PersonalizedComponents);
				var htmlString = new HtmlString(obj);
				return htmlString.ToString();
			}
			return string.Empty;
		}
	}

How to Implement Personalization Tracking in ASP.NET Web Forms

If your website is using Sitecore ASP.NET webforms, then you will need to override the EvaluateCondition pipeline. It’s like the MVC solution, but in Webforms the Evaluate Method is being called once and all the page renderings information can be collected in that call.

Sitecore.Pipelines.InsertRenderings.Processors.EvaluateConditions

By following these steps, you can track your Sitecore personalization efforts in Google Analytics. Not only will you have access to which personalizations users are seeing and how many people are seeing them, but you will be able to evaluate the success of your personalization efforts and adjust them as needed to better serve your audiences.

We write a lot about personalization, Sitecore, and analytics. See our work with these services or reach out to learn how we can partner with you on your next project.