Tracking outbound links with Google Analytics
The Google Analytics help has an entry that explains how to track clicks on outbound links. It uses the following JavaScript function:
var trackOutboundLink = function(url) {
ga("send", "event", "outbound", "click", url, {"hitCallback":
function () {
document.location = url;
}
});
}
Links to be tracked need to be modified as follows:
<a href="http://example.com" onclick="trackOutboundLink('http://example.com'); return false;">...</a>
The purpose of the hit callback is to ensure that the event is sent to Google Analytics before the new page starts
loading. This is necessary because the ga
function is asynchronous and loading a new document will stop execution of
JavaScript code for the current document, so that events may be lost. Note that this only applies if the new document
replaces the current document; if the link has a target="_blank"
attribute, then the new document will be loaded in
a new window or tab and using a hit callback is not necessary.
The problem with the approach described in the documentation
is that the visitor may have blocked Google Analytics using a privacy protection tool
such as Ghostery. In general, these tools don’t block execution of the GA tracking code itself, but prevent
analytics.js
from being loaded. This means that the ga
function is defined, but tracking events pushed using that
function are not processed. In this case, the hit callback used by trackOutboundLink
is never executed and clicking
on the link will have no effect. This is bad because it penalizes visitors who don’t want to have their page views
tracked and makes your site appear broken for them.
Note that this problem only arises with tracking events that load a new page in the same window/tab, not with other types of events. The reason is that loading a new page will stop JavaScript execution for the current page. In this case, it is necessary to use a hit callback ensures that the new page is loaded after the tracking event has been processed. In all other cases, it is safe to let the Google Analytics code process the event asynchronously.
To support visitors who use privacy tools we need to find a way to detect whether Google Analytics has been blocked or
not. As shown here, the ga
function defined by the tracking code creates a JavaScript array ga.q
(if it doesn’t
exist yet) and then pushes its arguments onto that array. Once analytics.js
is loaded, it processes the queued events
and replaces ga
by a completely different function, so that ga.q
is no longer defined. During page load at least two
items are added to the queue, one to create the tracker and another one to record the page view. This means that ga.q
is defined only if the tracking code has been executed, but analytics.js
has not been loaded yet. This means that it
is possible to determine if Google Analytics is blocked simply by checking if ga.q
is defined:
var trackOutboundLink = function(url) {
if (ga.q) {
// Google Analytics is blocked
document.location = url;
} else {
ga("send", "event", "outbound", "click", url, {"hitCallback":
function () {
document.location = url;
}
});
}
}
It is safe to assume that this code will continue to work as expected even if Google decides to make changes
to analytics.js
. The reason is that ga.q
is set by the ga
function defined by the tracking code embedded in your
site’s pages and that code can’t be changed unilaterally by Google.
Note that there are at least two other ways to determine whether Google Analytics has been loaded:
-
One option is to check
ga.loaded
as described here. Note that this doesn’t appear to be documented anywhere in the Google Analytics documentation, although it is indeed used in a recently added example. -
The other option is to set a global variable in a get parameter callback. This approach leverages the fact that the callback is called once the Google Analytics library has finished loading.
Finally, if you are using require.js, you may want to try an entirely different approach that I described in another article.
The other drawback of the approach described in the Google Analytics help is that the way links need to be modified
isn’t particularly elegant. Instead of having to add an onclick
attribute to every tracked link one would probably
prefer a solution that only requires adding a style class:
<a href="http://example.com" class="tracked">...</a>
With jQuery this is easy to implement:
$(function() {
$("a.tracked").click(function(e) {
if (!ga.q) {
var url = $(this).attr("href");
ga("send", "event", "outbound", "click", url, {"hitCallback":
function () {
document.location = url;
}
});
e.preventDefault();
}
});
});