Global Asynchronous Queues in Google Analytics and Optimizely
A global asynchronous queue, is a super confusing sounding term used to describe an incredibly common pattern used by web analytics providers, that we at Clearhead encounter on a daily basis.
To explain what a global asynchronous queue is, lets break down the script that Google Analytics provides to implement tracking. The following snippet is intended to be included in the head of any page that you want to include GA tracking on.
So what’s going on here:
1) On line 1: We set declare a window level variable _gaq equal to an empty array, ONLY if _gaq doesn’t already exist. This is important because we don’t want to overwrite the _gaq if it already exists.
2) On lines 3 & 4: We push two arrays into the _gaq array. The first value in each array will eventually be interpreted as a function, with each additional value in the array (if any) to become an argument in the function.
So lines 3 & 4 will eventually be interpreted as:
3) On lines 6-13: We add the ga.js file to the head of the document
Once ga.js is loaded, the _gaq array is turned into an object that is able to then call the “_setAccount” & “_trackPageview” functions that were stored in the _gaq array. This new _gaq object comes equipped with a push function so that we are still able to add events to the queue in the same syntax as on lines 3 & 4, despite _gaq no longer being an array.
The beauty of this global asynchronous queue, is that we don’t have to wait for ga.js to completely load before starting to call our tracking events. It would be much easier to screw up google analytics integrations if developers had to poll for ga.js to load, or listen some event that would be fired upon the ga.js loading.
The ordered nature of the _gaq queue also allows us to be 100% sure that a tracking event will never be called before the account has been set.
Many other resources use “global async queues” to their advantage. Optimizely
being one of them, with their window.optimizely object.
The optimizely object is useful because sometimes event tracking in Optimizely is best handled by using their API. The syntax for pushing events like this to the Optimizely API is similar to that of Google Analytics. To create a segment and push an event it would look something like this:
Here the optimizely object serves as the asynchronous queue in the same way that _gaq did for google analytics.
This syntax benefits optimizely users that include optimizely event tracking in their code base. Since the above tracking isn’t dependant on optimizely loading (it just creates an array named optimizely at the window level) if they ever remove optimizely from a page that has the above code on it, they won’t incur any errors.
I hope that this description of global async queues was helpful in explaining a pattern that I find to be really interesting/useful. If you’re here reading it, there’s probably a good chance that we’re interested in hiring you! We’re always looking for dev talent with an interest in analytics. Checkout our job listings here: http://clearhead.theresumator.com/ or feel free to reach out directly.
Posted April 22, 2015
We've noticed that due to the flexible nature of asynchronous queues, people have mistakingly assumed that there is no need for ordering the function calls at all. There are several functions in the Optimizely as well as in the Google Analytics api that require an order. For example:
1, // This custom var is set to slot #1. Required parameter.
'Items Removed', // The name acts as a kind of category for the user activity. Required parameter.
'Yes', // This value of the custom variable. Required parameter.
2 // Sets the scope to session-level. Optional parameter.
'Shopping', // category of activity
'Item Removal', // Action
In the example above, someone wants to set a customvar. If no _trackEvent or _trackPageview occurs after the _setCustomVar function, the custom variable will never reach the Google Analytics servers and will not show up in the reports.
The Optimizely api has similar requirements for some functions. For example, the function bucketVisitor:
window['optimizely'] = window['optimizely'] || ; window['optimizely'].push(["bucketVisitor", experimentId, variationId]);
needs to be called before the Optimizely snippet is loaded on a page. If the function call is done after Optimizely has loaded, nothing will happen.
Thanks a ton @brady! This is a very clear explanation of something most developers and marketers take for granted, but opens up a lot of custom possibilities when you break down what the code is doing. This code format also allows us to easily move between custom and standard solutions for customers because the underlying code approach is the same.
Solutions Architect | Optimizely, Inc.