AdWords Conversion Tag Demystified, Pt. 3

After a long, long time here it finally is: the third and last part of our little Conversion Script analysis. In the previous two parts, we first introduced the problem setup and tried to examine conversion.js, while the second post was about the different reasons why things did not work the way they should. This part now exhibits our particular solution.

AdWords Conversion Tag Demystified, Pt. 3

For the readers who don't remember very well, the initial issue we had on our webpage was the fact that dynamic insertion of content after page load does not play well with tracking Adwords conversions (a remarketing conversion, in our specific case).

The primary reason for this—as shown in the last part—is that conversion.js uses document.write to insert the tracking pixel into the DOM, which is not possible after document.close has been called. But the DOM will necessarily be closed by the time we want to track a conversion, because it happens on a sub-page that is loaded via jQuery.

There are two general approaches to solve this conundrum: The analytical one requires to analyze the conversion pixel request and recreate it with your own code in order to trigger the conversion. This works (presumably) fine, as evidenced by this StackOverflow thread. It's a simple yet elegant solution that does exactly what you want, if you just want to track an Adwords conversion. For remarketing lists, it is not evident whether those would be tracked correctly without some more delving into the code, as we have seen in part 1 that there is quite a bit of code in conversion.js that is concerned with remarketing.

The other solution is more pragmatic: just overwrite document.write with a function simulates an output stream and then inject the written bytes into the page.

Here's the general idea of how this could be done—this fragment would be placed somewhere where you reload new content into your page. The following assumptions are made:

  • you use jQuery and have already loaded the new page content into $newContent
  • all script tags that need to be executed on load are marked with class="ajax-exec"

The script differentiates between inline scripts and external ones. The former are executed directly using $.globalEval, while externally located script files are loaded and run asynchronously with jQuery's $.getScript function. It then waits until all external scripts have executed and appends the redirected output to a hidden div with the id lazyload-buf.

	// Execute js from the new content (e.g. AdWords conversion tags).// We redirect document.write to a string buffer as we're already// done loading the page at this point.var buf = '';var writeMethSave = document.write;$('div#lazyload-buf').remove();var done = {};document.write = function (string) {buf += string;};$newContent.filter('script.ajax-exec').each(function () {var url = $(this).attr('src');if (url) {// External script.done[url] = false;$.getScript({url: url,success: function () {done[url] = true;}});} else {// Inline script.$.globalEval($(this).html());}});function checkForDone () {for (var url in done) {if (!done[url]) {setTimeout(checkForDone, 25);return;}}// All done, restore method and write output to divdocument.write = writeMethSave;var $container = $(document.createElement("div"));$container.attr('id', 'lazyload-buf');$container.hide();$(document.body).append($container);$container.html(buf);};setTimeout(checkForDone, 25);

Something similar to the above code is in production on our site, and has been happily tracking conversions and putting visitors on remarketing lists ever since. Here's hoping that it will also be helpful to your specific needs.

This concludes our series on the anatomy of Google Adwords conversion tracking. We hope that you could take something away from these articles--and if you have any comments or critisims, we'd be delighted to hear from you!


Afterword: While writing this last part, we noticed that someone already covered the exact same topic in blog form. Their conclusion is the same, and while the proposed solution's script is noticably shorter, it is also less flexible. But it makes for an interesting read, too, that summarizes the whole affair: http://articles.adamwrobel.com/2010/12/23/trigger-adwords-conversion-on-javascript-event