A Different Approach to Cross-Domain Tracking

Most analytic tools use cookies to identify visitors. However, data stored in cookies is only visible in the domain in which the cookies were set/defined – which is a serious problem if your site cuts across multiple domains. If, for example, your visitor is presently on domain2.com, then your analytic tool will not be able to read data stored on domain1.com, nor will it be able to link between the two visits – thereby your one single visitor will be counted as two separate visitors.

 

There are two traditional methods to overcome the multi-domain issue:

 

  • User Identification – Most analytic tools (including the new version of Google Analytics) allow you to link activity to a specific user using your own user identification. If you choose to go with this method, then once your user logs in to any of your domains, you can tell your analytic tool to credit all activity (on that domain) to the identified user from now on. This method bypasses the above mentioned cookie issue, as your analytic tool does not have to obtain the visitor ID from the cookies.
    Disadvantage: Your visitors need to identify themselves, in order to be tracked correctly.
  • Cross-Domain Linking – By enabling the cross domain linking, you can tell your analytic tool to pass the relevant data between your domains. In a nutshell, if your analytic tool identifies a visitor as visitor “123” and stores this information in cookies, then when that visitor clicks on a link to a different domain – the visitor ID (“123”) will be passed as a parameter to the other domain and the analytic tool will read that information from the URL parameters – rather than from the cookies.
    Disadvantage: The downside of this method is that it only covers visitors who switch between domains via links on your sites.

Unfortunately, both methods described above are not perfect as they only solve part of the problem – mainly because your visitors can always switch between domains using methods that are not in your control. For example, let’s say you have a multilingual site with an English version on domain.com and a French version on domain.fr. Your French visitors, however, especially from organic and social sources, could end up on your .com site and be counted as new visitors – even though they have in fact already visited your French domain before.

 

But fear not! A different approach altogether could provide a great solution:

 

The Centralized Domain Method

Using this method, all you have to do is have one domain that is responsible for (1) Assigning new IDs to new visitors, and (2) Identifying returning visitors. The idea is that a new visitor to a domain (a visitor without a user ID in their cookies) will be transferred to a centralized domain in order to be identified. Once identified, they will be redirected back to the domain originally visited together with their new allocated ID.

 

Let’s look at a the following scenario of visitor who visits a site with 2 domains (a.com and b.com).

  • A new visitor (User X) visits a.com
  • A week later, the same visitor visits b.com
  • A week after that, the same visitor visits a.com again


In this example, the domain c.com is the Centralized Domain.

 

  1. A new visitor (User X) visits a.com
  2. A week later, the same visitor visits b.com
  3. A week after that, the same visitor visits a.com again

Now, in order to redirect the visitor from one domain to another without affecting the user experience, I suggest using a hidden iframe. There are two downsides to this method, however, but it is still a good option:

  1. Third Party Cookies – Since c.com sets a cookie from within an iframe, browsers will condiser it as a third party cookie (i.e., a cookie that is set in one domain from within a page that is hosted on a different domain). Unfortunately, some browsers do not allow 3rd party cookies as a default, while others only allow it if a compact policy is set on the domain (such as Internet Explorer).
    Please note: If the user blocks 3rd party cookies, or if you do not have a compact policy on that domain, this method will not work. In such a case, I suggest that you use one of the 2 methods described in the beginning of this post (as a fallback). Using your most popular site (for example, a.com) as the centralized domain will also help.
  2. Data Accuracy – This “round trip” from one domain to the centralized domain and back again might take a bit longer than usual because you have to add two more calls to the page – but shouldn’t take more than a few seconds. In addition, if the user leaves the page before the round trip is complete, then the pageview will not be counted. The trivial solution is therefore to have a separate analytic account for tracking all visitors – before they are identified by the centralized domain.
    Some might argue about the value (or lack thereof) of users who only come to your site for a second and leave, but if they are important to your analytics, then having a separate analytics account for gathering data about each and every visitor upon arrival at your site will allow you to track all users.

Now that we’ve understood the pros and cons of the Centralized Domain Method, let’s see how to implement it:

Implementing the Centralized Domain Method on your sites:

This method can be implemented with any number of analytic tools that let you set your own user identification, such as Mixpanel and KISSmetrics, but I will demonstrate how to implement this method using Google Universal. If you have any questions please feel free to contact me.

 

Using the example from earlier, a.com and b.com are the sites and c.com is the centralized domain.

 

And just to make things clearer, here is the complete flow:

 

  1. The first thing you have to do (on a.com and b.com) is check if you can identify the user without going to the centralized domain: Look for the _ga cookie (where Google Universal stores the user ID). If _ga is presented, then you can assume that this user has already visited your site in the past and then there is no need to go to the centralized domain.[javascript highlight=”4,8″]
    // Google Universal tracking code
    (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’);if (document.cookie.match(/(?:^| )_ga=[^;]/)) {
    // returning user. create a tracker and send pageview
    ga(‘create’, ‘UA-XXXXXX-Y’);
    ga(‘send’, ‘pageview’);
    }
    [/javascript]
  2. If, however, _ga is not presented, call c.com to get the user ID. Place a file on c.com that is responsible for obtaining the user ID, or assign a new user ID and send it back to the original domain.For the sake of this example, let’s assume you have jQuery on your site and use it to detect when the page is ready. [If you do not have jQuery, you can check out this project (cross browser DOM readiness detection) or find other solutions online.][javascript highlight=”8,9,10,11,12,13,14″]
    // Google Universal tracking code
    (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’);if (document.cookie.match(/(?:^| )_ga=[^;]/)) {
    // returning user. create a tracker and send pageview
    ga(‘create’, ‘UA-XXXXXX-Y’);
    ga(‘send’, ‘pageview’);
    } else {
    jQuery(function() {
    var iframe = document.body.appendChild(document.createElement("iframe"));
    iframe.src ="//www.c.com/get-userid.html?redirect="+
    document.location.protocol+"//"+document.domain+
    ((document.location.port != "") ? ":"+document.location.port : "");
    });
    }
    [/javascript]
  3. Now let’s place the necessary code on c.com (the centralized domain). Create a file called get-userid.html using the following code:[javascript highlight=”1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17″]
    <script>
    // Google Universal tracking code
    (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’);// make sure to use the same web property
    ga(‘create’, ‘UA-XXXXXX-Y’);

    ga(function(tracker) {
    var clientId = tracker.get("clientId");

    // get the url to redirect the user now that we have the user id.
    if (document.location.search.match(/[&\?]redirect=([^&]*)/)) {
    var redirectto = document.location.search.match(/[&\?]redirect=([^&]*)/)[1];
    document.location.href = redirectto+"/set-userid.html?clientId="+clientId;
    }
    });
    </script>
    [/javascript]

  4. At this stage, you have to prepare the page on a.com and b.com that will accept the user ID. To do so, create a file called set-userid.html and place it on both a.com and b.com[javascript highlight=”1,2,3,4,5,6,7″]
    <script>
    try {
    var clientid = document.location.search.match(/[&\?]clientId=([^&]*)/)[1];
    parent.setClientId(clientid);
    } catch (e) {
    }
    </script>
    [/javascript]
  5. To close the loop, add the setClientId function to the original page – a function that will be called by set-userid.html.[javascript highlight=”16,17,18,19,20,21″]// Google Universal tracking code
    (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’);

    if (document.cookie.match(/(?:^| )_ga=[^;]/)) {
    // returning user. create a tracker and send pageview
    ga(‘create’, ‘UA-XXXXXX-Y’);
    ga(‘send’, ‘pageview’);
    } else {
    jQuery(function() {
    var iframe = document.body.appendChild(document.createElement("iframe"));
    iframe.src ="//www.c.com/get-userid.html?redirect="+
    document.location.protocol+"//"+document.domain+
    ((document.location.port != "") ? ":"+document.location.port : "");
    });
    }
    function setClientId(clientId) {
    ga("create", "UA-XXXXXX-Y", {
    "clientId":clientId
    });
    ga(‘send’, ‘pageview’);
    }
    [/javascript]

That’s it! I’ll quickly run through the stages to summarise:

  1. Place the following file on your centralized domain (right-click the link and then click “Save link as…”)
  2. Place the following file on your sites’ domains
  3. On each page of your site, amend the default Google Universal code to include a call to the centralized domain and add a function to send a pageview once the visitor is identified by the centralized domain. Here is a sample code.

In addition, please remember to:

  • Set the web property ID in each of the files.
  • Specify the centralized domain in the main code (which is currently set to www.c.com).

Please feel free to contact me if you have any questions or if you need help implementing the same method on other analytics tools.