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.

43 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. What a great blog.And I just want to say thanx to you for awaring me about the new and revised things about google.I also have some information that will be very useful to you.Realted to discount on network and electric applinces.I have visited a site that is providing great discount by On Sale promo code.You can also visit that site for more information.

    ReplyDelete
  4. @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
  5. Nice, but what the world needs is asynchronous Goggle Ad Manager slot load!

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

    ReplyDelete
  7. 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
  8. 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
  9. hey thanks a lot guys for the new improved code.

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

    ReplyDelete
  11. 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
  12. @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
  13. 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
  14. 3 cheers (and about time :))!

    ReplyDelete
  15. @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
  16. 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
  17. 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
  18. 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
  19. 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
  20. Will you lose all your previously collected data when you start using the new code?

    ReplyDelete
  21. 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
  22. 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
  23. 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
  24. A review in brazilian portuguese: http://insighter.org/web-analytics/google-analytics-asynchronous-tracking

    ReplyDelete
  25. 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
  26. 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
  27. @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
  28. @Francois & @Dan Russell, did you get anywhere with figuring out whether the push trackPageview would work for tracking link clicks?

    ReplyDelete
  29. Thanks everyone for your feedback on the new Analytics Asynchronous Tracking snippet. We have incorporated some of your suggestions and have updated our snippet recommendation. You can check it out here: http://code.google.com/apis/analytics/docs/tracking/asyncTracking.html

    ReplyDelete
  30. 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
  31. 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
  32. 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
  33. 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
  34. Implemented this 1 hour ago... now wait and see!

    ReplyDelete
  35. 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
  36. 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
  37. It's amazing and nice step by Google to overcome the page speed problem.

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

    ReplyDelete