Dec 04 13

A Different Approach to Cross-Domain Tracking

By

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.
    // 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');
    }
    
  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.]

    // 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 : "");
      });
    }
    
  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:
    <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>
    
  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
    <script>
      try {
        var clientid = document.location.search.match(/[&\?]clientId=([^&]*)/)[1];
        parent.setClientId(clientid);
      } catch (e) {
      }
    </script>
    
  5. To close the loop, add the setClientId function to the original page – a function that will be called by set-userid.html.
    
    // 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');
    }
    

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.

  • Tim

    how implement in mix panel?

  • @DaveAnalyst

    Hi Shay. This is really interesting. Can you use this method on https pages, or will it trigger security alerts in users’ browsers?

    • Anonymous

      Good point. The “page contains secure and nonsecure items” will appear during the sync unless you can serve all the relevant files on https as well (including the page the user is currently on).

      Another thing to take into consideration, if you are going to work in “mixed” mode, besides the security message, secured cookies will be synced as non secured.

  • Andy

    Hi Shay,

    I feel really excited to implement this. Just want to make sure that this will work for the following scenario:

    I have a Google Universal Analytics account tied to domainA.com.

    I have domainB.com which receives Google Adwords traffic so users download our software from this domainB.com.

    After installing the software there is an after-install page opened
    on the domainA.com. So users don’t click any links on domainB.com to
    reach domainA.com.

    I want to track both domains within one Google Universal Analytics
    account tied to domainA.com with Cross Domain Auto Linking. So I
    followed this guide https://support.google.com/analytics/answer/1034342?hl=en
    and implemented the code according to it but the problem is that I
    still cannot see which Adwords campaigns of domainB.com attributed to
    after-install goal as they count as direct visits to domainA.com.

    Wondering if the strategy you describe will work in my case, so I could see a proper
    campaign attribution and see my goals while there’s no cross domain
    links?

    Thank you.

    • Anonymous

      Hi Andy,

      I think you should do the following:
      – make sure both domainB and domainA are tracked by the same Google Analytics property
      – use domainB as your centralized domain

      when the post install page (domainA) will open, it will first call domainB and get the clientId (earlier set by Google when the user arrived to domainB). This clientId is tied to the original traffic source so this page view will be related by Google Analytics to the same traffic source.

      since domainB is your centralized domain, the only place you have to add the code is to the post install page on domainA.

      Please feel free to email me if you need any help.

Subscribe for Our Latest SharePoint Analytics Updates

Signup to get the latest SharePoint Analytics posts straight to your inbox!