Sitecore analytics, cookie consent and personalization isn’t a great match – learn how to keep Sitecore functional without breaking the law!
Due to different laws (European as well as local legislation) companies have be very conversative in how they process data, while they have to take care on how they track people. People have to consent whether or not they will be tracked or not. Within Siecore, you might do both. This blogpost shares how to use your cookie consent strategy within Sitecore. In short: There are three level of cookies: Functional, analytic and tracking cookies. Without responding to the cookie consent, Only functional cookies are allowed, while analytics and tracking cookies is forbidden until a user gives approval for these kinds of functionality. Within Sitecore, this is hard to implement, due to the internal workings of Sitecore analytics and (from what I think) Sitecore bug. This blogpost explains why this is hard and how to solve this.
PS: Different companies classify the Sitecore cookies under different levels. I have seen classifications of “Functional”, “Analytics” and “Tracking”. I won’t judge any choice, as I am not a person with a legal background and can’t judge on what all companies implement to prevent data from being collected. This is my personal view and the approach should be applicable to every level. This blogpost applies to Sitecore 9.X
Too long; Didn’t Read
When implementing logic in Sitecore to follow Cookie consent settings, the Sitecore tracker needs to be stopped. While basic conditions which don’t require the tracker should still work (aka the functional level), this is not the case. Stopping the tracker prevents Conditional Renderings from working. The fix for this issue (override the Personalize Pipeline and remove the check for Tracker.IsActive) brings another issue to the surface; when there is a Condition that causes an Exception (and there are loads of them) your conditions will not be evaluated anymore and the rendering will fall back to the default rendering. The RuleList
Code can be found here.
Sitecore analytics and the tracker – a functional perspective
When Sitecore analytics is enabled, various functionalities (but not limited to) are available, which all require the Sitecore Tracker (important):
- Personalization (Until Sitecore 9.1 in process personalization was possible from Sitecore 9.1 the XM version is needed. Tracking might be disabled while still having making use of personalization rules) - Out of the box functionality
- Analytics – User behavior is collected anonymously. IP addresses are redacted, browsing history. Out of the box functionality
- Tracking – users may be identified and additional information might be stored into the XDB. Explicit action needs to be taken to store this information, which means this data is not stored out of the box. Using XDB to store data about people might fall under the GDPR law!
Depending on how the above functionality is plotted by your legal organization, out of the box functionality might or might not comply with the “Functional Level” – the level which should be applied without explicit consent. If your organization scores Personalization and Analytics under the “Functional level” – congratulations, you could stop reading, as you won’t have to take any actions to comply.
In the story below I’ll discuss the different functionalities and why you might have a problem.
Personalization - Basic functional working of Sitecore with rules and conditions
One of the most powerful capabilities of Sitecore is using personalization rules and conditions. As “personalization” may sound that it personalizes the website based on an identity, it may be a very general condition which doesn’t have to do anything with a person or identity. For example: Show a different rendering based on a querystring parameter:
In my personal opinion, this is a basic functionality which should work in any scenario, even when analytics is turned off. Which means: conditions which require the Sitecore Tracker should not function.
Sitecore Analytics – track anonymous data
In this functionality, Sitecore stores visitor information (useragent, resolution information, goals, events, page visited and a hashed ip-address). This functionality stores metadata about a certain visit, but no information about the visitor itself.
Sitecore Tracking – track visitor information
Whenever a user submits (personal) data, this data could be stored. A developer would have to take explicit action to, for example, store email addresses, name and address data, personal interests or whatsoever. Based on this kind of data, personalization options could be offered.
Sitecore analytics and the tracker – a technical perspective
When Sitecore analytics is enabled, the functionalities above are all available. But they rely on a single mechanism: the Sitecore Tracker. This one should be active and is filled with a certain context.
The property “Tracker.IsActive” tells is if analytics is turned on, while the Tracker.Current should have a Tracking context for the current user. The “SC_ANALYTICS_GLOBAL_COOKIE” goes hand in hand with this mechanism. It tells us a) who is this user and b) has the user already been classified (as a robot or human?))
Cookie consent levels and Sitecore and their precautions
Most companies inject their cookie consent messages and choices using a tag managent system like GTM or Relay42. The default choice is level 1 (Functional) or no level, while visitors can explicitly choose for level 1, 2 or 3 (functional, analytics or tracking – see the similarity with the Sitecore functions?)
Sitecore analytics classified as | Precautions |
Functional | No Actions |
Analytics | Take actions to prevent Sitecore from loading the tracker before consent has been given |
Tracking | Take actions to prevent Sitecore from loading the tracker before consent has been given |
When precautions need to be taken, based on your cookie consent levels and the Sitecore classification, the Tracker needs to be stopped as soon as possible. I won’t share code with the cookie consent logic, but this Tracker should be stopped directly after the following pipeline:
Sitecore.Analytics.Pipelines.StartAnalytics.CheckPreconditions
a custom pipeline should be implemented which, based on your cookie consent logic, should call the following code as long as no consent has been given:
Sitecore.Analytics.Tracker.Current?.EndTracking();
args.AbortPipeline();
The Tracker has been stopped – now it gets hard
When the tracker stops tracking, the most basic functionality stops working as well: Personalization! As explained, this doesn’t have to rely on a person, identity or the current visits; conditions could go off on things like query strings as well! A few lines of code within the “Sitecore.Mvc.Analytics.Pipelines.Response.CustomizeRendering.Personalize” pipeline prevent the (basic) conditions from evaluating, as there is an explicit check on the “Tracker.IsActive”. but it has explicitly been stopped:
A quick fix was to override this processor and remove the explicit check on the Tracker. But behavior wasn’t as obvious as it seemed:
Conditions might not evaluate
When working with basic conditions which do not require a tracker worked seamlessly. But when mixing up, behavior is unexpected. As an example, the rule “Where the specific campaign was triggered during the current visit”. This one has a dependency on the tracker. Based on the order of the conditions, the expected outcome will or won’t appear, see the included video below, as it explains the issue much better:
Conditions which require a Tracker throw an exception when it is not available
The HasCampaign condition for example has a few lines of code which chech whether or not the Sitecore Tracker is available:
Under the hood, these Asserts throw an “InvalidOperationException”.
Conditions which throw an error cause the complete pipeline to abort
At the “RunRules” method in the personalizae pipeline, the code to run the rules can be found. It’s actual impementation is the default RuleList
My expectation was that the Run implementation would evaluate rules which throw an exception to false. This expectation was wrong, every exception aborts the pipeline, which means that no rule will be evaluated anymore:
This cannot be fixed easily by Sitecore
As this function RuleList
A Suitable approach
A more suitable approach, is to replace the RuleList
The magic happens in this specific catch:
This will cause to the evaluation process to continue after an InvalidOperationException and causes all Conditions to evaluate successfully.