Async Google Analytics
JavaScriptRewrites a synchronous Google Analytics snippet to load asynchronously.
Filter
make_google_analytics_async
· Filter docs · Demonstrates rewriting the Google Analytics snippet.
A mod_pagespeed 1.1 filter. ModPageSpeed 2.0 applies it as part of one always-on pipeline, not as a separate switch.
Both frames render identically — that's the goal. The win is in the bytes and requests
below, not the look. They're served live by mod_pagespeed 1.1 on
demo-httpd-1.1.modpagespeed.com; the optimized frame
applies only this filter. Right after a cache purge it may briefly match the original while
the worker rewrites it — reload to see the result.
Measured impact
This filter changes how the page is structured or delivered, not its size — so there's no byte or request reduction to chart. The change shows in the source diff below.
What changed in the source
The page's HTML, before and after this filter. Red lines are removed, green lines are added.
… 5 unchanged lines …
Google Analytics loaded via document.write in main doc.
<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"));
+ var _gaq = _gaq || [];
+ (function(){
+ function functionName(fn) {
+ var name = /\W*function\s+([\w\$]+)\(/.exec(fn);
+ if (!name)
+ return 'No name';
+ return name[1];
+ }
+ var nameSpace = '_gat';
+ var existingGat = window[nameSpace];
+ if (existingGat && typeof existingGat['_getTracker'] == 'function') {
+ return;
+ }
+
+ var gaqAccounts = [];
+ function setAccount(acct, prefix) {
+ if (gaqAccounts[prefix] != acct) {
+ gaqAccounts[prefix] = acct;
+ _gaq.push([prefix + '_setAccount', acct]);
+ }
+ }
+
+ window['_modpagespeed_getRewriteTracker'] = function(tracker_acct,
+ tracker_name) {
+ var prefix = tracker_name ? tracker_name + '.' : '';
+
+ function deferTrackerFunc(fn) {
+ return function() {
+ setAccount(tracker_acct, prefix);
+ var pushArgs = [fn];
+ [].push.apply(pushArgs, arguments);
+ _gaq.push(pushArgs);
+ };
+ }
+ var pageTrackerMethodNames = [
+ '_trackPageview',
+ '_trackEvent',
+ '_trackTrans',
+ '_addIgnoredOrganic',
+ '_addIgnoredRef',
+ '_addItem',
+ '_addOrganic',
+ '_addTrans',
+ '_clearIgnoredOrganic',
+ '_clearIgnoredRef',
+ '_clearOrganic',
+ '_clearXKey',
+ '_clearXValue',
+ '_cookiePathCopy',
+ '_deleteCustomVar',
+ '_link',
+ '_linkByPost',
+ '_sendXEvent',
+ '_setAllowAnchor',
+ '_setAllowHash',
+ '_setAllowLinker',
+ '_setAutoTrackOutbound',
+ '_setCampCIdKey',
+ '_setCampContentKey',
+ '_setCampIdKey',
+ '_setCampMediumKey',
+ '_setCampNOKey',
+ '_setCampNameKey',
+ '_setCampSourceKey',
+ '_setCampTermKey',
+ '_setCampaignCookieTimeout',
+ '_setCampaignTrack',
+ '_setClientInfo',
+ '_setCookiePath',
+ '_setCookiePersistence',
+ '_setCookieTimeout',
+ '_setCustomVar',
+ '_setDetectFlash',
+ '_setDetectTitle',
+ '_setDomainName',
+ '_setHrefExamineLimit',
+ '_setLocalGifPath',
+ '_setLocalRemoteServerMode',
+ '_setLocalServerMode',
+ '_setMaxCustomVariables',
+ '_setNamespace',
+ '_setReferrerOverride',
+ '_setRemoteServerMode',
+ '_setSampleRate',
+ '_setSessionCookieTimeout',
+ '_setSessionTimeout',
+ '_setTrackOutboundSubdomains',
+ '_setTrans',
+ '_setTransactionDelim',
+ '_setVar',
+ '_setVisitorCookieTimeout',
+ '_setXKey',
+ '_setXValue'
+ ];
+ var pageTracker = {
+ _initData: function() {},
+ };
+ for (var i=pageTrackerMethodNames.length; i--;) {
+ var n = pageTrackerMethodNames[i];
+ pageTracker[n] = deferTrackerFunc(prefix + n);
+ }
+ return pageTracker;
+ };
+
+ 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 {