AdWords Conversion Tag Demystified, Pt. 1

16 Aug 2012 / by Dorian Kind / Comments

Let's take a look at a typical conversion script fragment to overcome the difficulties of more complicated setups for the AdWords Conversion Tag.

Share

Print

None

A recurring theme in our daily interactions with clients are issues with the installation and maintenance of Google AdWords conversion scripts. While it's not terribly difficult to insert a single JavaScript fragment into a single, static HTML page, things get more complicated if one has pages with dynamically loaded content, lots of different conversion tags or other fringe setups.

We recently stumbled about this subject ourselves when we wanted to insert remarketing tags on our own web site. On our site, there are different "main" categories, whose subpages are loaded dynamically using jQuery. When we just inserted the standard remarketing script into the loaded content...

...nothing happened at all. The conversion just wasn't tracked, except if you deactivate JavaScript (via the img-tag embedded in a noscript-element).
We decided to investigate. First of all, let's take a look at a typical conversion script fragment:

Adwords Conversion Tag

	
	<script type="text/javascript">
/* <![CDATA[ */
var google_conversion_id = 1011858948;
var google_conversion_language = "en";
var google_conversion_format = "3";
var google_conversion_color = "ffffff";
var google_conversion_label = "KpdpCPSB3QMQhPy-4gM";
var google_conversion_value = 0;
/* ]]> */
</script>
<script type="text/javascript" src="http://www.googleadservices.com/pagead/conversion.js">
</script>
<noscript>
<div style="display:inline;">
<img height="1" width="1" style="border-style:none;" alt="" src="http://www.googleadservices.com/pagead/conversion/1011858948/?value=0&amp;label=KpdpCPSB3QMQhPy-4gM&amp;guid=ON&amp;script=0"/>
</div>
</noscript>

Nothing too fancy here, a few variables are set containing information about the conversion (only id, label and perhaps value are really required), an external script tag and a noscript alternative. If one assumed that the script does some further checking of the user's setup and then basically makes the same pixel request as inside the noscript element, one would be right. Here's an example of a img request coming from the script:

 

ADWORDS CONVERSION IMG-TAG

	
	<img height="1" width="1" border="0" src="http://www.googleadservices.com/pagead/conversion/1011858948/?random=1344604284197&amp;cv=7&amp;fst=1344604284197&amp;num=1&amp;fmt=3&amp;value=0&amp;label=KpdpCPSB3QMQhPy&amp;bg=ffffff&amp;hl=en&amp;guid=ON&amp;u_h=1200&amp;u_w=1920&amp;u_ah=1174&amp;u_aw=1920&amp;u_cd=24&amp;u_his=31&amp;u_tz=120&amp;u_java=true&amp;u_nplug=13&amp;u_nmime=110&amp;url=http%3A//www.webrepublic.ch/en/services/facebook-marketing/&amp;frm=0">

Same basic structure, just containing additional information about the user. Nothing too interesting.

So let's have a look at the conversion script itself:

 

CODE: CONVERSION.JS

	
	(function(){var f=null;var h="google_conversion_id google_conversion_format google_conversion_type google_conversion_order_id google_conversion_language google_conversion_value google_conversion_domain google_conversion_label google_conversion_color google_disable_viewthrough google_remarketing_only google_remarketing_for_search google_conversion_items google_custom_params google_conversion_date google_conversion_time google_conversion_js_version onload_callback opt_image_generator google_is_call google_conversion_page_url".split(" ");
function i(b){return b!=f?escape(b.toString()):""}function j(b,c){var g=i(c);if(""!=g){var a=i(b);if(""!=a)return"&".concat(a,"=",g)}return""}function k(b){var c=typeof b;return b==f||"object"==c||"function"==c?f:String(b).replace(/,/g,"\\,").replace(/;/g,"\\;").replace(/=/g,"\\=")}
function l(b){var c;b=b.google_custom_params;if(!b||"object"!=typeof b||"function"==typeof b.join)c="";else{var g=[];for(c in b)if(Object.prototype.hasOwnProperty.call(b,c)){var a=b[c];if(a&&"function"==typeof a.join){for(var d=[],e=0;efunction m(b){return"number"!=typeof b&&"string"!=typeof b?"":i(b.toString())}function n(b){if(!b)return"";b=b.google_conversion_items;if(!b)return"";for(var c=[],g=0,a=b.length;gfunction o(b,c,g){var a=[];if(b){var d=b.screen;d&&(a.push(j("u_h",d.height)),a.push(j("u_w",d.width)),a.push(j("u_ah",d.availHeight)),a.push(j("u_aw",d.availWidth)),a.push(j("u_cd",d.colorDepth)));b.history&&a.push(j("u_his",b.history.length))}g&&"function"==typeof g.getTimezoneOffset&&a.push(j("u_tz",-g.getTimezoneOffset()));c&&("function"==typeof c.javaEnabled&&a.push(j("u_java",c.javaEnabled())),c.plugins&&a.push(j("u_nplug",c.plugins.length)),c.mimeTypes&&a.push(j("u_nmime",c.mimeTypes.length)));
return a.join("")}function p(b,c,g){var a="";if(c){var a=a+j("ref",c.referrer!=f?c.referrer.toString().substring(0,256):""),d,c=2;try{if(b.top.document==b.document)c=0;else{var e=b.top;try{d=!!e.location.href||""===e.location.href}catch(q){d=!1}d&&(c=1)}}catch(J){}d=c;e="";e=g?g:1==d?b.top.location.href:b.location.href;a+=j("url",e!=f?e.toString().substring(0,256):"");a+=j("frm",d)}return a}
function r(b){return b&&b.location&&b.location.protocol&&"https:"==b.location.protocol.toString().toLowerCase()?"https:":"http:"}function s(b,c,g){return r(b)+"//"+(g.google_remarketing_only?"googleads.g.doubleclick.net":g.google_conversion_domain||"www.googleadservices.com")+"/pagead/"+c}
function t(){var b=u,c=navigator,g=document,a=u,d="/?";"landing"==a.google_conversion_type&&(d="/extclk?");var d=s(b,[a.google_remarketing_only?"viewthroughconversion/":"conversion/",i(a.google_conversion_id),d,"random=",i(a.google_conversion_time)].join(""),a),e;a:{e=a.google_conversion_language;if(e!=f){e=e.toString();if(2==e.length){e=j("hl",e);break a}if(5==e.length){e=j("hl",e.substring(0,2))+j("gl",e.substring(3,5));break a}}e=""}c=[j("cv",a.google_conversion_js_version),j("fst",a.google_conversion_first_time),
j("num",a.google_conversion_snippets),j("fmt",a.google_conversion_format),j("value",a.google_conversion_value),j("label",a.google_conversion_label),j("oid",a.google_conversion_order_id),j("bg",a.google_conversion_color),e,j("guid","ON"),j("disvt",a.google_disable_viewthrough),j("is_call",a.google_is_call),n(a),o(b,c,a.google_conversion_date),p(b,g,a.google_conversion_page_url),l(a),a.google_remarketing_for_search&&!a.google_conversion_domain?"&srr=n":""].join("");c=d+c;g=function(a,b,c){return'</pre>
<img src="'+a+'" alt="" width="'+b+'" height="'+ c+'" border="0" />
<pre>'};return 0==a.google_conversion_format&&a.google_conversion_domain==f?'<a href="'+(r(b)+" target="_blank">'+g(c,135,27)+"</a>":1<a.google_conversion_snippets||3==a.google_conversion_format?g(c,1,1):'</pre>
<iframe name="google_conversion_frame" src="'+c+'" frameborder="0" marginwidth="0" marginheight="0" scrolling="no" width="'+(2==a.google_conversion_format?200:300)+'" height="'+(2==a.google_conversion_format?26:13)+'"></iframe>
<pre>"}function v(){return new Image};var u=window;
if(u)if(/[\?&;]google_debug/.exec(document.URL)!=f){var w=u,x=document.getElementsByTagName("head")[0];x||(x=document.createElement("head"),document.getElementsByTagName("html")[0].insertBefore(x,document.getElementsByTagName("body")[0]));var y=document.createElement("script");y.src=s(window,"conversion_debug_overlay.js",w);x.appendChild(y)}else{try{var z;var A=u;"landing"==A.google_conversion_type||!A.google_conversion_id||A.google_remarketing_only&&A.google_disable_viewthrough?z=!1:(A.google_conversion_date=
new Date,A.google_conversion_time=A.google_conversion_date.getTime(),A.google_conversion_snippets="number"==typeof A.google_conversion_snippets&&01),z=!0);if(z&&(document.write(t()),u.google_remarketing_for_search&&!u.google_conversion_domain)){var B=u,C,D=u,E;E=r(D)+"//www.google.com/ads/user-lists/"+[i(B.google_conversion_id),"/?random=",Math.floor(1E9*Math.random())].join("");C=E+=[j("label",B.google_conversion_label),j("fmt","3"),p(D,document,B.google_conversion_page_url)].join("");var F=v;"function"===typeof B.opt_image_generator&&(F=B.opt_image_generator);var G=F();C+=j("async","1");G.src=C;G.onload=function(){}}}catch(H){}for(var I=
u,K=0;K<h.length;K++)I[h[K]]=f};})();

Whoops! This does not look very familiar. It's quite compressed and obfuscated and illegible. We have to transform this into something more readable. We dabbled around a bit with a JavaScript IDE and got the following code. It looks like something went wrong with the variable renaming, so it probably won't work any longer, but to quickly analyze it it's good enough...

 

CONVERSION.JS (MORE READABLE)

	Code: conversion.js (more readable)
	(function () {
var nil = null;
var convItems = "google_conversion_id google_conversion_format google_conversion_type google_conversion_order_id google_conversion_language google_conversion_value google_conversion_domain google_conversion_label google_conversion_color google_disable_viewthrough google_remarketing_only google_remarketing_for_search google_conversion_items google_custom_params google_conversion_date google_conversion_time google_conversion_js_version onload_callback opt_image_generator google_is_call google_conversion_page_url".split(" ");

function toStr(b) {
if (b != nil) {
return escape(b.toString())
} else {
return ""
}
}

function keyValueParam(b, c) {
var g = toStr(c);
if ("" != g) {
var a = toStr(b);
if ("" != a) return "&".concat(a, "=", g)
}
return ""
}

function paramEscape(b) {
var c = typeof b;
if (b == nil || "object" == c || "function" == c) {
return nil
} else {
return String(b).replace(/,/g, "\\,").replace(/;/g, "\\;").replace(/=/g, "\\=")
}
}

function buildDataParam(b) {
var c;
b = b.google_custom_params;
if (!b || "object" != typeof b || "function" == typeof b.join) c = "";
else {
var g = [];
for (c in b) if (Object.prototype.hasOwnProperty.call(b, c)) {
var a = b[c];
if (a && "function" == typeof a.join) {
for (var d = [], e = 0; e < a.length; ++e) {
var q = paramEscape(a[e]);
q != nil && d.push(q)
}
a = 0 == d.length ? nil : d.join(",")
} else a = paramEscape(a);
(d = paramEscape(c)) && a != nil && g.push(d + "=" + a)
}
c = g.join(";")
}
return "" == c ? "" : "&".concat("data=", encodeURIComponent(c))
}

function literalToStr(b) {
return "number" != typeof b && "string" != typeof b ? "" : toStr(b.toString())
}
function buildItemParam(b) {
if (!b) return "";
b = b.google_conversion_items;
if (!b) return "";
for (var c = [], g = 0, a = b.length; g < a; g++) {
var d = b[g],
e = [];
d && (e.push(literalToStr(d.value)), e.push(literalToStr(d.quantity)), e.push(literalToStr(d.item_id)), e.push(literalToStr(d.adwords_grouping)), e.push(literalToStr(d.sku)), c.push("(" + e.join("*") + ")"))
}
return 0 < c.length ? "&item=" + c.join("") : ""
}

function buildEnvironParam(b, c, g) {
var a = [];
if (b) {
var d = b.screen;
d && (a.push(keyValueParam("u_h", d.height)), a.push(keyValueParam("u_w", d.width)), a.push(keyValueParam("u_ah", d.availHeight)), a.push(keyValueParam("u_aw", d.availWidth)), a.push(keyValueParam("u_cd", d.colorDepth)));
b.history && a.push(keyValueParam("u_his", b.history.length))
}
g && "function" == typeof g.getTimezoneOffset && a.push(keyValueParam("u_tz", - g.getTimezoneOffset()));
c && ("function" == typeof c.javaEnabled && a.push(keyValueParam("u_java", c.javaEnabled())), c.plugins && a.push(keyValueParam("u_nplug", c.plugins.length)), c.mimeTypes && a.push(keyValueParam("u_nmime", c.mimeTypes.length)));
return a.join("")
}
function buildLocationParam(b, c, g) {
var a = "";
if (c) {
var a = a + keyValueParam("ref", c.referrer != nil ? c.referrer.toString().substring(0, 256) : ""),
d, c = 2;
try {
if (b.top.document == b.document) c = 0;
else {
var e = b.top;
try {
d = !! e.location.href || "" === e.location.href
} catch (q) {
d = !1
}
d && (c = 1)
}
} catch (J) {}
d = c;
e = "";
e = g ? g : 1 == d ? b.top.location.href : b.location.href;
a += keyValueParam("url", e != nil ? e.toString().substring(0, 256) : "");
a += keyValueParam("frm", d)
}
return a
}

function getProtocol(b) {
return b && b.location && b.location.protocol && "https:" == b.location.protocol.toString().toLowerCase() ? "https:" : "http:"
}
function getTrackingURL(b, c, g) {
return getProtocol(b) + "//" + (g.google_remarketing_only ? "googleads.g.doubleclick.net" : g.google_conversion_domain || "www.googleadservices.com") + "/pagead/" + c
}

function getConversionStmtStr() {
var b = window_,
c = navigator,
a = window_,
d = "/?";
"landing" == a.google_conversion_type && (d = "/extclk?");
var d = getTrackingURL(b, [a.google_remarketing_only ? "viewthroughconversion/" : "conversion/", toStr(a.google_conversion_id), d, "random=", toStr(a.google_conversion_time)].join(""), a),
e;
a: {
e = a.google_conversion_language;
if (e != nil) {
e = e.toString();
if (2 == e.length) {
e = keyValueParam("hl", e);
break a
}
if (5 == e.length) {
e = keyValueParam("hl", e.substring(0, 2)) + keyValueParam("gl", e.substring(3, 5));
break a
}
}
e = ""
}
c = [keyValueParam("cv", a.google_conversion_js_version), keyValueParam("fst", a.google_conversion_first_time),
keyValueParam("num", a.google_conversion_snippets), keyValueParam("fmt", a.google_conversion_format), keyValueParam("value", a.google_conversion_value), keyValueParam("label", a.google_conversion_label), keyValueParam("oid", a.google_conversion_order_id), keyValueParam("bg", a.google_conversion_color), e, keyValueParam("guid", "ON"), keyValueParam("disvt", a.google_disable_viewthrough), keyValueParam("is_call", a.google_is_call), buildItemParam(a), buildEnvironParam(b, c, a.google_conversion_date), buildLocationParam(b, document, a.google_conversion_page_url), buildDataParam(a), a.google_remarketing_for_search && !a.google_conversion_domain ? "&srr=n" : ""].join("");
c = d + c;
var getImgUrl = function (a, b, c) {
return '<img height="' + c + '" width="' + b + '" border="0" src="' + a + '" />'
};
if (0 == a.google_conversion_format && a.google_conversion_domain == nil) {
return '<a href="' + (getProtocol(b) + "//services.google.com/sitestats/" + ({
ar:1,
bg:1,
cs:1,
da:1,
de:1,
el:1,
en_AU:1,
en_US:1,
en_GB:1,
es:1,
et:1,
fi:1,
fr:1,
hi:1,
hr:1,
hu:1,
id:1,
is:1,
it:1,
iw:1,
ja:1,
ko:1,
lt:1,
nl:1,
no:1,
pl:1,
pt_BR:1,
pt_PT:1,
ro:1,
ru:1,
sk:1,
sl:1,
sr:1,
sv:1,
th:1,
tl:1,
tr:1,
vi:1,
zh_CN:1,
zh_TW:1
}[a.google_conversion_language] ? a.google_conversion_language + ".html" : "en_US.html") + "?cid=" + toStr(a.google_conversion_id)) + '" target="_blank">' + getImgUrl(c, 135, 27) + "</a>"
} else {
return 1 < a.google_conversion_snippets || 3 == a.google_conversion_format ? getImgUrl(c, 1, 1) : '<iframe name="google_conversion_frame" width="' + (2 == a.google_conversion_format ? 200 : 300) + '" height="' + (2 == a.google_conversion_format ? 26 : 13) + '" src="' + c + '" frameborder="0" marginwidth="0" marginheight="0" vspace="0" hspace="0" allowtransparency="true" scrolling="no">' + getImgUrl(c.replace(/\?random=/, "?frame=0&random="), 1, 1) + "</iframe>"
}
}

function getImgElem() {
return new Image
};

var window_ = window;
if (window_) {
if (/[\?&;]google_debug/.exec(document.URL) != nil) {
var w = window_,
x = document.getElementsByTagName("head")[0];
x || (x = document.createElement("head"), document.getElementsByTagName("html")[0].insertBefore(x, document.getElementsByTagName("body")[0]));
var y = document.createElement("script");
y.src = getTrackingURL(window, "conversion_debug_overlay.js", w);
x.appendChild(y)
} else {
try {
var z;
var A = window_;
if ("landing" == A.google_conversion_type || !A.google_conversion_id || A.google_remarketing_only && A.google_disable_viewthrough) {
z = !1;
} else {
A.google_conversion_date = new Date,
A.google_conversion_time = A.google_conversion_date.getTime(),
A.google_conversion_snippets = "number" == typeof A.google_conversion_snippets && 0 < A.google_conversion_snippets ? A.google_conversion_snippets + 1 : 1,
"number" != typeof A.google_conversion_first_time && (A.google_conversion_first_time = A.google_conversion_time),
A.google_conversion_js_version = "7",
0 != A.google_conversion_format && (1 != A.google_conversion_format && 2 != A.google_conversion_format && 3 != A.google_conversion_format) && (A.google_conversion_format = 1),
z = !0;
}
if (z && (document.write(getConversionStmtStr()), window_.google_remarketing_for_search && !window_.google_conversion_domain)) {
var B = window_,
C, D = window_,
E;
E = getProtocol(D) + "//www.google.com/ads/user-lists/" + [toStr(B.google_conversion_id), "/?random=", Math.floor(1E9 * Math.random())].join("");
C = E += [keyValueParam("label", B.google_conversion_label), keyValueParam("fmt", "3"), buildLocationParam(D, document, B.google_conversion_page_url)].join("");
var F = getImgElem;
"function" === typeof B.opt_image_generator && (F = B.opt_image_generator);
var G = F();
C += keyValueParam("async", "1");
G.src = C;
G.onload = function () {
}
}
} catch (H) {
}
for (var I = window_, K = 0; K < convItems.length; K++) I[convItems[K]] = nil
}
};
})();

Well, that's sure a bunch of code. Notice the many clever, clever constructs that are a nightmare to debug :)

An interesting point is that the same script is used for many different purposes, "normal" AdWords conversions, remarketing conversions, view-through conversions and even DoubleClick stuff — we think that's where user-lists (line 221) and the "landing" conversion type (line 206) are used. That makes sense from an efficiency stance, as most people will have this script cached, you might just as well put all your ad-related functionality in there instead of splitting it into multiple files.

Another thing that caught our attention was the part at line 195 (highlighted), where a check against the document's URL is made with some regex containing 'google_debug'. Hmmm... Let's try that one on a page with a conversion script:

Holy smokes! Why did no one tell us? An overlay with all conversion-related information without even registering the conversion itself? That could be quite useful. So useful in fact, that we quickly hacked together a Google extension that just appends the necessary query parameter to all visited links. Have a client with conversion troubles? Install the extension, turn it on and start browsing the client's site.
You can get the plugin at the Chrome web store. Please note that it's alpha-quality software and will probably not work with all sites, but it's better than checking pages by hand for non-working conversion scripts.

That's it for this post, next time we will continue the examination of the script and present our solution to the issue of conversion tags not working inside dynamically loaded content.

Read on: AdWords Conversion Tag Demystified, Pt. 2