Multiple Domains, Tracking and Third-Party Cookies

Tracking anonymous visitors across multiple domains is difficult because cookies can’t be shared across domains. One way around this is to use an iframe to set the cookie, which works well in Chrome, Firefox, and Edge. However, Safari prevents a challenge because it prevents third-party cookies from being set.

I haven’t found a solution for the Safari issue yet, but thought I’d share the method I’ve worked out for cross domain tracking with Mixpanel for the remaining browsers.

For the example, I’ll use domains a A.com and B.com. A.com is the primary website and B.com is a marketing website that refers traffic to A.com.

On domain A.com you’ll need to set up an URL that loads the tracking code when it’s called inside of an iframe. We can pass tracking data from B.com to the iframe using a query string, and an efficient method for passing that data is by base64 encoding an JSON object.

Passing tracking data from domain B.com to A.com

Let’s say this is the data I wanted to track from B.com:

var data = {
	'source': 'B.com',
	'path': window.location.pathname,
	'title': document.title,
	'full_url' : window.location.href
}

This can be converted into a string and then base64 encoded:

data = JSON.stringify( data );
data = btoa( data );

Then, when the iframe is created we can pass that information along:

var iframe = document.createElement('iframe');
iframe.setAttribute( 'src', 'http://a.com/tracking/?data=' + data );
iframe.style.width = "1px";
iframe.style.height = "1px";
console.log( 'http://a.com/tracking/?data=' + data  );
document.body.appendChild(iframe);

Here’s what it looks like all together:

document.addEventListener("DOMContentLoaded", function(event) {
var data = {
'source': 'B.com',
'path': window.location.pathname,
'title': document.title,
'full_url' : window.location.href
}
data = JSON.stringify( data );
data = btoa( data );
var iframe = document.createElement('iframe');
iframe.setAttribute( 'src', 'http://a.com/tracking/?data=' + data );
iframe.style.width = "1px";
iframe.style.height = "1px";
document.body.appendChild(iframe);
});
view raw iframe-data.js hosted with ❤ by GitHub

Recording data on domain A.com

When http://a.com/tracking/ loads, we’ll want to get the data that was passed in the query string to the iframe.

You can use a function to decode query string data (thanks StackExchange!) and then parse it back into a JSON object:

// Parses the url for query strings
function prefix_return_query_strings( url ) {
var urlParams;
var match,
pl = /\+/g, // Regex for replacing addition symbol with a space
search = /([^&=]+)=?([^&]*)/g,
decode = function (s) { return decodeURIComponent(s.replace(pl, " ")); },
query = url.search.substring(1);
urlParams = {};
while (match = search.exec(query) ) {
urlParams[decode(match[1])] = decode(match[2]);
}
return urlParams;
}
// If query data is present, track it
var query = prefix_return_query_strings( window.location );
if ( query.data ) {
var data = atob( query.data );
data = JSON.parse( data );
// Now tracking scripts can be called using data
console.log( data.source );
console.log( data.path );
console.log( data.path );
console.log( data.title );
console.log( data.full_url );
}

For anyone looking specifically for a Mixpanel solution, I posted the full code here.

The Mixpanel script set its own cookie, so to verify if the cookie was being set properly I outputted it in the console log:

console.dir( mixpanel.cookie.props );

Results

In testing, Chrome, Firefox and Edge all returned the same distinct_id.

In Safari, if A.com had been visited before B.com, the cookie was already set on A.com and tracking worked properly. However, if the visitor went to B.com for the first time, a distinct_id (and fresh cookie) was generated on every page visit.

Safari and old versions of IE (which also doesn’t set third-party cookies) are 30% of traffic on the site I built this for, which is a huge amount of visits that don’t get attributed correctly. However, being able to track the other 70% correctly is a huge improvement.

However, for Safari users, the tracking is even worse than before since each page view now gets a separate distinct_id. To solve that, I’m planning to set a cookie the first time a Safari visitor lands on B.com with a unique distinct_id, and pass that in the data object so all visits by that user get attributes to the same visitor.

Conclusions

This tracking method is imperfect, but associating data for Chrome, Firefox and Edge users is definitely an improvement. If anyone has suggestions for working around the third-party cookie restrictions on Safari (without requiring a log in or passing query strings in links), I’d love learn more.

About Devin

I'm a WordPress developer based in Austin, Texas. I run a little theme shop called DevPress and work for a startup called Cratejoy. Find me on twitter @devinsays.

2 Responses

  1. Mike

    Hi Devin, you mention a distinct_id passed back and forth, but I don’t see you getting or setting it anywhere. Can you explain further? I’m looking to implement a feature like this to track conversions, but I need to be able to link a unique user id between both domains.

Leave a Reply