This is a 3 part series on cross domain tracking with Google Analytics in non-standard situations:
- Part 1
- Part 2
- Part 3
When faced with a non-hyperlink and non-form submission crossing of domains, our first thought might be to write a method that simply takes the GA query string variables (generated by our standard solutions) and appends them to the end of our destination URL.
But, Google Analytics is doing a bit more than this in its dedicated functions. Specifically, it uses a hash function as a checksum in order to make sure that the cookies being passed are from the desired source (this ensures that you cannot maliciously affect someone else’s data using GA cookies). This checksum is calculated on the server side and stored in the _utmk variable. Having to write your own server side hashing by reverse engineering the algorithm GA uses to do this checksum isn’t our ideal situation.
So what to do?
The first thing we have to do is understand how the _link() and _linkByPost() functions are working. Looking specifically at some of the ga.js codebases, we see:
a._link=function(b,e)
{
if(i.I&&b){
a._initData();
a.a[p].href=a._getLinkerUrl(b,e)}
};
a._linkByPost=function(b,e){
if(i.I&&b&&b.action){
a._initData();
b.action=a._getLinkerUrl(b.action,e)
}
};
One thing we immediately notice is that both functions require a URI to be passed in, and yet take two parameters, the second being “e”…and both then take this and pass it and the target (b for hyperlinks and b.action for forms) along to a _getLinkerUrl() function. Let’s take a closer look:
a._getLinkerUrl=function(b,e)
{
var j=f(b,"#"),t=b,v=a.qc();
if(v)if(e&&1>=j[w])t+="#"+v;
else if(!e||1>=j[w])if(1>=j[w])t+=(r(b,"?")?"&":"?")+v;
else t=j[0]+(r(b,"?")?"&":"?")+v+"#"+j[1];
return t
}
Again, we see the “e”, and in order to figure out what’s happening, it’s important to understand some of the features and quirks of Javascript, like:
- Constructors can return values
- No block scope
- Reserved words can be overriden
- Every function returns a value
As objects are essentially associative arrays, they are dynamically capable of adding properties and methods. The key to understanding “e” is found in the following declaration:
var _gat=new Object(
{
c:"length",
lb:"4.2",
m:"cookie",
b:undefined,
cb:function(d,a){this.zb=d;this.Nb=a},
r:"__utma=",
W:"__utmb=",
ma:"__utmc=",
Ta:"__utmk=",
na:"__utmv=",
oa:"__utmx=",
Sa:"GASO=",
X:"__utmz=",
lc:"http://www.google-analytics.com/__utm.gif",
mc:"https://ssl.google-analytics.com/__utm.gif",
Wa:"utmcid=",
Ya:"utmcsr=",
$a:"utmgclid=",
Ua:"utmccn=",
Xa:"utmcmd=",
Za:"utmctr=",
Va:"utmcct=",
Hb:false,
_gasoDomain:undefined,
_gasoCPath:undefined,
e:window,
a:document,
k:navigator,
t:function(d){
var a=1,c=0,g,o;
if(!_gat.q(d))
{
a=0;
for(g=d[_gat.c]-1;g>=0;g--)
{
o=d.charCodeAt(g);
a=(a<<6&268435455)+o+(o<<14);
c=a&266338304;
a=c!=0?a^c>>21:a
}
}
return a},
So “e” is actually just the window itself. Now that we know that by passing in the url and the window object to _getLinkerUrl(), we are able to handle both hyperlinks and forms, we can see if it will work for our DIV container example. Let’s give it a try…
function GoogleAnalyticsCookieAppend(uri)
{
var c = pageTracker._getLinkerUrl(uri, window);
return c;
}
We can test this and see that our cookies are indeed being passed. Now, what if we want to pass info with other query string variables?
Continue to Part 3