Race condition and using Google Analytics Asynchronous (_gaq) synchronously

試著忘記壹切 提交于 2019-11-27 20:10:23

You're right. If the browser leaves the page before it sends the GA tracking beacon (gif hit) for the event, the event will not be recorded. This is not new to the async code however, because the process of sending the tracking beacon is asynchronous; the old code worked the same way in that respect. If tracking is really that important, you could do something like this:

function track(link) {
  if (!_gat) return true;
  _gaq.push(['_trackEvent', 'stuff']);
  setTimeout(function() {location.href=link.href'}, 200);
  return false;
}

...

<a href="example.com" onclick="return track(this);"></a>

This will stop the browser from going to the next page when the link is clicked if GA has been loaded already (it's probably best to not make the user wait that long). Then it sends the event and waits 200 milliseconds to send the user to the href of the link they clicked on. This increases the likelihood that the event will be recorded. You can increase the likelihood even more by making the timeout longer, but that also may be hurting user-experience in the process. It's a balance you'll have to experiment with.

I've got this problem too, and am determined to find a real solution.

What about pushing the function into the queue?

  // Log a pageview to GA for a conversion
  _gaq.push(['_trackPageview', url]);
  // Push the redirect to make sure it happens AFTER we track the pageview
  _gaq.push(function() { document.location = url; });

From Google's documentation for universal analytics (new version since most other answers for this question). You can now easily specify a callback.

var trackOutboundLink = function(url) {
   ga('send', 'event', 'outbound', 'click', url, {'hitCallback':
     function () {
     document.location = url;
     }
   });
}

For clarity I'd recommend using this syntax, which makes it clearer which properties you're sending and easier to add more :

            ga('send', 'event', {
                'eventCategory': 'Homepage',
                'eventAction': 'Video Play',
                'eventLabel': label,
                'eventValue': null,

                'hitCallback': function()
                {
                    // redirect here
                },

                'transport': 'beacon',

                'nonInteraction': (interactive || true ? 0 : 1)
            });

[Here's a complete list of parameters for all possible ga calls.]

In addition I've added the transport parameter set to beacon (not actually needed because it's automatically set if appropriate):

This specifies the transport mechanism with which hits will be sent. The options are 'beacon', 'xhr', or 'image'. By default, analytics.js will try to figure out the best method based on the hit size and browser capabilities. If you specify 'beacon' and the user's browser does not support the navigator.sendBeacon method, it will fall back to 'image' or 'xhr' depending on hit size.

So when using navigator.beacon the navigation won't interrupt the tracking . Unfortunately Microsoft's support for beacon is non existent so you should still put the redirect in a callback.

In event handler you should setup hit callback:

_gaq.push(['_set', 'hitCallback', function(){
  document.location = ...
}]);

send you data

_gaq.push(['_trackEvent'

and stop event event processing

e.preventDefault();
e.stopPropagation();

I'm trying out a new approach where we build the URL for utm.gif ourselves, and request it, then only once we've received the response (the gif) we send the user on their way:

Usage:

  trackPageview(url, function() { document.location = url; });

Code (CrumbleCookie from: http://www.dannytalk.com/read-google-analytics-cookie-script/)

/** 
 * Use this to log a pageview to google and make sure it gets through
 * See: http://www.google.com/support/forum/p/Google%20Analytics/thread?tid=5f11a529100f1d47&hl=en 
 */
function trackPageview(url, fn) {
  var utmaCookie = crumbleCookie('__utma');
  var utmzCookie = crumbleCookie('__utmz');

  var cookies = '__utma=' + utmaCookie + ';__utmz=' + utmzCookie;

  var requestId = '' + (Math.floor((9999999999-999999999)*Math.random()) + 1000000000);
  var hId = '' + (Math.floor((9999999999-999999999)*Math.random()) + 1000000000);

  var utmUrl = 'http://www.google-analytics.com/__utm.gif';
  utmUrl += '?utmwv=4.8.9';
  utmUrl += '&utmn=' + requestId;
  utmUrl += '&utmhn=' + encodeURIComponent(window.location.hostname);
  utmUrl += '&utmhid=' + hId;
  utmUrl += '&utmr=-';
  utmUrl += '&utmp=' + encodeURIComponent(url);
  utmUrl += '&utmac=' + encodeURIComponent(_gaProfileId); 
  utmUrl += '&utmcc=' + encodeURIComponent(cookies);

  var image = new Image();
  image.onload = function() { fn(); };
  image.src = utmUrl;
}

/**
 *  @author:    Danny Ng (http://www.dannytalk.com/read-google-analytics-cookie-script/)
 *  @modified:  19/08/10
 *  @notes:     Free to use and distribute without altering this comment. Would appreciate a link back :)
 */

// Strip leading and trailing white-space
String.prototype.trim = function() { return this.replace(/^\s*|\s*$/g, ''); }

// Check if string is empty
String.prototype.empty = function() {
    if (this.length == 0)
        return true;
    else if (this.length > 0)
        return /^\s*$/.test(this);
}

// Breaks cookie into an object of keypair cookie values
function crumbleCookie(c)
{
    var cookie_array = document.cookie.split(';');
    var keyvaluepair = {};
    for (var cookie = 0; cookie < cookie_array.length; cookie++)
        {
        var key = cookie_array[cookie].substring(0, cookie_array[cookie].indexOf('=')).trim();
        var value = cookie_array[cookie].substring(cookie_array[cookie].indexOf('=')+1, cookie_array[cookie].length).trim();
        keyvaluepair[key] = value;
    }

    if (c)
        return keyvaluepair[c] ? keyvaluepair[c] : null;

    return keyvaluepair;
}

Using onmousedown instead of onclick may also help. It doesn't eliminate the race condition, but it gives GA a head start. There's also the concern of someone clicking on a link and dragging away before letting go of the mouse button, but that's probably a negligible case.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!