Found this useful? Love this post

Workaround for when the hitCallback function does not receive a response (analytics.js)

Updated with common adblockers / privacy filters (Jan 2014)

I’ve found in some circumstances when sending a command using Google Universal analytics.js, code sitting inside the hitCallback function does not execute.

So it might appear that the hitCallback function isn’t working. Well actually, it’s working just fine (sort-of).

It turns out I had an AdBlocker running which prevented analytics.js from sending the data, and as result, the hitCallback function not firing.

A number of most common AdBlockers / Browser Privacy filters used are:

If you’re having issues, I’d suggest you start debugging with Ghostery first, this software is the most comprehensive analytics blocker out the there listed.

I had a look at the ga object. This is what it looks like when it loads successfully:

analytics.js ga object in it's successfully loaded state.

And what it looks like when it doesn’t load:

analytics.js ga object when it doesn't load

Based on this, I developed the quick solution below:

var url = "http://www.domsammut.com/";

/*
 * Simply checks that the loaded property exists 
 * and that it has a value of true. 
 */
if (ga.hasOwnProperty('loaded') && ga.loaded === true) {

    //Success, ga is loaded

    ga('send', 'event', {
        'eventCategory' : 'Outbound',
        'eventAction' : 'Link',
        'eventLabel' : url,
        'eventValue' : 1,
        'hitCallback' : function () {
            document.location = url;
        }
    });

} else {

    //Not loaded, continue without tracking the data
    document.location = url;

}

While in the past, if a user hasn’t been able to load Google Analytics, it hasn’t been a major concern as the send command fails silently. While this is still the case with analytics.js, you can hook code into Google Analytics that is dependant on successfully completing the send command.

Note: This doesn’t solve the problem above, since the analytics.js script was not able to load at all.

Ideally, Google would expand this function so that you could pass a timeout value to execute your function regardless.

ga('send', 'event', {
    'eventCategory' : 'Outbound',
    'eventAction' : 'Link',
    'eventLabel' : url,
    'eventValue' : 1,
    'hitCallbackTimeout' : 500, // ms
    'hitCallback' : function () {
        document.location = url;
    }
});

Or have another function that gets triggered after X seconds with no response (time either defined by Google or optionally overridden by user).

ga('send', 'event', {
    'eventCategory' : 'Outbound',
    'eventAction' : 'Link',
    'eventLabel' : url,
    'eventValue' : 1,
    'hitCallback' : function () {
        document.location = url;
    },
    'hitCallbackFail' : function () {
        alert("Unable to send Google Analytics data");    
    }
});

In the mean time, hopefully this solution helps you out a little.

Subscribe

You'll only get 1 email per month containing new posts (I hate spam as much as you!). You can opt out at anytime.

Categories

Leave a Reply to Lawrence Lagerlof Cancel reply

Your email address will not be published. Required fields are marked *

Preview Comment

9 Comments

  1. Steven
    https://www.domsammut.com/?p=675#comment-1983

    Steven

    Hi,

    Many thanks for your post which helped me get across :)

    In my case, I had to check if ga actually existed and was an object or it would blow.
    So I ended up with this check: if (typeof ga === ‘object’ && ga.hasOwnProperty(‘loaded’) && ga.loaded === true)

  2. Lawrence Lagerlof
    https://www.domsammut.com/?p=675#comment-1949

    Lawrence Lagerlof

    I was going crazy with the hitCallback redirection not working. In my case, uBlock Origin was the problematic ad blocker.

    Thanks.

    • Dom Sammut
      https://www.domsammut.com/?p=675#comment-1950

      Dom Sammut

      Thanks for this Lawrence, I’ve added this to the list of possible interfering trackers :)

  3. Enrico L
    https://www.domsammut.com/?p=675#comment-1734

    Enrico L

    Thanks a lot for this post. You saved me a lot of time!

  4. sghegde87
    https://www.domsammut.com/?p=675#comment-261

    sghegde87

    Thank you for sharing this idea. It really helps. Subscribed!!

  5. Terry Burton
    https://www.domsammut.com/?p=675#comment-79

    Terry Burton

    I have seen occasions where the analytics.js is loaded but the GA send event is filtered. Therefore I would suggest refining the code by adding a backup routine that is triggered by setTimeout:

    var trackOutboundLink = function(link) {
        if (ga.hasOwnProperty('loaded') && ga.loaded === true) {
            setTimeout(function() {
                document.location.href = link.href;
            }, 1000);
            ga('send', 'event', 'outbound', 'click', link.href, {'hitCallback':
                function () {
                    document.location.href = link.href;
                }
            });
        } else {
            document.location.href = link.href;
        }
    }
    

    Invoked using:

    ...
    

    Example page at http://bwipp.terryburton.co.uk/

    As an aside, the nice thing about using "trackOutboundLink(this);return false;" is that you can decorate all external <a> tags with this onclick method with a DOMContentLoaded event handler.

    • Dom Sammut
      https://www.domsammut.com/?p=675#comment-80

      Dom Sammut

      Good idea Terry regarding the timeout fallback. Do you have an example / scenario on how to reproduce the issue? I’ve yet to see this happen before under normal circumstances (Normal circumstances being Google Analytics initialising and a persistent internet connection).

      • Terry Burton
        https://www.domsammut.com/?p=675#comment-81

        Terry Burton

        I had two users reporting that my “links were broken” within a week of switching a high-volume site over to using a callback solution similar to your own.

        One individual was using their own laptop on a corporate network and the other was browsing from a wifi hotspot. So this would likely indicate interference by an application layer proxy.

        • Dom Sammut
          https://www.domsammut.com/?p=675#comment-84

          Dom Sammut

          Ah okay. So was the Google Analytics script able to be initialised? It would seem odd that they could make a request to get the analytics.js script and have it initialised but then not make the get request for the event. The script and the get request are both made to the same domain google-analytics.com. If you have ga('require', 'displayfeatures');, it will make requests to stats.g.doubleclick.net, that could cause the hitCallback not to fire if doubleclick.net is blocked and hence can’t successfully make the get request. Good to know though, I think the setTimeout is a prudent measure to add in case it fails for some reason though.

css.php