Track outbound links with Google Universal Analytics.js

Jun 15, 2016 JavaScript
If you are using gtag.js (and not analytics.js), then see this tutorial instead.

This guide describes how to track outgoing links using Google Universal Analytics or commonly known as Analytics.js - the new tracking that Google provides webmasters since 2013.

The best method of “auto-tracking” outgoing links is to automatically detect outbound links with JavaScript when they are clicked, and automatically track it as an event. The method below uses a “hitCallback” function that, once the click has been registered with Analytics, the link is opened. This prevents the situation whereby the browser starts opening the new page before Analytics has had a chance to register the click. This method is by far the most robust, and simply means you need to include an external JavaScript file on your pages.

Features

  • Tracks all outgoing links as events in Google Analytics, including outbound link & referring page
  • Uses callbacks to first track and then redirect when outbound link opens in current window
  • Detects and works with Ctrl/Shift/Meta & middle-mouse clicks
  • Works around the IE bug where Ctrl-clicks bypass JavaScript calls by using mousedown events rather than click (except for touchscreen devices)

Tracking script

<script>
    function _gaLt(event) {

        // if GA is blocked or not loaded, or not main|middle|touch click then don't track
        if (!ga.hasOwnProperty("loaded") || ga.loaded != true || (event.which != 1 && event.which != 2)) {
            return;
        }

        var el = event.srcElement || event.target;

        // loop up the DOM tree through parent elements if clicked element is not a link (eg: an image inside a link)
        while (el && (typeof el.tagName == 'undefined' || el.tagName.toLowerCase() != 'a' || !el.href)) {
            el = el.parentNode;
        }

        // if a link with valid href has been clicked
        if (el && el.href) {

            var link = el.href;

            // only if it is an external link
            if (link.indexOf(location.host) == -1 && !link.match(/^javascript\:/i)) {

                // is target set and _(self|parent|top)
                var target = (el.target && !el.target.match(/^_(self|parent|top)$/i)) ? el.target : false;

                // assume a target if Ctrl|shift|meta-click
                if (event.ctrlKey || event.shiftKey || event.metaKey || event.which == 2) {
                    target = "_blank";
                }

                var hbrun = false; // tracker has not yet run

                // hitBack to open link in same window after tracker
                var hitBack = function() {
                    // run once only
                    if (hbrun) return;
                    hbrun = true;
                    window.location.href = link;
                };

                if (target) { 
                    // if target opens a new window then just track
                    ga(
                        "send", "event", "Outgoing Links", link,
                        document.location.pathname + document.location.search
                    );
                } else { 
                    // prevent standard click, track then open
                    if (event.type == 'mousedown') {
                        var blockClick = function (event) {
                            event.preventDefault();
                            // remove click event after click
                            el.removeEventListener('click', boundClick);
                        }
                        // bind the click event
                        var boundClick = blockClick.bind(event)
                        // prevent the click
                        el.addEventListener('click', boundClick);
                    }
                    event.preventDefault ? event.preventDefault() : event.returnValue = !1;
                    // send event with callback
                    ga(
                        "send", "event", "Outgoing Links", link,
                        document.location.pathname + document.location.search, {
                            "hitCallback": hitBack
                        }
                    );

                    // run hitBack again if GA takes longer than 1 second
                    setTimeout(hitBack, 1000);
                }
            }
        }
    }

    var _w = window;
    /* Use "click" if touchscreen device, else "mousedown" */
    var _gaLtEvt = ("ontouchstart" in _w) ? "click" : "mousedown";
    /* Attach the event to all clicks in the document after page has loaded */
    _w.addEventListener("load", function() {document.body.addEventListener(_gaLtEvt, _gaLt, !1)}, !1);
</script>

Comments