The ROI Revolution Blog

Converting To Asynchronous Code

June 30, 2010

A sinking bowl: fill it with water and use it to track time

There's a pretty strong push now for everyone to move to the new Asynchronous Google Analytics Tracking Code. It's the only code that's available from the interface now, and nearly all of the documentation includes examples of this as the primary code to be used. Converting your code to the new async code might seem like it's just a hassle, but there are benefit to using the new code. Because the code loads asynchronously, there's no longer any danger that it will interfere with the loading of the rest of your page. This means that the code can now be placed up in the header of your pages rather than right before the closing </body> tag. The result is that you'll be able to track a greater percentage of your visitors than your were previously, which will improve the accuracy of your reports in Google Analytics. Now if your setup isn't too complex, converting won't be too big of an issue. Your old code might look something like this:

Notice that the only modification on this code from the standard code is the line for subdomain tracking. The approach to converting something like this to the new asynchronous code is pretty standard:

Google has provided several migration examples if you need more information. But what if your code is a bit more complicated? Perhaps you've added initial referrer tracking to your Google Analytics Tracking Code:

The trouble with this type of modification is that it includes a bit of logic in addition to the standard tracking method calls. Something like this certainly looks possible:

This will work just fine for this example. But your code most likely looks very different and may have even more modifications. The benefits of the asynchronous code certainly sound nice, but do you really have the time and resources to change the code, test it, and then figure out where you missed a bracket or comma? Fortunately, there's a fairly straightforward way to convert just about any traditional Google Analytics Tracking Code snippet to the asynchronous code:

I personally like this style a lot for several reasons. It can turn the conversion process from a 1 to 2 hour project to a 10 to 20 minute project. There are also far fewer chances to make mistakes. Rather than having to change every single line, you can follow a few simple steps: 1. Start with the following code:

2. Copy everything between "try {" and "} catch(err) {}" from your old code and put it where it says "// Put your code here." If your code is old enough that it doesn't have a try...catch block, just copy everything between the the last opening tag of your Google Analytics Tracking Code. 3. Replace "_getTracker" with "_createTracker". If you have multiple tracking objects, in addition to pageTracker, like a secondTracker, then you'll need to change the _getTracker lines for these objects a bit more. Something like this should work: secondTracker = _gat._createTracker("UA-XXXXXXX-Y", "secondTracker"); The "secondTracker" in quotes could be anything at all, but using "secondTracker" might make it easier if you have to reference this later on. If you have additional code, such as ecommerce code, you can convert these according to the migration examples. You can also follow the following steps: 1. Start with the following code:

2. Copy your additional code, minus any script tags, and paste it where it says "// Put your code here." 3. If the code used pageTracker as an object, then you're done. If the code uses secondTracker instead, then you'll need to change the "var pageTracker._getTrackerByName();" line to the following: var secondTracker = _gat._getTrackerByName("secondTracker"); You can also just add this line if your additional code uses both pageTracker and secondTracker. One thing that's worth noting in the all of the above async examples is that no where is pageTracker or any other tracking object declared as a global variable. This means that if you have any onclick events that use pageTracker, you'll need to update them as well. While this might seem like another pain to go through, it's actually very necessary to ensure that ga.js has loaded, the tracking object has been created, and all methods already applied to it have been run, in order, before the onclick event can run. The benefit is that you no longer have to use try...catch blocks, checks for object existence, and recurring setTimeout statements to ensure that everything works properly; it's all taken care of for you in a much more robust way. So let's say you had an onclick event like this: onclick="pageTracker._trackEvent('Videos', 'Play', 'Marketing Video', 10);" You would have two options for converting this to async: 1. onclick="_gaq.push(['_trackEvent', 'Videos', 'Play', 'Marketing Video', 10]);" 2. onclick="_gaq.push(function () { var pageTracker = _gat._getTrackerByName(); pageTracker._trackEvent('Videos', 'Play', 'Marketing Video', 10); });" Which option should you go with? Option #1 is usually best for simple onclick events like the one above. For longer, more complex onclick events, especially if you're setting them dynamically, option #2 makes a lot of sense since you can simply wrap all of your statements and simplify your conversion process. As a final note, if you need to use secondTracker or some other tracking object, this can be done option #1 style like this: onclick="_gaq.push(['secondTracker._trackEvent', 'Videos', 'Play', 'Marketing Video', 10]);" The name preceding _trackEvent in the must match the name you passed to _gat._getTrackerByName. For example, suppose your converted Google Analytics Tracking Code had the following statement: secondTracker = _gat._createTracker("UA-XXXXXXX-Y", "tracker2"); The correct way to reference this in your option #1 style onclick event would be the following: onclick="_gaq.push(['tracker2._trackEvent', 'Videos', 'Play', 'Marketing Video', 10]);" The reason you use tracker2 instead of secondTracker is that tracker2 is the name that the tracking object was registered under, while secondTracker is simply a local reference to the tracker2 tracking object. You can avoid this confusion by simply using the same name for both as shown earlier. Also note that we didn't register a name for our local pageTracker objects, so these use the default tracking object, which is referenced without a name in option #1 style statements. Feel free to leave comments if you have additional situations that steps don't seem to address. Also, while the above steps may be enough to fully convert your code, you may still want to consider purchasing support to do this, especially if you have a more complicated setup.

Google Analytics for Online Advertisers
Here at ROI Revolution, we consider Google Analytics tracking essential for paid search, so it's included in our PPC Campaign Management service.

Comments

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Claudiu said:

I guess many people will delay this moment till they will need to do some changes to the tracking code.

The more tutorials based on the async will be written the more will do the change. I'll make sure all my blogposts from now will be based on the new code as well.

Thanks for the article. I'll use it as a reference.

July 1, 2010 4:49 AM

Tom Atkinson said:

I can't help thinking that one easy way to migrate would be to create a massive set of wrapper functions that have the same name as the deprecated synchronous GA methods, and that these are hard-coded to the bottom of page in-line, and that only serve to push out the gaq.push commands.

So like you could have a set with all methods like this:

function _setVar(x) {
_gaq.push([ '_setVar', x ]);

}
function _trackPageview(x) {
_gaq.push([ '_trackPageview', x ]);
}

Seems like a plan no?

September 27, 2010 10:06 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Tom: For some setups, something along those lines might work. If someone has a site that uses multiple tracking objects, they may run into some problems with that approach.

The other problem is that if you're putting your wrapper functions at the bottom of the page, it's possible that someone might interact with an element that calls one of the deprecated functions before the page loads and run into a JavaScript error. This is one of the situations that the async code was designed to overcome, so you might be losing some of the benefits with this approach.

This kind of thing was done sometimes during the urchin.js to ga.js migration. Someone would have some code along the lines of:

function urchinTracker(x) {
pageTracker._trackPageview(x);
}


September 28, 2010 8:06 AM

Jay said:

Looking at the code examples above, I notice that your code to include the First Referrer doesn't seem to be running off of the customised ga.js you mention in the previous article about it.

Does the code above to track first referrers work okay with the standard ga.js now? I'd like to use this on one of our sites but want to make sure everything is compliant with the newer asynchronous approach.

January 6, 2011 6:51 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file in the previous post allows you to create two profiles: one for traditional attribution and one for first referrer attribution. The example in this post doesn't need a custom ga.js file because it's just doing one profile for first referrer attribution, so you won't even have a profile for traditional attribution.

As long as you only need to track one attribution model, the standard ga.js will work fine. If you need to do both, we have a technique that we use to do that, but it uses an unsupported technique and involves a lot of extra code to do it right, especially if you have to track across domains.

January 6, 2011 7:34 AM

Jay said:

Just as a followup on my last comment to clarify - we want to have just one profile tracking initial referrers, and the others that are set up just as they are.

This is the code we're using, could you verify if it's correct or suggest how we should be implementing it please?

--- First set of script tags ---

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

--- Includes custom JS, and then this second block of script tags ---

var _gaq2 = _gaq || [];

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _roit._getTracker("UA-XXXXXXX-9");
secondTracker._setDomainName("mysite.co.uk");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

January 6, 2011 7:36 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay: The custom ga.js file isn't compatible with the async code. It might be possible to customize one in a similar way that would work with the async code, but I'd probably do this instead:

var _gaq = _gaq || [];

// Track normal page view
_gaq.push(['_setAccount', 'UA-XXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.co.uk']);
_gaq.push(['_trackPageview']);

_gaq.push(['t1._setAccount', 'UA-XXXXXXX-7']);
_gaq.push(['t1._setDomainName', 'mysite.co.uk']);
_gaq.push(['t1._trackPageview']);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-9", 't2');
secondTracker._setDomainName("mysite.co.uk");
secondTracker._setNameSpace("t2");
if(document.cookie.match("(^|;\\s)__roia=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ?
'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0];
s.parentNode.insertBefore(ga, s);
})();

Some things to note:

1. This uses an unsupported method, _setNameSpace, to create a separate set of cookies.
2. Some of the cookie timeouts with _setNameSpace are a bit off, so you'll need some custom script to fix the timeouts if you care.
3. Cross-domain tracking with _setNameSpace is very hard since you have to pass linking parameters for multiple trackers and parse them correctly on the other domain. Since _setNameSpace is unsupported, doing this correctly is very difficult.

January 6, 2011 8:21 AM

Jay said:

@Jeremy Thanks for the responses and the code snippet, very much appreciated!

Just a couple of further questions if it's alright:

1) We do need to track both attribution modes, the "first referrer" method being the one-off exception in this case. You've mentioned this entails extra work to get it setup right across domains, does this include subdomains as well?

2) I notice in your snippet that the cookie being used in the secondTracker block is still roia instead of utma, is this intentional and okay with the asynchronous approach?

3) How different a change to the cookie lifetimes are we talking about here? If it's negligable in difference I shan't worry too much :-)

4) Using this _setNameSpace method, what naming convention(s) do the cookies take? are they just utma, utmz etc under a different space or do I need to specify the names?

I think that covers it, sorry to bombard you with these!

January 6, 2011 11:57 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Jay:

1. The extra work is more with multiple domains. It's not so bad with subdomains.
2. It should have been 2__utma instead. It should also have been _setNamespace instead of _setNameSpace.
3. All the cookie timeouts other than 2__utmc are set to 2 years. So you could end up with some really long visitor sessions.
4. The each cookie starts with a "2" and its value starts with ^, so ^t2 since we had _setNamespace("t2")

Also, depending on how long your original installation has been in place, you may need to write some code that looks at your existing cookies and overwrites the new cookies with the old referral information. You have to be careful when you do this because the new cookies have a different format and the format needs to be exactly right for them to work.

January 6, 2011 1:01 PM

Jay said:

@Jeremy thank you very much, that's all very helpful! :-)

January 7, 2011 7:51 AM

Hans said:

Regardless of when or how your code inside of script tag executes - it will still slow the pageload time if placed in the header. Browsers must stop rendering the page whenever a set of script tags is encountered to make sure js inside is not altering the DOM. If you work on the kind of site where every ms counts then I'd seriously consider whether placing *any* script tags in the docs head is worthwhile.

January 12, 2011 1:49 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Hans: I think you definitely have to balance the need for the site to load quickly vs the need to have accurate tracking. If you can't measure it, you can't improve it. The new async version of the Google Analytics Tracking Code takes a step in the right direction as it allows you a way to have more accurate tracking with a much smaller hit to load time of the page.

If you still have concerns about load time, you can certainly place the async code at the bottom of the page like the traditional code. You will lose most of the benefits of the async code, however, so you will need to consider what your priorities are.

January 12, 2011 2:02 PM

Dara said:

Hi Jeremy,

We've just launched this code on one of our sites and it all appears to be behaving just fine, so thank you very much for all your help getting us up and running with this on async!

The last issue we have to resolve is the cookie lifetimes, I've tried using the set lifetime calls to adjust them from 2 years to their default lifetimes, but for some reason these are being ignored and the cookies are all set to expire in 2 years anyway. I've tried the calls in different points in the code but to no avail, so I was wondering if you could have a look and see whether you can spot what I'm doing wrong?

Here's the code for the overall script, just in case any of it's making a difference:

---

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-XXXXXXX-1'],
['_trackPageview'],
['t3._setAccount', 'UA-XXXXXXX-3'],
['t3._trackPageview']
);

// Track initial referrer
_gaq2.push(function () {
var secondTracker = _gat._createTracker("UA-XXXXXXX-8", 't2');
secondTracker._setDomainName("sitedomain.co.uk");
secondTracker._setNamespace("t2");

if(document.cookie.match("(^|;\\s)2__utma=")) {
secondTracker._setReferrerOverride("");
secondTracker._setCampNameKey("zzz");
secondTracker._setCampMediumKey("zzz");
secondTracker._setCampSourceKey("zzz");
secondTracker._setCampTermKey("zzz");
secondTracker._setCampContentKey("zzz");
secondTracker._setCampCIdKey("zzz");
}

secondTracker._setVisitorCookieTimeout(63072000000);
secondTracker._setCampaignCookieTimeout(15768000000);
secondTracker._setSessionCookieTimeout(1800000);
secondTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

January 28, 2011 6:27 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

You have to manually set the cookie timeouts when using _setNamespace. I've done something like this before:

var cookieTimeouts = {
"utma": 63072E6,
"utmb": 18E5,
"utmz": 15768E6
};
var reAll, utmAll, i;

for (i in cookieTimeouts) {
reAll = new RegExp("(?:^|;\\s)2__" + i + "=([^;]*)");
utmAll = reAll.exec(unescape(document.cookie));
createCookie("2__" + i, utmAll[1], cookieTimeouts[i], 'sitedomain.co.uk');
}

where createCookie is your favorite create cookie function. This should fix the most obvious cookie timeout issues. This basically needs to run after any _trackPageview call, _trackTrans call, and any _trackEvent call.

January 28, 2011 7:22 AM

Stephen Licata said:

I have been tasked with changing the site to async code. Currently we have the following code. How can I still benefit with the "Roll-up"


var gaJsHost = (("https:" == document.location.protocol) ? "https://ssl." : "http://www.");
document.write(unescape("%3Cscript src='" + gaJsHost + "google-analytics.com/ga.js' type='text/javascript'%3E%3C/script%3E"));


try {

var pageTracker = _gat._getTracker("UA-1274567-12");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var pageTracker = _gat._getTracker("UA-2164562-1");
pageTracker._setDomainName(".abc.com");
pageTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-21646028-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

var rollupTracker = _gat._getTracker("UA-20452391-1");
rollupTracker._setDomainName(".abc.com");
rollupTracker._trackPageview();

}
catch(err) {}


___________

Will the new code be as follows:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2164562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-2456562-1']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_setAllowLinker', true]);
_gaq.push(['_trackPageview']);


(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();


March 28, 2011 6:48 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Stephen: I'd probably do something like this:

var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1274567-12']);
_gaq.push(['_setDomainName', '.abc.com']);
_gaq.push(['_trackPageview']);

_gaq.push(['t2._setAccount', 'UA-2164562-1']);
_gaq.push(['t2._setDomainName', '.abc.com']);
_gaq.push(['t2._trackPageview']);

_gaq.push(['r1._setAccount', 'UA-21646028-1']);
_gaq.push(['r1._setDomainName', '.abc.com']);
_gaq.push(['r1._trackPageview']);

_gaq.push(['r2._setAccount', 'UA-20452391-1']);
_gaq.push(['r2._setDomainName', '.abc.com']);
_gaq.push(['r2._trackPageview']);

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Putting t2, r1, and r2 in front of each method call ensures that each account number has its own tracker. You may still need to make additional changes if you have any ecommerce code, event tracking code, etc., but this should get you started.

March 28, 2011 8:17 AM

Dan said:

Hey Jeremy, I know this thread is a bit old, but I had a quick question.

I've got a simple setup where I want to track first referrer in one profile, and second referrer in the other profile...all for the same website.

Here's the simple code I came up with after looking at the posts above:

var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq2.push(
['_setAccount', 'UA-23908912-4'],
['_trackPageview']
);

// Track initial referrer
if(document.cookie.match("(^|;\\s)__utma=")) {
_gaq2.push(
['_setReferrerOverride', ''],
['_setCampNameKey', 'zzz'],
['_setCampMediumKey', 'zzz'],
['_setCampSourceKey', 'zzz'],
['_setCampTermKey', 'zzz'],
['_setCampContentKey', 'zzz'],
['_setCampCIdKey', 'zzz']
);
}

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

The pages are tracking to each profile... but I'm trying to test which source will be credited with the conversion.

The conversion page is tracking as well, but the conversion counter doesn't seem to be being incremented at all based on my goal.

2 questions:

1. Does it take awhile for conversion data to be incremented?

2. Does my code look like it will work?

Thanks,

Dan

July 2, 2011 3:53 AM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan:

1. Sometimes the conversion data can come in a little later than pageview data, but that happens less and less these days. If you don't see any conversion data within 24 hours, it is most likely an issue with the goal configuration.

2. The code doesn't look right. First, the way to differentiate between tracking objects in the async code is different than the non-async. It should look something like this:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._trackPageview']
);

Second, the tracking objects are going to share cookies, even if you use separate tracking objects. You'll need to go one step further and set the cookies to different domains:

var _gaq = _gaq || [];

_gaq.push(
['_setAccount', 'UA-23908912-1'],
['_setDomainName', 'mydomain.com'],
['_trackPageview']
);

_gaq.push(
['t2._setAccount', 'UA-23908912-4'],
['t2._setDomainName', 'www.mydomain.com'],
['t2._trackPageview']
);

This isn't a well-supported technique, but it may get you what you need.

July 5, 2011 7:55 AM

Dan said:

Hey Jeremy,

Thanks so much for your response... I think I'm getting closer, and thanks to your help, you gave me the idea of doing a www.sitedomain.com to seperate the cookies.

I'm finding that setNamespace isn't working to create another cookie namespace anymore.

Here's what I have now:



var _gaq = _gaq || [];
var _gaq2 = _gaq || [];

_gaq.push(['_setAccount', 'UA-XXXXXXXX-1']);
_gaq.push(['_setDomainName', 'mysite.com']);
_gaq.push(['_trackPageview']);

_gaq2.push(function () {
var pageTracker = _gat._createTracker("UA-XXXXXXX-4",'t2');
pageTracker._setDomainName("www.mysite.com");
if(document.cookie.match("(^|;\\s)www")) {
pageTracker._setReferrerOverride("");
pageTracker._setCampNameKey("zzz");
pageTracker._setCampMediumKey("zzz");
pageTracker._setCampSourceKey("zzz");
pageTracker._setCampTermKey("zzz");
pageTracker._setCampContentKey("zzz");
pageTracker._setCampCIdKey("zzz");
}
pageTracker._trackPageview();
});

(function() {
var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
})();

Because I can't get setNamespace to work, the "if" statement needs to change to find the "www.mysite.com" in the cookie.

If it finds a "www" it knows the visitor is returning and will keep the original referrer values.

No matter what I try, I can't see to get the "if" rule to work...even if a www.mysite.com cookie is already set, this "if" rule will not recognize that fact.

Is there something wrong with my "if" logic?

Thanks a bunch...

Sincerely,

Dan

P.S. My goal, obviously, is to have the first profile track last referrer and the 2nd profile trick first referrer.

July 14, 2011 4:44 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: The domain of a cookie cannot be read through javascript. That's why Google Analytics adds a hash to cookies (unless you turn off hashing). So one option would be to visit a page with the code, see what the hash is on the cookies that you want using your favorite cookie viewing tool (I use firebug with firecookie), and then just change your if statement to look for that hash. That's essentially what Google Analytics does to determine which cookie is the correct cookie when more than one with the same name is set.

July 15, 2011 7:59 AM

Dan said:

Hey Jeremy... ok thanks! I'm looking at the 2 sets of cookies in firebug...but I'm not sure what the actual hashtag IS that seperates the cookies for Google analytics.

Is it the first number before the first period in the cookie values? If so, should I just change my "if" to:

if(document.cookie.match("(^|;\\s)NUMBERHERE")) {

?

Let me know... you're a great help here.

Thanks,

Dan

August 4, 2011 4:20 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

@Dan: It would be something this:

if(document.cookie.match("(^|;\\s)__utma=NUMBERHERE")) {

The presence of the __utma cookie determines whether or not it's a return visitor. By requiring there to be a specific hash value at the beginning of cookie value, then you'll make sure that the code only detects the correct __utma cookie.

August 5, 2011 1:05 PM

blu said:

HI Dan and Jeremy!

We are into the same gulag! I was wondering if you could clarify what you mean in the last post by NUMBERHERE after the _utma=? What number is being referenced?

Much Appreciated!
Blu

October 18, 2011 5:05 PM

Jeremy Aube, Director of Engineering Author Profile Page said:

The value of each of the cookies (__utma, __utmb, __utmc, etc) starts with the same number, which is a hash of your domain. You can see what this number is when you view the cookies for your site. This number will also be different depending on what value you pass to _setDomainName, so it can be used to differentiate between the same cookie set to the root level domain or a subdomain, for example.

October 19, 2011 8:46 AM

Post Your Comments

© 2002-2014 ROI Revolution, Inc. All rights reserved.