Make Google Analytics Asynchronous

Configuration

The 'Make Google Analytics Asynchronous' filter is enabled by specifying:

Apache:
ModPagespeedEnableFilters make_google_analytics_async
Nginx:
pagespeed EnableFilters make_google_analytics_async;
in the configuration file.

Description

The filter rewrites pages that load the Google Analytics tracking code synchronously to load it asynchronously instead. Loading Google Analytics asynchronously has the advantage that it will not block resources that load later in the page.

Currently, the filter only changes the loading mechanism. To get the full benefit of the asynchronous load, you should move the loading of the tracking code to the bottom of the <head> of the page. That allows beacons to be sent earlier during the page load -- and avoids missing them if a user navigates away from a page quickly. For more information on how to manually upgrade, see Migrating to Async Tracking

Operation

The filter looks for a Google Analytics snippet such as the following:

<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-XXXXX-X");
    pageTracker._trackPageview();
  } catch(err) {}
</script>

and rewrites such snippets in-place to:

<script type='text/javascript'>
  var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
  GLUE_SCRIPT
  var ga = document.createElement('script');
  ga.type = 'text/javascript'; ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' :
            'http://www') + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0];
  s.parentNode.insertBefore(ga, s);
</script>
<script type="text/javascript">
  try {
    var pageTracker = _modpagespeed_getRewriteTracker("UA-XXXXX-X");
    pageTracker._trackPageview();
  } catch(err) {}
</script>

where GLUE_SCRIPT is JavaScript that defines the _modpagespeed_getRewriteTracker function to return an object that maps all the methods of the synchronous API to the asynchronous API.

Additionally, the filter will replace loads in the following format:

<script src="http://www.google-analytics.com/ga.js" type="text/javascript"></script>

The rewrite is known to not work when calls are made to Google Analytics methods that return values. To avoid this issue, the filter searches for these methods and abandons the rewrite if they are found.

Example

You can see the filter in action at www.modpagespeed.com on this example.

Requirements

In order for the filter to trigger, the Google Analytics snippets must be in the same format as shown above. The filter only performs simple string matches to find the Google Analytics snippets.

Also, once a synchronous load is matched, the rest of the page is scanned for any Google Analytics calls that return values. It only performs the rewrite once it has reached the end of the page. That means the filter depends on how the web page is buffered by the server. Specifically, if the snippet is not in the last flush window, it will not be rewritten.

Risks

This filter is considered high risk.

The make_google_analytics_async filter is experimental and has not had extensive real-world testing. One case where a rewrite would cause errors is if the filter misses calls to Google Analytics methods that return values. If such methods are found, the rewrite is skipped. However, the disqualifying methods will be missed if they

Those cases are expected to be rare.