Don't use clearVars!

Avatar

Avatar
Publish 1
MVP
yuhuisg
MVP

Likes

200 likes

Total Posts

608 posts

Correct reply

122 solutions
Top badges earned
Publish 1
Affirm 100
Springboard
Bedrock
Validate 1
View profile

Avatar
Publish 1
MVP
yuhuisg
MVP

Likes

200 likes

Total Posts

608 posts

Correct reply

122 solutions
Top badges earned
Publish 1
Affirm 100
Springboard
Bedrock
Validate 1
View profile
yuhuisg
MVP

01-06-2021

(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 (s.t()). 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. 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 cleared!

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:

  1. User opens the web page.
    1. Set s.eVar5 to the site language.
    2. Send the Pageview beacon --> s.eVar5 is tracked with the site language.
    3. Run clearVars --> s.eVar5 is now blank.
  2. User clicks a link.
    1. Set s.eVar5 to the site language.
    2. Send the Custom Link beacon --> s.eVar5 is tracked with the site language.
    3. 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. 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|camapign|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 s.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' 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.

 

Yuhui | yuhui.sg | Analytics, A/B Testing, Development since 2006

7 Comments

Avatar

Avatar
Boost 5
Level 2
atulsingh17
Level 2

Likes

5 likes

Total Posts

13 posts

Correct reply

4 solutions
Top badges earned
Boost 5
Boost 3
Affirm 3
Establish
Affirm 1
View profile

Avatar
Boost 5
Level 2
atulsingh17
Level 2

Likes

5 likes

Total Posts

13 posts

Correct reply

4 solutions
Top badges earned
Boost 5
Boost 3
Affirm 3
Establish
Affirm 1
View profile
atulsingh17
Level 2

01-06-2021

This is nice post. I would definitely give it a try.
clearVars() always been a pain area for me too. However, I was wondering, if you have any variable that you would want to set again on next s.tl() call, you can define such variables in doPlugins() section.

Variables which you don't want to persist to linkcalls, can be set in Global Variable in Analytics extension and the variable which you would want there is linkcalls can be set in doPlugins() section. With that, even though clearVars() would clear all the globally set variables but variables like lang/site-section can be set in doPlugins() so next time when you have linkcall you would have those set again.

 

I have seen most people avoid extra lines of code 🙂

 

Avatar

Avatar
Publish 1
MVP
yuhuisg
MVP

Likes

200 likes

Total Posts

608 posts

Correct reply

122 solutions
Top badges earned
Publish 1
Affirm 100
Springboard
Bedrock
Validate 1
View profile

Avatar
Publish 1
MVP
yuhuisg
MVP

Likes

200 likes

Total Posts

608 posts

Correct reply

122 solutions
Top badges earned
Publish 1
Affirm 100
Springboard
Bedrock
Validate 1
View profile
yuhuisg
MVP

01-06-2021

Thanks for sharing, @atulsingh17 !


Variables which you don't want to persist to linkcalls, can be set in Global Variable in Analytics extension and the variable which you would want there is linkcalls can be set in doPlugins() section. With that, even though clearVars() would clear all the globally set variables but variables like lang/site-section can be set in doPlugins() so next time when you have linkcall you would have those set again.

That is precisely what I want to avoid: remembering to set the variables again somewhere else. That's why instead of the set-clear-reset method that you've described, I've opted to use a method that only clears specific variables, while leaving the others intact.

Also, if I were implementing AA directly in code, then I would definitely go with your method of using doPlugins(). But with Adobe Experience Platform Launch Data Collection, I prefer to rely on the Global Variables as much as possible.

But there's definitely nothing wrong with your approach, and since you're comfortable with that, I'd recommend that you continue with it.

Avatar

Avatar
Shape 100
MVP
AndrewWathen
MVP

Likes

575 likes

Total Posts

320 posts

Correct reply

16 solutions
Top badges earned
Shape 100
Bedrock
Springboard
Seeker
Contributor
View profile

Avatar
Shape 100
MVP
AndrewWathen
MVP

Likes

575 likes

Total Posts

320 posts

Correct reply

16 solutions
Top badges earned
Shape 100
Bedrock
Springboard
Seeker
Contributor
View profile
AndrewWathen
MVP

02-06-2021

@yuhuisg - really interesting insight into how you approach this.... and is very different to how I like to set up.  I think it is one of those situations where there are multiple approaches and there is no right or wrong approach.

 

Just for the record in case any one is interested here is our approach...

 

We have a Launch rule that always runs before everything else that both calls clearVars and sets linkTrackVars & linkTrackEvents to "none".  We do this deliberately to create a completely clean slate each time.  We then explicitly re-establish the adobe analytics variables that we want.

 

I like this approach because:

  • we'll never accidently have anything bleeding over from one call to the next
  • by looking at the rules we have, it is absolutely clear what variables will be sent for a given scenario (easy for people to understand)

This works well for us, but appreciate your approach clearly works well for you too 🙂

Avatar

Avatar
Coach
MVP
StewSchilling
MVP

Likes

342 likes

Total Posts

278 posts

Correct reply

85 solutions
Top badges earned
Coach
Give Back 25
Springboard
Bedrock
Validate 1
View profile

Avatar
Coach
MVP
StewSchilling
MVP

Likes

342 likes

Total Posts

278 posts

Correct reply

85 solutions
Top badges earned
Coach
Give Back 25
Springboard
Bedrock
Validate 1
View profile
StewSchilling
MVP

02-06-2021

Interesting approach.  I have some concerns with it as written though. 

 

The code block :

 

  var setVariables = Object.keys(s).filter(function (k) {
    return /^((eVar|hier|prop)[0-9]+|products)$/.test(k);
  });

 

  • This fails to include a handful of variables, ['channel', 'campaign', 'state', 'zip', 'pageType', 'purchaseID', 'transactionID', 'list1', 'list2', 'list3', ...maybe some others].  As it stands, these variables would not get cleared. 
  • The s object has a ton of keys on it.  It would me more code, but more performant to run some for loops to create the array that gets returned here. 

I think that a better implementation for a clearVars function with exclusions would be to overwrite s.clearVars as such: 

 

// This should be run at the top of AA Custom Code
s.clearVars = function() {
  var clearVarsExclusions = _satellite.getVar('clearVarsExclusions') || [];
  var clearVarsAdditions = _satellite.getVar('clearVarsAdditions') || [];

  var aaVars = [
    'chanel', 
    'events', 
    'products', 
    'purchaseID', 
    'transactionID', 
    'state', 
    'zip', 
    'campaign'].filter(function(variable){
      return (clearVarsExclusions.indexOf(variable) === -1);
    });
  var genVars = function(prefix, limit, exclusions){
    var variables = [];
    for (var i=1; i<=limit; i++) {
      var variable = prefix+i;
      (exclusions.indexOf(variable) === -1) && variables.push(variable);
    }
    return variables;
  };
  
  aaVars.concat(
    clearVarsAdditions,
    genVars('prop', 75, clearVarsExclusions), 
    genVars('eVar', 250, clearVarsExclusions), 
    genVars('list', 3, clearVarsExclusions),
    genVars('hier', 250, clearVarsExclusions)
  ).forEach(function(variable){
    s[variable] = void 0;
  });
}

 

 

Beyond being more performant, this allows the use of the AA Extension's Clear Variables action if desired.  If you would rather call s.clearVars from a postTrackCallback, this solution would support that as well. 

 

Oddly enough, the s.clearVars function in AppMeasurement.js does not clear s.pageName. The solution above allows the specification of an array of variables to include when clearing. 

 

If I were to take this one step further, I would

  • put this code into an extension so that no changes would need to be made in AA custom code. 
  • also add a UI for management of the exclusion and addition lists.
  • add the option to call the function after every beacon (via register postTrackCallback).
  • possibly add some functionality for clearing context variables. 

Just my $0.02

 

Avatar

Avatar
Publish 1
MVP
yuhuisg
MVP

Likes

200 likes

Total Posts

608 posts

Correct reply

122 solutions
Top badges earned
Publish 1
Affirm 100
Springboard
Bedrock
Validate 1
View profile

Avatar
Publish 1
MVP
yuhuisg
MVP

Likes

200 likes

Total Posts

608 posts

Correct reply

122 solutions
Top badges earned
Publish 1
Affirm 100
Springboard
Bedrock
Validate 1
View profile
yuhuisg
MVP

03-06-2021

Thanks for the input, @StewSchilling . I am personally not in favour of overwriting functions that have been specified in the library, because it introduces a new area of error if I or my successors forget about it.

Also, I've corrected my regular expression in the post to accommodate more variable names. There could still be others that are left out, but it would be trivial for someone who wants to use this code to add them into the expression, if needed.

Avatar

Avatar
Engage 1
Level 1
Vijaysarathy_Krishnan
Level 1

Likes

0 likes

Total Posts

4 posts

Correct reply

0 solutions
Top badges earned
Engage 1
View profile

Avatar
Engage 1
Level 1
Vijaysarathy_Krishnan
Level 1

Likes

0 likes

Total Posts

4 posts

Correct reply

0 solutions
Top badges earned
Engage 1
View profile
Vijaysarathy_Krishnan
Level 1

25-07-2021

I was dealing with exactly the same problem and used this solution and it worked beautifully. Thank you for sharing this. @yuhuisg 

Avatar

Avatar
Coach
Level 6
David__Garcia
Level 6

Likes

106 likes

Total Posts

217 posts

Correct reply

45 solutions
Top badges earned
Coach
Builder
Engage 10
Seeker
Bedrock
View profile

Avatar
Coach
Level 6
David__Garcia
Level 6

Likes

106 likes

Total Posts

217 posts

Correct reply

45 solutions
Top badges earned
Coach
Builder
Engage 10
Seeker
Bedrock
View profile
David__Garcia
Level 6

31-07-2021

Thank you for the insight, helped me out.