Adobe Analytics: Don't use clearVars() to clear variables!
This article was posted originally at Adobe Experience League Communities.
(Disclaimer: The following recommendation is based on my personal experience. It is not endorsed nor recommended by Adobe or any of its partners.)
Background: sending more than one beacon in the same page
When it comes to accurate analytics tracking, one of the most important things to guard against is that you don't track variables that shouldn't actually be tracked. This happens particularly often when multiple beacons are sent from the same web page.
A simple example is what happens when you want to track a link click on a page. When the page's Pageview beacon (s.t()) is sent, you might have tracked eVar8 with the page's site section. This eVar8 remains set in the Analytics "s" object. So when you track the click on the link with a Custom Link beacon (s.tl()), that eVar8 would be tracked as well – even if that wasn't your intention.
This problem manifests itself even more so if your website is a Single Page Application (SPA). In that case, your website really only has one "physical" page, and then you have multiple "virtual" pages. Each page would be tracked with a Pageview beacon. But because the browser never actually loads a new "physical" page in between pages, there is only one single Analytics "s" object that persists as long as the user keeps interacting with the website. And as you can imagine, multiple props, eVars and events could accumulate in that "s" object, resulting in variables being tracked wrongly!
To work around this problem of variable accumulation, Adobe Analytics provides a clearVars() function. In simple terms, it wipes out all of the variables that have been set in the "s" object, giving you a nice, clean slate to track from. (Learn more about clearVars().)
But clearVars() (or the "Clear variables" action in the Adobe Analytics extension in Adobe Experience Platform Launch Data Collection) is both a blessing and a curse. It wipes out everything!
The Problem: everything gets reset!
Back to the above example of the Pageview and the Custom Link beacons. Let's say you track site language to eVar5, and you want this to be tracked with all beacons, both Pageview and Custom Link ones. If you were to use clearVars after sending every beacon, then you'll always need to set eVar5 again! In other words, you need to do this all of the time:
- User opens the web page.
- Set s.eVar5 to the site language.
- Send the Pageview beacon --> s.eVar5 is tracked with the site language.
- Run clearVars() --> s.eVar5 is now blank.
- User clicks a link.
- Set s.eVar5 to the site language.
- Send the Custom Link beacon --> s.eVar5 is tracked with the site language.
- Run clearVars() --> s.eVar5 is now blank.
If you miss step 2.1, then your tracking implementation is wrong and you have to fix that. And all because you had used clearVars() at step 1.3. You might remember that, but will the future you remember that? Or the person who inherits your implementation after you?
And that is precisely why I don't use clearVars() – because it's so destructive!
Solution: use s.registerPostTrackCallback() to unset only those variables that should be cleared
Fortunately, Analytics' tracking code has a handy function called registerPostTrackCallback(). Any code that is put inside here will run after every beacon call. (Learn more about registerPostTrackCallback().) This is the perfect place to unset any variables that you don't want to persist between beacons – precisely because you can control what variables you want to clear and/or leave intact.
Here's the code that I use:
s.registerPostTrackCallback(function(requestUrl, s) { // unset variables and events that are not needed after sending a beacon // BUT LEAVE BEHIND variables that should remain, e.g. those that are set in the Adobe Analytics extension itself var doNotUnsetVariables = [ 'pagename', // page name 'server', // site server 'eVar5', // site language // keep adding more dimension variables: hiers, props, eVars ]; var doNotUnsetVariablesRegExp = new RegExp('^(' + doNotUnsetVariables.join('|') + ')$'); // find and erase all unneeded variables var setVariables = Object.keys(s).filter(function (k) { return /^((eVar|hier|list|prop)[0-9]+|(purchase|transaction)ID|campaign|channel|pageType|products|state|zip)$/.test(k); }); var unsetVariables = setVariables.filter(function (k) { return !doNotUnsetVariablesRegExp.test(k); }); unsetVariables.forEach(function (v) { s[v] = ''; }); // erase all success events s.events = ''; }, s);
The important part is the "doNotUnsetVariables". This is an array of variable names that you want to retain between beacons. In my example code above, I've kept eVar5, so that site language can still be tracked with every beacon. But you don't see eVar8 because I don't want to track the site section every time.
(Take note of that 2nd last line too: my example code clears out all s.events. If you have any events that you want to retain between beacons, then that line will need to be modified for your specific case.)
This code can be placed before or after the s.doPlugins() block in your AppMeasurement code. If you're using Adobe Experience Platform Launch Data Collection, then you can add this in the Adobe Analytics extension's custom code.
What happens is, in my view, beautiful and elegant:
After every beacon, whether it's a Pageview or Custom Link or Download Link or Exit Link, that code inside registerPostTrackCallback() will run.
When that code runs, it clears out only those variables that are not specified in doNotUnsetVariables. So variables that should remain in the Analytics "s" object remain intact for the next beacon.
This is much, much, much better than clearVars()'s all-or-nothing massively destructive approach. clearVars() is like a megaton nuclear bomb on the "s" object, while my approach picks and chooses those "s" variables that don't need to be retained.
So don't use clearVars()! Instead, clear only those variables that you want to clear, and the example above provides you with a quickstart to doing just that.
What do you think of my recommendation? Is it good or bad? Have you done something similar to this? Or do you actually prefer clearVars(), despite its massively destructive approach? Leave a comment and share your views.
I do it differently.
ReplyDeleteInstead of marking all that doesn't have to be reset, I started having a different approach. I mean... it may sound barbaric. But damn it makes my life so much easier.
I set all global vars (the ones that should fire on all pages/links/whatever) in doPlugins. Moreover. I completely dump the concept of linktrackevents by... adding all events from s.events into it. In doPlugins. So I NEVER touch that useless thing again.
I was considering doing the same with linktrackvars. I mean, linktrackvars MAY be useful in case you're not careful and allow garbage there. But if you're careful with what you put where and when you clean your mess, you're good to not use it.
Yes, having code like that in doPlugins requires you to write high quality failproof code and be extremely careful about it. failing doplugins is not very good. It's awful, in fact. And I'm sure I could find a better callback for it. But doPlugins is always there and it was too tempting to make use of it.
So I never suffer from clearing all vars after each call. Actually, I find it annoying to clear them in every action. I was thinking about finding a callback that fires after each s.t and s.tl and clear the vars after. Or maybe even override them... huh .
> I was thinking about finding a callback that fires after each s.t and s.tl and clear the vars after. Or maybe even override them... huh .
DeleteThat is **exactly** what I had proposed in the section "Solution: use s.registerPostTrackCallback() to unset only those variables that should be cleared".
You want to unset only the ones that should be cleared. I want to unset all of them. On every call. Unconditionally. Because I set all I need to be set automatically in doPlugins.
DeleteMy logic is inverted comparing to yours.
But thanks for the callback :)