Tuesday, December 01, 2009

Google Analytics Launches Asynchronous Tracking

Today we're excited to announce our new Google Analytics Asynchronous Tracking Code snippet as an alternative way to track your websites! It provides the following benefits:
  • Faster tracking code load times for your web pages due to improved browser execution
  • Enhanced data collection & accuracy
  • Elimination of tracking errors from dependencies when the JavaScript hasn't fully loaded
Here is the JavaScript source of the new tracking snippet:
<script type="text/javascript">

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-XXXXX-X']);
_gaq.push(['_trackPageview']);

(function() {
var ga = document.createElement('script');
ga.src = ('https:' == document.location.protocol ? 'https://ssl' :
'http://www') + '.google-analytics.com/ga.js';
ga.setAttribute('async', 'true');
document.documentElement.firstChild.appendChild(ga);
})();

</script>
The first part of the asynchronous tracking code snippet assigns the _gaq variable to a JavaScript array. After that, two tracking API calls (encoded as arrays) are pushed onto _gaq. When the tracking code initializes, it transforms the _gaq object from a standard array into a new object and executes all the tracking API calls initially collected in the array. With this feature, you can immediately store all necessary tracking calls even before the Google Analytics tracking code is downloaded! No more worrying about race conditions or dependency issues on the ga.js tracking code.

The second half of the snippet provides the logic that loads the tracking code in parallel with other scripts on the page. It executes an anonymous function that dynamically creates a <script> element and sets the source with the proper protocol. As a result, most browsers will load the tracking code in parallel with other scripts on the page, thus reducing the web page load time. Note here the forward-looking use of the new HTML5 "async" attribute in this part of the snippet. While it creates the same effect as adding a <script> element to the DOM, it officially tells browsers that this script can be loaded asynchronously. Firefox 3.6 is the first browser to officially offer support for this new feature. If you're curious, here are more details on the official HTML5 async specification.

Once loaded, the tracking code, transforms the _gaq array into an Analytics _gaq object. This object acts as a wrapper for the underlying _gat object and executes all the commands, sending data to your Google Analytics account. Your page code can ignore this fact though, because the _gaq.push syntax can be used at any time. See the Asynchronous Tracking Usage Guide for more details.

The new tracking code is now in Beta and available to all Google Analytics users. Keep in mind that use of the code is also optional: all your existing Google Analytics code will continue to work as-is should you decide not to adopt the new tracking method. But if you want to improve the speed of your website and the increase accuracy of your Analytics data, then we think you'll love this new option.

Learn more about this new tracking code in our Google Code developer docs and get started with our migration guide.

40 comments:

  1. An even easier way, which also allows this same type of dynamic loading even with all other scripts on your page as well as GA, is to use LABjs: http://labjs.com

    For instance:

    $LAB
    .script(('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js')
    .wait(function(){
    pageTracker = _gat._getTracker("UA-XXX-XX");
    pageTracker._trackPageview();
    });

    ReplyDelete
  2. what shall we do rows below within new version ?

    pageTracker._setCampContentKey("XXX");
    pageTracker._setCampMediumKey("XXX");
    pageTracker._setCampNameKey("XXX");
    pageTracker._setCampSourceKey("XXX");
    pageTracker._setCampTermKey("XXX");
    pageTracker._setDomainName("XXX");
    pageTracker._trackPageview("XXXX");

    tep

    ReplyDelete
  3. @tep, obviously, if you look at the provided code, you see immediately that they simply changed "pageTracker.XXX(YYY)" info "_gaq.push(['XXX', YYY])"

    ReplyDelete
  4. Nice, but what the world needs is asynchronous Goggle Ad Manager slot load!

    ReplyDelete
  5. What is necessary to make this work if you are also using a rollup account?

    ReplyDelete
  6. There is a bug in this code and at least in Friefox 3.5.5 gave me error. document.documentElement.firstChild is not head, but white space. I have no white space, but Firefox told me that there is white space. To make sure that first element is element, not text, I use:

    var f = document.documentElement.firstChild;
    while(f & f.nodeType != 1){ f = f.nextSibling; }
    f.appendChild(e);

    e is document.createElement("script") and other attributes.

    ReplyDelete
  7. I hope this isn't a stupid question, but if the person viewing the page doesn't have an html5 browser will they still be tracked? Should I wait to install this until the standard is more common?

    ReplyDelete
  8. hey thanks a lot guys for the new improved code.

    ReplyDelete
  9. welcome move. as it makes the site faster

    ReplyDelete
  10. Instead of a anonymous function, can we have a setTimeout instead?

    setTimeout ( function () {
    ...
    }, 0);

    Or will this add any problem that I'm not foreseeing?

    ReplyDelete
  11. @frogman: don't worry, the code works well also without 'async' attribute. The creation of a script element with createElement() method is asyncronous by default in every current browser.

    Just a question: document.documentElement... only indentifies browser in standard mode, so in order to ensuring the inclusion on all pages (no matter about doctype) why not use simply a document.body.appendChild() ? Or am I missing something?

    Fabrizio

    ReplyDelete
  12. There is a bug in the official GA code snippet.

    Since "async" is a boolean-attribute its must be either "async" or "" according to the HTML5 spec. The value of "true" is not correct.

    Example:
    ga.setAttribute("async", ""); // legal and true
    ga.setAttribute("async", "async"); // legal and true
    ga.setAttribute("async", "true"); // illegal but true
    ga.setAttribute("async", "false"); // illegal but true

    Reference:
    http://www.w3.org/TR/html5/infrastructure.html#boolean-attribute

    ReplyDelete
  13. 3 cheers (and about time :))!

    ReplyDelete
  14. @Hannibal:
    document.documentElement.firstChild is also a Text node for me. So instead of:

    document.documentElement.firstChild.appendChild(ga);

    This works:

    document.getElementsByTagName('head')[0].appendChild(ga);

    Or document.head.appendChild(ga), but this isn't yet implemented in browsers; or document.querySelector('head').appendChild(ga), but alas again.

    ReplyDelete
  15. http://yura.thinkweb2.com/jstests/document_head_test_by_Garrett.html

    Try that in certain browsers (like Chrome and Opera 10), and you'll see that in fact the comment node is the first node returned (which is of course invalid to nest a <script> element under).

    My feeling is the GA code is *NOT* safe as is. They should use a more robust option.

    ReplyDelete
  16. this is great news. if you could nudge your colleagues on the Ad Manager team to do something similar it would be even better. thanks!

    ReplyDelete
  17. http://www.top-battery.com.au/
    http://www.ibuynow.com.au/
    We specialize in substitute laptop batteries (laptop battery) packs for, camcorders batteries, digital camera batteries, PDA batteries, mobile phones batteries, and power tools battery, etc. as well as battery chargers
    Online shopping for laptop batteries, laptop AC/DC adapters, battery chargers, camcorder batteries, digital camera batteries, PDA batteries, power tool batteries, 2-way radio batteries, GPS batteries, MP3 player batteries, iPod batteries, DVD player batteries, game player batteries, ink cartridges, laser toner,universal battery and more.

    ReplyDelete
  18. The comment above by "Super" is spam - isn't there a way to report spam here?

    What about answers to the fixes shown here by other users? An official response would be helpful.

    ReplyDelete
  19. Will you lose all your previously collected data when you start using the new code?

    ReplyDelete
  20. On a website I've just changed over and the following are results from YSlow doing 10 page refreshes with Web Developer toolbar disabling Cache:

    Old GS Tracking code in Footer

    1) 1.614s
    2) 1.418s
    3) 1.573s
    4) 1.343s
    5) 1.304s
    6) 1.373s
    7) 1.529s
    8) 1.429s
    9) 3.4s
    10) 1.781s

    New Async Tracking Code in Header

    1) 1.789s
    2) 1.73s
    3) 1.707s
    4) 1.727s
    5) 1.761s
    6) 2.171s
    7) 1.767s
    8) 1.864s
    9) 1.792s
    10) 1.86s

    ReplyDelete
  21. Added this into a website today, seemed nice at first, but was causing consistent problems with jquery / coda-slider v2 in google chrome resulting in problems with the first panel in coda. Took everything back to the old analytics code and it all works fine. In Firefox or IE7+ there were no such issues.

    ReplyDelete
  22. Will you add the async feature to Urchin?

    Also, we use 2 profiles for every call to GA (1 for local profile and 1 for global rollup profile). How would you setup the async calls in that situation?

    ReplyDelete
  23. If I was using

    pageTracker._trackPageview("/myurl.html");

    should I use

    _gaq.push(['_trackPageview', '/myurl.html']);

    or should I stay with the old code.

    ReplyDelete
  24. Blogger's comment system isn't great for answering questions. If you ask your questions on the Help forum, I'll do my best to answer them.

    http://www.google.com/support/forum/p/Google+Analytics/label?lid=5a6c689030bdafe7&hl=en

    ReplyDelete
  25. @Francois I came to ask the same thing. Looks like you've gotta change that or the code won't work anymore. The code you have there seems to work.

    ReplyDelete
  26. @Francois & @Dan Russell, did you get anywhere with figuring out whether the push trackPageview would work for tracking link clicks?

    ReplyDelete
  27. One thought - could Google please drop the "ssl" in the URL, and simply have https://google-analytics.com available?

    Since the URL spec calls for relative URLs to inherit any missing portions from the current address, the src for the script could then be just "//google-analytics.com/ga.js" with no script needed to correctly select http vs https.

    Not much of a saving, I know, but every little bit helps.

    ReplyDelete
  28. I just created a new Analytics account and it told me to use the old snippet, not the new one. Is that a bug or is the new snippet not ready for primetime?

    ReplyDelete
  29. I couldn't find any information on the "exclude_me" cookie for excluding team members or anyone else you would want to exclude from google analytics. _gaq.push(['_setVar', 'exclude_me']); works as expected (where the synchronous code was pageTracker._setVar("exclude_me");) by setting an exclusion for a __utmv cookie.

    ReplyDelete
  30. im a little confused... this page in the GA documentation suggests that even though you can have multiple instances of the GA tracker on a page that they will read from the same cookies and clobber one another:

    http://code.google.com/apis/analytics/docs/concepts/gaConceptsCookies.html#cookieImplementationLimits

    Does Asynchronous Tracking account for this and deal with it?

    ReplyDelete
  31. Implemented this 1 hour ago... now wait and see!

    ReplyDelete
  32. I am using google rollup account. Please let me know implementation procedure for Analytics asynchronus code. I have tried to make rollup but after editing in this code, Analytics is not showing any data.

    ReplyDelete
  33. Slight nit: async isn't exactly a new feature. Defer was in the 1998 HTML 4 standard and IE 4, and it is Mozilla who refused to implement it for a decade (because the execution order wasn't fully specified). So I think it's bizarre that Firefox is being praised for being the first to implement defer's new reincarnation.

    ReplyDelete
  34. It's amazing and nice step by Google to overcome the page speed problem.

    ReplyDelete
  35. I will use the code above and I hope it works well without a problem for my website analytic

    ReplyDelete