Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to wait until tracking scripts have fired before redirecting the user?

I run a typical price comparison website, where the user browses products, then clicks on a link to go to the merchant's website.

Before being redirected to the merchant's website, the user is presented with a "we are redirecting you..." page.

This page is only there to allow tracking codes (Google Analytics, Adwords, Bing Ads...) to track the event.

I've placed the tracking codes right before the closing </body> tag, to avoid blocking the rendering of the page while the scripts are loaded.

I'm redirecting the user with a meta refresh tag:

<meta http-equiv="refresh" content="0; url=...">

It seems to work alright, but I'm worried that, depending on the browser / speed of the internet connection, the redirect can happen before the tracking scripts have fired.

I could just delay the redirect for a few seconds to be on the safe side, but I want to keep the experience smooth for the user.

I could also include the scripts in the <head>, but:

  • This would delay the display on the "redirecting..." page while the scripts are loaded
  • This would not guarantee that the tracking scripts have done their job before the user is redirected: the tracking script is first loaded, then triggers another action asynchronously to track the event.

How can I guarantee that the tracking scripts have done their jobs, while still redirecting the user ASAP?

Any feedback on a similar experience will be appreciated.

like image 704
BenMorel Avatar asked Sep 21 '15 09:09

BenMorel


4 Answers

For Google analytics there is an official way to do this by tracking outbound links as 'events'. You need to set up an onclick function as below, and Google will call a callback when it has received the analytics message.

js

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-0000000-5', 'auto');
ga('send', 'pageview');

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

html

<a href='<url>' onclick="trackOutboundLink('<url>'); return false;'>buy me now</a>"

return false prevents the link being followed as such, and leaves it to trackOutboundLinks to redirect to the new Url when called back by GA.

Let me know if you need more. For example I use more granularity in my event calls to distinguish between links to the websites of the product and websites where you can purchase.

like image 139
Simon H Avatar answered Sep 17 '22 23:09

Simon H


TL;DR In short, every library has their own way of tracking users. You should handle every library differently and redirect when they all finished. Below, I've explained the different ways of tracking I could think of on the top of head. Especially, pay attention to the beacons part, I haven't seen it between the answers here, though it will be used more and more in the future I think.

This actually depends on the way other parties track the users. In general, I think there are three kind of ways to track a user. JavaScript, images and (maybe) iframes. Some methods allow you to check if the tracking is done. I'll try to explain the different methods. In short, per 3rd party you'll have to check if they finished tracking the user and redirect when all have finished (using window.location).

1. Javascript

In JavaScript, tracking can be implemented in different ways. I can think of 4 different methods on the top of my head. I'll try to explain how you can track if everything is loaded and processed correctly.

1.1. Beacons

Beacons are not very well known. It is a new technology, which allows the browser to send small packets of data to the server before the page unloads. Those are the easiest to handle. At the moment the page has unloaded (so after the redirect is initiated) they can still send their final data to the server. In short, don't worry to much about this way.

(But be aware, this is not yet supported in every browser. If you want to read more about it, please see https://developer.mozilla.org/en-US/docs/Web/API/Navigator/sendBeacon . I'm not sure, but I thought Google Analytics was using this).

1.2. AJAX Requests

The AJAX requests are the most difficult. I see others have suggested $.ajaxComplete from the jQuery library. It's worth a try, but I'm not sure if you can catch AJAX calls which are made from scripts that are loaded from a different domain. From the same domains should work, I've used this myself to keep track of the AJAX calls on a page. You could test this however. Take two domains. On the first domain, use jQuery to catch the AJAX calls. On the second domain, host a file which makes an AJAX call (without using jQuery). This way, you should be able to find out if this works.

Otherwise, you should check if the libraries have a callback method for their tracking methods. Once this callback is called, you can assume the tracking part has finished.

1.3. Append image

With JavaScript, it is also possible to append an image tag to the HTML. In short, see the section below about tracking images. But, you will need to write some small piece of JavaScript to detect the tracking pixel which is appended. I think most libraries will add something to the image so you can identify them with JS.

1.4. Append iframe

Of course, appending an iframe is also an option. I don't think it will be used that often in combination with JavaScript, but the idea should be the same as with the tracking pixels.

2. Images

Images should not be that difficult. If you place the images in the body yourself, add a certain class or ID and use jQuery's load event. Again, I'm not sure this will always launch, but there are ways which can make you sure it does. For example, see this questions on SO: Check if an image is loaded (no errors) in JavaScript

For the tracking pixels append with JavaScript, if the always use a certain class, you write some JavaScript right after the <body> tag. For example:

<body>
<script type="text/javascript">
    $(document).on('load', '.trackingPixelClass', function () {
        // increase counter and check if every tracking work is done
    });
</script>

3. IFrames

IFrames should be the same as tracking if images are done. This should work, but I'm not a 100% certain what happens if the iframe loads content from another domain. Browsers might think this is a security risk.

like image 42
M. Dekker Avatar answered Sep 17 '22 23:09

M. Dekker


There are a few solutions that come to my mind, I'll show you the one I think it fits best for your case.

Although, there is one single pre-requisite for this solution to work: you must take a look what their code does, so you can figure out what global object is created when the script is run. All those tracking codes generate global variables, so the code below should work as a piece of cake.

For example, the Google Analytics creates a ga object, and as soon as it's fully loaded, it creates an answer property with a value 42in this object, so, you could do:

document.addEventListener('DOMContentLoaded', function() {
  function check(arr, callback) {        
    if (arr.filter(function(item) {
      var final = window;
      
      item = item.split('.');
      
      for (var i = 0; i < item.length; i++)
        final = final[item[i]];      
      
      return typeof final !== 'undefined' ? true : false;    
    }).length < arr.length) {
      setTimeout(function() { check(arr, callback) }, 0);
      return;
    }
    callback();
  }

  check(['ga.answer'], function() {
    location.replace('http://www.pudim.com.br/'); // change it to the merchant's website
  });
});

(function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
})(window,document,'script','//www.google-analytics.com/analytics.js','ga');

ga('create', 'UA-0000000-5', 'auto');
ga('send', 'pageview');
Redirecting...

The code above keeps calling a check function until all the elements are already loaded, and then, as soon as they are all available, it immediately redirects the user to the page you want.

Note: You can pute the code above anywhere in your page (better to put it inline than in a separate file).

like image 31
Buzinas Avatar answered Sep 16 '22 23:09

Buzinas


The answer really depends on what "trackers" you use. Some of them use asynchronous calls which are hard to track.

Your best bet is to check if all of them provide callbacks and hen count them, and if they all fire use javascript window.location to redirect user instead of meta-refresh.

Another option would be to check which elements appear when those scripts finish loading, then wait either till they all appear or preset max number of seconds and redirect the user.

like image 35
Marcin Raczkowski Avatar answered Sep 16 '22 23:09

Marcin Raczkowski