Ending The ga.js Wait

Google Analytics is ubiquitous, not least of all because it’s better at what it does than most of the alternatives. Also, it doesn’t require any install or maintenance. And it’s free. What’s not to like?

Frankly, not much, but if I had to nit pick, I’d note that the worst part of Google Analytics is the ga.js script that does the actual tracking of content. It’s not bad, in and of itself, but it tends to load slowly. There are several reasons for this:

  • Another DNS lookup to resolve http://www.google-analytics.com/. This DNS entry is likely to be “warm” given how frequently ga.js is used on the web, but as Jim Roskind explained on the Chromium blog, it’s the outliers that kill you.
  • It’s kinda big. At 9K on the wire (22K unzipped), ga.js is kinda chunky for what it does most of the time, namely tracking a single page load.
  • The default instructions are bone-headed. They direct you to do a document.write() which is a blocking, synchronous operation WRT page loading. This is tres dumb. Reasonable people should just include ga.js with a <script> tag, but nearly nobody does. Turns out that sane defaults still matter.
  • Load times seem totally random. As with DNS lookup, ga.js‘s latency varies wildly. This isn’t backed up by anything empirical, but many pages feel blocked by ga.js for a near eternity.

So how to fix this? Dojo 1.3’s dojox.analytics.Urchin to the rescue! Given that I was going to be including Dojo on the page to do other things anyway, I can use 1.3’s new Urchin system to help amortize the cost of using Google Analytics. The code running on this blog now includes the following code (more or less):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<script type="text/javascript"
  src="http://ajax.googleapis.com/ajax/libs/dojo/1.3/dojo/dojo.xd.js">
</script>
<script type="text/javascript">
  dojo.addOnLoad(function(){
    setTimeout(function(){
      dojo.require("dojox.analytics.Urchin");
      dojo.addOnLoad(function(){
        var tracker = new dojox.analytics.Urchin({
          acct: "UA-XXXXXX-X" // your tracking # here
        });
      });
    }, 100);
  });
</script>

You can see the real thing by looking at the bottom of this page which pulls in custom.js which includes this logic. Pete Higgins blogged about how the module works when he first wrote it, and the strategy is to load Dojo from a CDN (since the page wanted it for other things) and wait until after the page has loaded to include ga.js. This delayed loading ensures that the page is responsive before we start doing anything related to tracking. The nested calls to dojo.addOnLoad show how we can wait for one set of modules to finish before kicking off another group, and in this case we also wait until after the page is responsive to load dojox.analytics.Urchin. This module further delays loading of ga.js, meaning that it doesn’t matter how long it takes for things like DNS to resolve and for Google to serve ga.ja since it’s not ever blocking the user.

Looking at the “before” and “after” shots in firebug gives you some idea of how this technique can really make a difference:

onload waits for ga.js

onload waits for ga.js

using dojox.analytics.Urchin, we can get a responsive page and *then* track usage

using dojox.analytics.Urchin, we can get a responsive page and *then* track usage

We get page tracking and the user gets an interactive page faster. Rad.

17 Comments

  1. Posted April 12, 2009 at 12:36 am | Permalink

    This is quite useful. The analytics does takes a lot of time to load. Also hope there will be a version from Mootools :-)

  2. kl
    Posted April 12, 2009 at 6:34 am | Permalink

    I just copy ga.js to my domain and merge it with my other scripts.

  3. Posted April 12, 2009 at 7:53 am | Permalink

    We had discovered this issue of Google Analytics load time effecting our JavaScript from executing; GA was holding back on DOMReady event. We were using YUI, so I just wrote a convenience wrapper the YAHOO.util.Get.script function which made the loading of ga.js asynchronous.

    Back in October 2008, I decided to re-write my little utility and make it work with YUI 3, YUI 2.7.0, and jQuery 1.3. http://925html.com/code/non-blocking-google-analytics-integration/

    Since then my blog has received a majority of it’s search keyword traffic from people searching for a solution to this, it’s pretty evident that other developers are effected by a synchronous loading of Google Analytics and want to take control of it. It’s great to see this being baked into Dojo and if people are using other libraries (jQuery or YUI) my utility should help them solve this issue.

  4. Posted April 13, 2009 at 6:42 am | Permalink

    Here is jQuery alternative:

    var gaJsHost = ((“https:” == document.location.protocol) ? “https://ssl.” : “http://www.”);

    jQuery.getScript(gaJsHost + “google-analytics.com/ga.js”, function(){
    _gat._getTracker(“UA-8245545-1″)._trackPageview();
    });

    Source: http://www.reddit.com/r/javascript/comments/8bvx0/ending_the_gajs_wait/c08t4jy?context=1

  5. Posted April 13, 2009 at 8:38 am | Permalink

    Since people are claiming prior art, might as well include mine with the bunch (circa 2007):

    http://www.zachleat.com/web/2007/11/01/speed-up-google-analytics-with-dynamic-includes/

    Obviously, library specific code would be more elegant.

    One wonders why the Google Analytics team doesn’t fix their example code though. Web stats are a tricky beast.

  6. David
    Posted April 15, 2009 at 11:05 am | Permalink

    Awhile back, I tried to not use the document.write method to place ga.js but it didn’t like to cooperate. Now I just use the dojo way, so all is good and well.

  7. Posted April 15, 2009 at 1:29 pm | Permalink

    That’s great, but come on, Alex, you work at Google, now, make it happen, get them to fix their script. :)

  8. Posted April 15, 2009 at 5:20 pm | Permalink

    Bertrand:

    Wait? We have a right hand?

    Regards

  9. Neil
    Posted April 16, 2009 at 12:59 am | Permalink

    Is there a chance that you could “miss” a track though? If a user quickly moved off the page before the script had been fully downloaded?

    The (small) benefit of the original script is that missing a track is unlikely because the page is forced to wait?

  10. Posted April 16, 2009 at 1:11 am | Permalink

    Neil:

    Sure, you could miss it, but I’m not sure I’d call it a “visit” if the user never even got to the point where all the resources loaded. I’d hope that the goal of all content is to provide value to the user first and to the publisher second, so by that rubric, missing a couple of clicks on analysis is no big loss if the user gets a better experience. I can see valid reasons for your personal calculus being different, though. I’m only tracking a personal blog, after all.

    Regards

  11. Posted April 26, 2009 at 6:53 am | Permalink

    If you put the tag with GA at the end of your HTML, the page will show up without waiting for the script to load, so all this seems fairly pointless.

  12. Posted April 26, 2009 at 12:33 pm | Permalink

    Pies:

    The problem is that while that will, indeed, get most of the content to render before requesting ga.js, it holds up the visual indicators of “doneness” in the browser. Further, it causes any scripts that expect to be run onload to be significantly delayed. Depending on the site, the UI consequences of this lag can be mild or severe. I’d just prefer not to have to deal with it at all.

    Regards

  13. Posted April 27, 2009 at 4:43 am | Permalink

    I’d guess one reason people don’t play with analytics’ tracking code is because they’re worried it might affect the tracking status.

    i.e. Google’s “Instructions for adding tracking” don’t make it clear how important it is to stick to the example tracking code – if at all.

  14. Alvin
    Posted April 30, 2009 at 12:49 am | Permalink

    there are any method for prototype? thanks in advanced ;)

  15. Barak
    Posted May 25, 2009 at 11:59 pm | Permalink

    Out of curiosity, why is the “before” example loading a gzipped ga.js, (9K), and the after loads a non-compressed one (23K)? If that’s inherent to the way dojo.analytics.Urchin works, it should probably be fixed, or in some cases (slow connection) you’ll loose more than you gain.

  16. Chris Stephens
    Posted July 13, 2009 at 2:41 pm | Permalink

    Google seems to have a problem with compressing the text/javascript mimetype. You can make google use gzip compression by changing the type to application/javascript in all of the script code. I also suggest wrapping your type= to double quotes in the document.write, since single quotes in HTML are a bad idea.

    Someone should tell google to turn on gzip compression for the text/javascript mime type, or to switch the suggested code to application/javascript. It would probably save them terabytes per month in traffic and make peoples sites go faster :)

  17. Posted October 8, 2009 at 9:05 am | Permalink

    Alex,

    Why not do what “kl” suggested doing (near the top of the comments section)? Are there any drawbacks?

3 Trackbacks

  1. [...] Make google analytics not block your site [...]

  2. By Ajaxian » Speeding Up Urchin with Dojo, Part 2 on April 15, 2009 at 6:30 am

    [...] but the Dojo folks have packaged up Pete’s script into the recently released Dojo 1.3 and Alex Russell recently posted a great summary of issues with Google Analytics and an example of the new code: [Google Analytics] [...]

  3. By dojox.analytics.Urchin for jQuery | Jens Arps on October 3, 2009 at 10:28 am

    [...] wrote such a wrapper for dojo, and as of dojo 1.3, it’s officially included in dojox (see Alex Russel’s post). But this WordPress theme runs jQuery, and I didn’t want to have two frameworks in one [...]