Google Analytics provides an overwhelming quantity of information. If you do nothing but add the tracking script to your pages, you’ll be faced with an endless stream of data and reports about user activity on your site. However, while Analytics shows exit pages it won’t tell you which links users clicked to leave your site. In this article we’ll discover how to add outbound link tracking.

Does Google Record Outbound Links?

Probably. If you’re linking from one site using Analytics to another using Analytics Google could record that relationship. Unfortunately, reports would be misleading if one or more outbound sites didn’t use Analytics.

Google has additional means of collecting data: you can gather a lot of statistics when you own the top browser and search engine! But we’re then moving away from on-site Analytics into more dubious territory; Google wouldn’t necessarily want to share that data.

Fortunately, we can gather outbound link details ourselves.

Upgrade to Universal Analytics First!

Before we go any further, you must upgrade to Universal Analytics. Google has possibly started this process for you but the tracking code must be updated on your website pages. It’s a pain, but the outbound link tracking code shown below won’t work without it. (It could be made to work with legacy Analytics, but it’ll eventually stop working so it’s best to upgrade now.)

Custom Event Tracking

Analytics supports event tracking. Typically, it’s used for recording on-page JavaScript-controlled interactivity such as opening a widget or making an Ajax call. We can use event tracking to record outbound links but there are a number hurdles to overcome:

  • the event must be recorded on all browsers and not impede navigation
  • we should not need to manually identify or attach separate handlers to every outbound link, and
  • we must ensure the event is recorded before the outbound page starts to load.

The solution…

  1. We’ll attach a click event handler to the body element. This will receive an clicked-link events as they bubble up through the DOM.
  2. We can detect whether a link will open a page on a domain which is different to ours. If it’s an outbound link, we’ll cancel the click event and initiate Analytics event tracking.
  3. In the background, Analytics sends data by requesting an image beacon. Once the call is complete, it can run a callback function so we can redirect to the outbound page.
  4. We need to be careful and ensure tracking never stops user navigation even on failure. The process must be fast, not handle clicks which have been deactivated by other processes and ensure links work even if the Analytics event fails.

We want tracking to work everywhere so I recommend using a library with robust cross-browser event handling. I’ll use jQuery 1.x for this example since most sites use it but you can substitute a lightweight option such as min.js, Zepto.js, Minified.js or your own event handling functions.

The full code is shown below. This can be added to existing JavaScript files or in a script block as long as it’s loaded somewhere within the HTML body (ideally, just before the closing tag). jQuery (or your alternative) must be loaded first although the Google Analytics tracking code can appear anywhere on the page.

/* Track outbound links in Google Analytics */
(function($) {

  "use strict";

  // current page host
  var baseURI = window.location.host;

  // click event on body
  $("body").on("click", function(e) {

    // abandon if link already aborted or analytics is not available
    if (e.isDefaultPrevented() || typeof ga !== "function") return;

    // abandon if no active link or link within domain
    var link = $(e.target).closest("a");
    if (link.length != 1 || baseURI == link[0].host) return;

    // cancel event and record outbound link
    e.preventDefault();
    var href = link[0].href;
    ga('send', {
      'hitType': 'event',
      'eventCategory': 'outbound',
      'eventAction': 'link',
      'eventLabel': href,
      'hitCallback': loadPage
    });

    // redirect after one second if recording takes too long
    setTimeout(loadPage, 1000);

    // redirect to outbound page
    function loadPage() {
      document.location = href;
    }

  });

})(jQuery); // pass another library here if required

The event is recorded with the category name ‘outbound’, action name ‘link’ and the value set to the URL of the outbound page. You can modify these in the ga call if necessary (lines 24 to 26).

Once implemented, visit your site and click a few outbound links. You should see the activity in the Analytics Real-Time > Events panel. Further data will appear in the Behavior > Events pane after a few hours.

Please use the code as you wish.

Craig is a freelance UK web consultant who built his first page for IE2.0 in 1995. Since that time he's been advocating standards, accessibility, and best-practice HTML5 techniques. He's written more than 1,000 articles for SitePoint and you can find him @craigbuckler

Free Guide:

How to Choose the Right Charting Library for Your Application

How do you make sure that the charting library you choose has everything you need? Sign up to receive this detailed guide from FusionCharts, which explores all the factors you need to consider before making the decision.


  • http://onsman.com/ ronsman

    A very timely article for me, Craig, and clever. I’ll be trying this with a number of client sites – I’ll let you know how it goes.

    • Craig Buckler

      Best of luck, Ricky!

  • Dave Mo

    Recently our website had ga code added to track when PDF or Word documents are accessed. However, the code strips out the ‘target=_blank’ attribute we have on almost all our links (for accessibility/usability reasons) to documents like that. However, the code keeps the ‘title’ attribute that goes along with the target attribute to inform users that “the link they are clicking will open in a new window or tab.” One might see how that would cause confusion for certain users.

    According to the folks who manage the ga aspect of our site, this is a known problem without a solution in the near future. Could this also be a problem with this technique, or am I dealing with a “non-issue” usability/accessibility-wise?

    Thanks

  • http://www.ashnewport.com Ash

    Can you explain a bit more how it selects an anchor element? Seems like it is getting the closest to the click event which may not always be accurate if you don’t actually click an anchor element (just a little lost here).

    Not being a jQuery guru, how does this code track when a user doesn’t click. For example, touch or keyboard access. Could additional events be bound to be inclusive? If so, how would this be approached?

    Could this functionality be expanded to include file tracking? Perhaps by specifying something along the lines of $(“a[href*=’.pdf’], a[href*=’.doc’]) to be tracked when selected.

    I’d be very interested to see this work with the code you have provided or even standalone. Maybe a follow up tutorial?

    Thanks as always for the useful article!

    • Craig Buckler

      Hi Ash. When you click something (the “click” event is still valid on touch screens), the browser applies that event to the element you’re clicking and all parent elements – after all, you’re clicking them too. So if you had a strong element within a link, the browser bubbles the event up starting at strong, then the link, its parent, and all the way up to the body. Therefore, you can detect when a click will fire a redirect to another page.

      You could apply this method to document types such as PDF. You could apply handlers to each link as you’ve shown but you can also do it like I have above (which would be more efficient if you had dozens of PDF links).

  • Craig Buckler

    Yes, this technique would be a solution for parsing document clicks and opening another window. You could even make it better by opening a resized window which is ideal for the document.

    That said, be wary about opening windows. It’s an accessibility faux pas because it’s not always obvious another window opened (especially on mobile devices) and there’s no back button for the user.

    • DaveMo

      Thanks Craig, I’ll point this technique in the direction of our folks and see what they think.

      While I’ve been using the ‘target=”_blank”‘ attribute for years for documents and outbound links (and always with the ‘title’ attribute) under the belief that it was good usability practice, I’m beginning to rethink that strategy in light of comments like yours and research into the practice. However, I haven’t been able to find a definitive opinion on the subject and so I haven’t quite made up my mind on dropping the practice (we’re a government website and have hundreds, if not thousands of PDF forms and doucuments, so I’d have a lot of links to fix if I did!).

      On the other hand, our site uses A LOT of Bootstrap and jQuery functions now, in particular accordion lists. I’m finding with the current situation when the document opens in the same window and I back-button out of it, I’m dumped back at the top of the page and have to scroll down and reopen the accordion list to access any other documents or text related to it that may be at that particular spot in the list. Or at least that’s how it functions with me.

      Thanks again!

  • Craig Buckler

    If I recall correctly, IBM did a series of tests like this several years ago and concluded that the back button was the only control users really understood. Many didn’t understand the OS taskbar, window placement, resizing, etc.

    In general, I would say few (good) sites open windows these days because it’s considered to be bad practise. Most browsers also open PDFs directly now so it’s not as though you’re switching application.

  • Brandon Luhring

    We created a custom jQuery selector for the items we wanted to track… Mailto links, recognized downloadable files, and outbound links primarily. We then added click events to the items that jQuery recognized via those custom selectors. It actually works very nicely in that you can simultaneously add classes to those links for styling or further javascript use. Something along the lines of $(“a:outbound”).addClass(“outboundLnk”).click(myTrackingFunction()); Then in myTrackingFunction, we track the event in Google Analytics as described in this article. …just another option.

  • Craig Buckler

    It’s certainly a less infallible method because you’re tagging all the links you want to track regardless of type. The disadvantage is that you must manually add that tracking class and performance could be affected if you had many hundreds on the page.

  • http://www.andressmerkin.com/ Andrés Smerkin

    So this appears as a different event category. Is there a way to see them within the Exit Pages?

  • http://www.favoritecandle.com Art

    I looked at 20+ example implementations on the web for tracking outbound links in GA. Craig, your script is the most elegant and efficient I found and with a minimum of code. Other “experts” had javascript that looped through all a tags and others just had overly complex and lengthy scripts to accomplish nothing more than you’ve done in just 10 lines.

    I installed your code and voila, my outbound link tracking was immediately working like a charm.

    Thanks for putting this up!

  • http://tool-rank.com/ Quiglag

    target=”_blank” seems to stop working with this code enabled.

  • Bman

    So this code does not track outbound links that are opened in a new window (_blank)? How can those links also be tracked?

  • Chris

    Very easy to understand article, compared to others. While this definitely solves the problem of tracking all outbound clicks, would you use a variation of this code, or some entirely different code, to track only outbound links that were assigned a specific class? I.e. if you wished to set up different events for tracking social clicks vs. outbound clicks to another website. Thanks for the post and your time!

  • naomi fridman

    I need the outbound page to open in new window, _blank.

    I changed

    document.location = href;

    to

    window.open(href);

    But that opens 2 new pages!! if the original link was defined in the html _blank

    any ideas will be very wellcome

  • Cristian Bitoi

    This will not work for Internet Explorer 9, 8 because of the: `baseURI == link[0].host`. In IE, 9,8 link[0].host will be `:80` so the Codition will allow the ga to register even if the domain are the same. You should use indexOf() for a more permisive condition.

Learn JavaScript for free!
Free course: Introduction to JavaScript

Yours when you take up a free 14-day SitePoint Premium trial.