David Hefendehl - Manager eCommerce Group der netzkern AG
Head of Online Marketing

Google Content Experiments with Google Tag Manager – Extrem Coding

According to Google you cannot serve Content Experiments (GCX) using Google Tag Manager (GTM) (https://developers.google.com/tag-manager/). This is because the GCX scripts need to be rendered in the head section of the page but GTM is embedded into the body of the page. My problem was that I have a client where we don’t have access to the sites source code but we do have Google Tag Manager running.

The question for my client was: "Will a certain product sell better in one category with a product image closer to that category or can I still use the generic product image." Think of a hammer that sells well in DIY but not so good in Masonry Tools. The suspicion is, that showing an image that connects more to the category it’s shown in will be better received by our customers.

Fortunately Google announced the GCX API in June and so the Online Marketing Team here at netzkern got to work.

The setting for this test was: Serve variations using the GCX API with Google Tag Manager. Waiting for IT would just be a month long process. As the product sells under the same SKU in many categories, we had to tag the participants to only track those, who have seen the variation and then purchased the product. We're not interested in customers who just purchase the product, so a "normal" conversion wouldn't do in GCX.

Let pigs fly

The Variation Page

Via GTM we can load the GCX script, www.google-analytics.com/cx/api.js?experiment=YOUR-ID-HERE, through a DOM insertion via a Custom HTML Tag. Here my UserTimings Script came in handy. The script in the Custom HTML Tag contains the logic to pick a variation and then manipulate the content on the page accordingly. It then tags our participant to identify him on the thankYou page later on. GCX takes care that the user will from on always see this very variation.

Within Google Analytics we create an event based goal as it is easiest to track in this scenario. We use this GOAL as our conversion point in the test setup, so be sure to create it before you create the actual experiment. After you created this GOAL you can go about setting up the experiment. All you need to do is setup an API Experiment, i.e., use fake URLs and ignore all warnings. All you need is the Experiment-ID displayed in step 3.

Goal setup in Google Analytics
  (left Google Analytics Goal, right Google Content Experiment Step)

The Goal Page

My goal page was already setup to collect transaction data so I could reuse my addTrans dataLayer event as a trigger. As soon as this event comes into GTM, I read the transactionProducts array through a simple macro that passes on the values to another custom HTML Tag. This tag, getSKUFromProductArray does three things. First it checks if a participant has purchased. Then if this transaction contained any of the desired products. My products comes in two variations so two SKUs. If so, we can fire an event back into GTM that in turn triggers our Goal event in GA. This last bit could as well fire the GA Event itself as we have access to that _gaq object at this stage.

Below I have listed the tags and code you will need to setup a similar scenario. I am sure there is a lot of potential for optimizing this code, feel free to share it in the comments.

You will need the following Tags in GTM :

This tag loads the GCX API, delivers the variation in the participant’s browser and tags it for later use. <script>
var chosenVariation = 0;
var domReadyVar = false;
function domReady() {
// Wait for the DOM to load, then execute the view for the chosen variation.
// Execute the chosen view
// wait for jQuery
function startDomReady() {
if(!domReadyVar && chosenVariation && jQuery) {
domReadyVar = true;
// load JavaScript in
chosenVariation = cxApi.chooseVariation();
dataLayer.push({event: 'setExpCustVar'}); // fire an event for GTM to set teh Custom Var. As I don't have access to _gaq here I need a custom HTMl tag in GTM
loadByJs('//ajax.googleapis.com/ajax/libs/jquery/2.0.0/jquery.min.js',function() {
// the function below loads javaScript and appends it to the head element
function loadByJs(url,callback) {
var head = document.getElementsByTagName("head")[0] || document.documentElement;
var done = false;
var js = document.createElement('script');
js.async = true;
js.src = url;
js.onload = js.onreadystatechange = function() {
if ( done !=true && (!js.readyState || js.readyState === "loaded" || js.readyState === "complete") ) { // handle X-Browser, especially IE8
done = true;
// Handle memory leak in IE
js.onload = js.onreadystatechange = null
if ( head && js.parentNode ) {
head.removeChild( js );
head.insertBefore( js, head.lastChild );
} </script>
// this does an image replace
var image_variations = [
'/images/original.jpg', // original
'/images/variation.jpg' // variation 1
// define as many as you need here
var pageVariations = [
function() {}, // Original: Do nothing. This will render the default HTML.
function() { // Variation 1:
exp_image = document.getElementById('YOUR-DIV-ID-HERE');
exp_image.src = image_variations[chosenVariation];
exp_image.parentNode.href='/images/variation_large.jpg'; // I need to manipulate a URL around teh image too

As we can't use the default GA tracking to set CustomVars we need a nother Custom HTMl tag to do so. The rule employed to stop this tag fiering all the time is "event:contains:setExpCustVar" that was pushed into the dataLayer in the ABTest tag. _gaq.push(['_setAccount', 'UA-1-YOUR_ID_HERE']);
_gaq.push(['_setCustomVar', 1, 'UserType', 'participant', 1]);
_gaq.push(['_trackEvent', 'usertype', 'set']);

This is the main tag on the thank you page. It checks for the participant,then loops through the SKUs and if successful triggers the conversion event. The rule here is the same I use for my e-commerce tracking, " event:contains:onlyWhenAddTrans" . <script>
var participant = false;
checkProductsArray = true;
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-1-YOUR_ID_HERE']);
_gaq.push(function() {
var pageTracker = _gat._getTrackerByName(); // Gets the default tracker.
var visitorCustomVar1Value = pageTracker._getVisitorCustomVar(1);
{//decides if customer has cookie or not
var productArray = {{getProductArray}}; // here we get the values of the transactionProducts array through a macro
for(i=0;i {
for (var key in productArray[i]) // loop through the productArray value from macro getProductArray
if(key=='sku' && (productArray[i][key]=='TARGET-SKU-1' || productArray[i][key]=='TARGET-SKU-2') && checkProductsArray == true) // only need to check SKU, and only if the SKU matches our products and once only
dataLayer.push({'event' : 'goalReached'}); // fire our conversion event in GA, could prob. be done directly avoiding another round in GTM
checkProductsArray = false; // we have our conversion and don't need to track another in case the participant has odered the two version available
_gaq.push(['_deleteCustomVar', 1]); // delete the custom var as we no longer need it

expGoalReached This is our conversion goal. Here we can use the standard GA implementation in GTM. The rule here is my rather non-descript " fireEventInGA" that is triggered through dataLayer.push({'event' : 'goalReached'}); in getSKUFromProductsArray 

Experiment Event in Google Tag Manager

Here is an overview of how all of this plays together, click to enlarge. Please do feel free to comment below.

Visualization of how to setup Google Content Experiments with Google Tag manager





Thanks for all the great info! Did you have to set the serving framework to API like it says in Experiments API documentation? Thanks, Shay

am 29.07.2013



Hi Shay, No there was no need to set it up as an API experiment. Just follow the steps outlined and it should work fine. David

am 29.07.2013



Hey David, have you tried this with Universal analytics recently?

am 21.04.2015



Hi Maggie, No I haven't tried this with UA. We're using different tools now. It was a hack to start with and I think Google might have been closing the loopholes I exploited here.

am 22.04.2015

Kommentar hinzufügen
Vor und Zuname
E-Mail bei weiteren Kommentaren
Mein Kommentar