Wednesday, January 14

Tracking AJAX calls with Google Analytics (and Rails)

With my recent pet project I used AJAX to provide a majority of the site functionality on the main page with it never having to reload itself or load another page. This resulted in a drastic drop of "page" views in my Google Analytics reports, because the only "page" being loaded on each visit was the sole main page; every click after that was an AJAX call to update only a portion of the already loaded page, hence not triggering any calls back to the Google Analytics tracking server. So I set out to see if I could remedy that, and I did.

I started out with a Google search for assistance. Surprisingly, the results were grim. The highest ranked result required a "donation" to read the answer, and I opted not to. Other results were vague or dated or focused on the same issue with Flash. I had to crack open the code and get my hands dirty.

When you set up a profile to track with Google Analytics, they give you a little snipped of JavaScript code to paste into your website pages. It looks something like this:

<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-1377203-6");
pageTracker._trackPageview();
} catch(err) {}</script>

Seems cryptic enough, right? If you look closely you'll see it's actually two scripts, not one. The first script imports the Google Analytics tracking library:

<script type="text/javascript">
var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));
</script>

And the second script calls the library to track the page.

<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-1377203-6");
pageTracker._trackPageview();
} catch(err) {}</script>

In order to track a page load, including an AJAX call, you merely need to call the tracking library, but you need to import the library only once. That's where things get a little tricky.

For starters, I separated the two scripts into their own respective partials. I render both partials on the main page, so the library is loaded and then called to track the page load. However, from the AJAX calls, I only render the second script, the one that calls the library, since it will have already been loaded by the main page.

Here's the first curve ball. The first time I render and serve the main page, the AJAX-y portions of the page are rendered in-line. Since each of them in turn renders the call to the tracking library, the loading of the main page could erroneously track several hits. In order to prevent this, I wrapped the script with a global flag check and set, so no matter how many times it's rendered for a single page, it only injects the script once:

<% unless @already_tracked %>
<% @already_tracked = true %>
<script type="text/javascript">
try {
var pageTracker = _gat._getTracker("UA-1377203-6");
pageTracker._trackPageview();
} catch(err) {}</script>
<% end %>

The second curve ball is that you need to render the first partial - the one that loads the Google Analytics library - at the top of your page, rather than the bottom as Google recommends in its documentation. I put mine immediately inside the body tag. Why? Because the first partial, with an embedded tracker call, to render on the page is going to try to call the tracking library when the browser processes it, and if the tracking library isn't yet loaded, the call will silently fail (thanks to the try/catch block).

Now that the main page loads the tracking library, and the HTML snippets returned from the AJAX calls in turn call the already-loaded tracking library, each AJAX call is tracked as a page view on your Google Analytics report. Note that this solution is specific to AJAX calls that inject pre-rendered HTML into the page. If you need to track AJAX calls that deal with behind-the-scenes processing you should be able to simply make the same JavaScript calls you see in the second script; wrap them up in a helper function for convenience.

4 comments:

Michael said...

This maybe what you want -

http://www.google.com/support/googleanalytics/bin/answer.py?hl=en&answer=55519

To sum up, the article says to call:
pageTracker._trackPageview("/pagefilename1" );

after your ajax call has been completed. (replace /pagefile1 with the "ajax" page you requested.)

Anonymous said...

Very nice. People wrote in the Google Analytics offical group this was impossible.

Anonymous said...

Very nice. People wrote in the Google Analytics offical group this was impossible.

Anonymous said...
This comment has been removed by a blog administrator.