AdWords Page Event Conversion Tracking

in PPC Tracking

Conversion events often happen as the result of some action being taken on a page, such as the click of a button or submission of a form, that don't cause a new page to be displayed. These can be tracked in Google Analytics using custom code attached to JavaScript events, like onClick and onSubmit; however, this isn't possible if you want to use AdWords Conversion Tracking because the tracking code is only triggered by a full page view.

This issue has recently caused me problems as I wanted to track leads generated via a Drupal contact form, but the contact form module doesn't let you specify any confirmation page to send the user to after they hit the submit button. I found some modules for redirecting the user after sending a message, but they hadn't been upgraded to work with Drupal 7.

This left me with three choices: build my own module, upgrade the existing redirect module, or modify the AdWords tracking code to fire in response to a JavaScript onClick or onSubmit event. I decided to go with the last option, as it is likely to be useful in other situations.

Registering a Conversion in Response to a Click

I needed a way to send the conversion tracking pixel to AdWords within a JavaScript event, instead of when a page initially loads. The two ways I thought about doing this were to either simulate the tracking pixel request or delay the execution of the conversion script, but first I needed to define the variables that make up a conversion goal.

Defining the Conversion Goal

The two important variables that need to be sent to AdWords are the id and label:

  • ID – Identifies your AdWords account.
  • Label – Identifies the conversion type within your account: lead, sale etc. In addition to this, you're also likely to want to set the value and URL:
  • Value – The optional value you've attached to the conversion goal to measure ROI.
  • URL – The page that triggered the conversion event, which can be viewed from the Webpages tab within AdWords.

Given this, we can define a conversion goal using the following JavaScript:

var Goal = function(id, label, value, url) {
    this.id = id;
    this.label = label;
    this.value = value;
    this.url = url;
}
An Object that Represents a Conversion Goal

Sending a Conversion Tracking Pixel

Once the values that defined the conversion goal were identified, I needed to work out how to send them to AdWords. The obvious way to do this is by using the noscript portion of the tracking snippet: this contains an image request with parameters to register the conversion; as AdWords conversion tracking uses third party cookies—so shouldn't need JavaScript to operate—it should be possible to record a conversion by just creating the same image using JavaScript. The following function does just that:

function trackAdWordsConversion(goal, callback) {
    // Create an image
    var img = document.createElement("img");
 
    // An optional callback function to run follow up processed after the conversion has been tracked
    if(callback && typeof callback === "function") {
        img.onload = callback;
    }
 
    // Construct the tracking beacon using the goal parameters
    var trackingUrl = "http://www.googleadservices.com/pagead/conversion/"+goal.id;
    trackingUrl += "/?random="+new Date().getMilliseconds();
    trackingUrl += "&value="+goal.value;
    trackingUrl += "&label="+goal.label;
    trackingUrl += "&guid=ON&script=0&url="+encodeURI(goal.url);
    img.src = trackingUrl;
 
    // Add the image to the page 
    document.body.appendChild(img);
 
    // Don't display the image 
    img.style = "display: none;";
}
Sending a Tracking Pixel to AdWords

The important parts of this to understand are the construction of the tracking URL and the callback function that's attached to the image.

How the Tracking URL Is Built

The following code snippet constructs an AdWords tracking pixel request using the Goal object defined earlier:

var trackingUrl = "http://www.googleadservices.com/pagead/conversion/"+goal.id;
trackingUrl += "/?random="+new Date().getMilliseconds();
trackingUrl += "&value="+goal.value;
trackingUrl += "&label="+goal.label;
trackingUrl += "&guid=ON&script=0&url="+encodeURI(goal.url);
img.src = trackingUrl;
Building a Tracking Pixel for a Conversion Goal

You can see that the base URL is a location on Google's servers with your unique account ID appended to the end. I've added a parameter with a random number to ensure the image isn't cached in the users browser, then placed the goal value and label into the value and label parameters. Next, I've left the guid and script parameters in place as I found them in the noscript element, and finally I've used an additional parameter to send the URL that triggered the conversion.

The Callback Function

To get this working, you're going to need to trap a click or submit event and send the tracking pixel off before completing the action that the user took on the page; however, you need to cancel the default behavior of the click, or the user will be taken to a new page before the script has a chance to finish. This means that you need to use your own JavaScript code to complete the action once the tracking code has done its work. I've done this by attaching a function to the tracking image's onLoad event:

if(callback && typeof callback === "function") {
   img.onload = callback;
}
A Function Called After the Pixel is Sent

Using the Custom Tracking Code

To use this code, you need to attach a function to the JavaScript event that's triggered when a user completes your goal; this is very similar to the way you would track user actions in Google Analytics:

  • Send off the tracking pixel,
  • Stop the default behavior of your click or submit event to ensure the pixel gets sent first,
  • Trigger the default behavior so the user can continue what they were doing.

Registering a Conversion for a Form Submission

Here's an example function that you could use when a form is submitted:

function submitForm(form, goal) {
    try {
        // A function to submit the form after the conversion event has been sent
        var submitFormCallback = function() {
            form.submit();
        }
 
        // Track the conversion
        trackAdWordsConversion(goal, submitFormCallback);
 
        // Don't keep the user waiting too long in case there are problems
        setTimeout(submitFormCallback, 1000);
 
        // Stop the default form submission
        return false;
    } catch(err) {
        // Ensure the form is still submitted if there's an unexpected error in the code
        return true;
    }
}
Tracking an AdWords Conversion from a Form Submission

This takes a reference to a form and a Goal object and does the following:

  • constructs a callback function, called submitFormCallback(), to submit the form when the tracking pixel has loaded,
  • calls the trackAdWordsConversion() function to fire off the pixel then run submitFormCallback() when the image has loaded,
  • attaches submitFormCallback() to a timeout so the user won't be kept too long just for the sake of tracking,
  • returns false to cancel the normal submit action.

As an extra safety measure, the whole thing is wrapped in a try/catch block that will return true to ensure the form is still submitted if an error occurs in the code.

The only thing left to do is attach this function to the onSubmit event of a form:

<form action="#" method="post" onsubmit="return submitForm(this, new Goal(123456789, 'AdswCDsAW1AMQ74adD', 10, location.href));"> 
   <input type="submit" value="Submit"/> 
</form>
Attaching a Tracking Pixel to a Form

Results

If you trigger one of the events with the Firefox “Live HTTP Headers” plugin active, then something like the following should be recorded:

http://www.googleadservices.com/pagead/conversion/123456789/?random=156&value=10&label=AdswCDsAW1AMQ74adD&guid=ON&script=0&url=http://www.example.com/tracking_test.html 
 
GET /pagead/conversion/123456789/?random=156&value=10&label=AdswCDsAW1AMQ74adD&guid=ON&script=0&url=http://www.example.com/tracking_test.html HTTP/1.1 
Host: www.googleadservices.com 
User-Agent: Mozilla/5.0 (Ubuntu; X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1 
Accept: image/png,image/*;q=0.8,*/*;q=0.5 
Accept-Language: en-us,en;q=0.5 
Accept-Encoding: gzip, deflate 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 
Connection: keep-alive 
 
HTTP/1.1 302 Found 
P3P: policyref="http://www.googleadservices.com/pagead/p3p.xml", CP="NOI DEV PSA PSD IVA PVD OTP OUR OTR IND OTC" 
Date: Thu, 26 Jan 2012 14:14:01 GMT 
Pragma: no-cache 
Expires: Fri, 01 Jan 1990 00:00:00 GMT 
Cache-Control: no-cache, must-revalidate 
Content-Type: image/gif 
Location: http://googleads.g.doubleclick.net/pagead/viewthroughconversion/123456789/?random=156&value=10&label=AdswCDsAW1AMQ74adD&guid=ON&script=0&url=http://www.example.com/tracking_test.html &ctc_id=CVSAQgSSSB0CDDDD&ct_cookie_present=false 
X-Content-Type-Options: nosniff 
Server: cafe 
Content-Length: 42 
X-XSS-Protection: 1; mode=block
HTTP Log of Sending a Conversion Pixel

This shows that the pixel was sent and received by AdWords, then a response was returned with a redirect to register any potential view-through conversions:

http://googleads.g.doubleclick.net/pagead/viewthroughconversion/123456789/?random=156&value=10&label=AdswCDsAW1AMQ74adD&guid=ON&script=0&url=http://www.example.com/tracking_test.html &ctc_id=CVSAQgSSSB0CDDDD&ct_cookie_present=false 
 
GET /pagead/viewthroughconversion/123456789/?random=156&value=10&label=AdswCDsAW1AMQ74adD&guid=ON&script=0&url=http://www.example.com/tracking_test.html &ctc_id=CVSAQgSSSB0CDDDD&ct_cookie_present=false HTTP/1.1 
Host: googleads.g.doubleclick.net 
User-Agent: Mozilla/5.0 (Ubuntu; X11; Linux i686; rv:9.0.1) Gecko/20100101 Firefox/9.0.1 
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 
Accept-Language: en-us,en;q=0.5 
Accept-Encoding: gzip, deflate 
Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.7 
Connection: keep-alive 
Cookie: id=223321eef4e01008a||t=13554324461|et=710|cs=002243fd486f0e60cd71ecd012; __ar_v4=YPFL37FMYVFISEEFZYY4JJG%3A20120124%3A2%7C4Q6BPY74FFSDFLVM57FRXB%3A20120120%3A4%7CWP23UARADFGF57LSWMZXZSJ%3A20120113%3A2%7CUAZEVLFSDFGGPMOT77ULX3%3A20120112%3A8%7CDIPHX7THRNCIRKSFGGYF%3A20120112%3A5%7CU6PZANHGRASDFBIDRUUZ3E%3A20120111%3A9%7CN34ZPOW5TSFGGFDFHM2G4%3A20120111%3A24%7CU2CSDFGE2RBBLPPB4KOV37%3A20120111%3A5%7CYCLARV5PGRB7ROUG4SQYSA%3A20120111%3A21%7CGVKFWCGI6VHFRLSDFGVK%3A20120111%3A4%7CSDUW4IOBWFCKJBSDFG7TI%3A20120111%3A7%7CDHWKRULTQNEWPDGH4OZP%3A20120124%3A3%7CGL3MUA642RHBBDFGDACBN%3A20120124%3A1%7CR5JVENCYJVAOFEDG4JSUJ%3A20120124%3A1; _drt_=NO_DATA 
 
HTTP/1.1 200 OK 
P3P: policyref="http://googleads.g.doubleclick.net/pagead/gcn_p3p_.xml", CP="CURa ADMa DEVa TAIo PSAo PSDo OUR IND UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR" 
Date: Thu, 26 Jan 2012 14:14:01 GMT 
Pragma: no-cache 
Expires: Fri, 01 Jan 1990 00:00:00 GMT 
Cache-Control: no-cache, must-revalidate 
Content-Type: image/gif 
X-Content-Type-Options: nosniff 
Server: cafe 
Content-Length: 42 
X-XSS-Protection: 1; mode=block
HTTP Log of the Response from AdWords

More importantly, once this code was installed on my site I started to get conversions being registered against my keywords in AdWords when people sent me messages:

A Conversion Correctly Logged for a Keyword
A Conversion Correctly Logged for a Keyword

The conversions were correctly categorised based on the Goal label:

Conversion Logged for the Contact Goal
Conversion Logged for the Contact Goal

And the additional URL parameter has been recorded:

Conversion Logged for the Page URL
Conversion Logged for the Page URL

Conclusion

As my testing shows, this is a valid approach to tracking conversions in AdWords for JavaScript events. The advantages of using this method is that it's reasonably simple to implement, and there's a good hook for determining when the tracking is successful so the user can continue with their usage of your site without delays.

However, the tracking pixel that's generated via the AdWords JavaScript contains additional parameters, but I'm not sure what their purpose is; if they're being generated then there must be a reason and some functionality could be lost: For example, I noticed some code referring to remarketing in there, but I don't know how important it is; I'm not using remarketing at the moment, so I haven't tested to see if my tracking impacts it.

In the future I'll try out a different approach that downloads and executes the JavaScript code; however, I'd need to find a good hook for the callback. I'm also going to extend the functionality to track my adCenter campaigns, which have a similar issue. Finally, there's the issue of combining this with GA tracking: I actually had to do this on my own site, so I'll write it up into a post at some point.

← Using the AdWords API Sandbox Simple Usability Oversights →

To help me decide what to write about, I'd like to asses the value of my blog posts to see which ones people find most beneficial. If you found the information here useful then could you please +1 it, but if you didn't find what you were looking for then please leave a comment and I'll be happy to help where I can. Thanks!

Comments

I'm keen to get feedback on my posts, so if you have any questions or comments, then please send me a message and I'll be happy to help.

Gio

That's awesome! I'm waiting for Adcenter's one :) What about replacing onclick with onmousedown ? Should it work differently?

Reply

Thank you, just what I was looking for! I was thinking about doing something like this and was just getting started researching but with this it took me 5 mins to get it implemented. I already had a function that was capturing all clicks and sending tracking information for other reasons so it was very easy.

Reply

Great info here! Have been looking for a similar solution- was wondering if you could share the page with the functioning conversion script on it?

Reply

Ewan

Sure, I'm using it on the contact form of my company site; however, the code there uses jQuery, has some modifications for registering a GA conversion, and is mixed up with all the Drupal output, so get back to me if you have trouble finding it.

Reply