The Problem: Platform Agnosticism
Enhanced Ecommerce tracking is infinitely better than the standard Ecommerce plugin (ecommerce.js). It offers deep insight into your website’s customer journey, allowing you to measure product impressions, shopping cart behaviour, checkout abandonments, and so on.
The most efficient way to implement Enhanced Ecommerce is with Google Tag Manager (GTM), and the bulk of the work necessary to do so is in configuring your site’s Data Layer (see Google’s Documentation). Once the relevant attributes and values are present on the page, enabling Enhanced Ecommerce in GTM is as simple as ticking a box.
However, in larger organisations – particularly those valuing data-led decision-making – the Data Layer often has multiple stakeholders and needs to serve multiple analytics platforms. For this reason, a degree of platform agnosticism is always encouraged; it minimizes the number of moving parts in your reporting setup and keeps things lean and DRY (don’t repeat yourself!).
Customisations to Enhanced Ecommerce tracking frequently require us to use proprietary, GA-specific syntax in our Data Layer. To illustrate the problem, I’ve created the following example based on a real problem I encountered with one of our Analytics clients:
<script>
window.dataLayer = window.dataLayer || [];
dataLayer.push({
"ecommerce": {
"purchase": {
"actionField": {
"id": "123456",
"affiliation": "Outdoor Adventure Park",
"revenue": "29.98",
"location": "Bristol" // Our custom purchase attribute
},
"products": [{
"name": "Quad Biking",
"id": "15727899",
"category": "Vehicle Track",
"price": "14.99",
"quantity": "1"
},
{
"name": "Clay Pigeons",
"id": "16682710",
"category": "Shooting Range",
"price": "14.99",
"quantity": "1"
}]
}
}
});
</script>
Our (fictional) website allows users to make bookings at a number of outdoor activity centres. As you can see, the Data Layer above corresponds to our purchase page, and it shows that our customer has purchased two activities – clay pigeon shooting and quad biking – at the Bristol venue.
Our nice, platform-agnostic Data Layer includes the name of the venue in the actionField
object, where it is available to all analytics platforms under the name location
. Makes sense, right? Because users are asked to select a venue during the first step of the checkout process, location is a purchase-level attribute, rather than product-level: all transactions containing multiple items relate to a single location.
However… let’s say we want to push location to Google Analytics as a product-scoped custom dimension, so we can aggregate revenue by location. Doing so requires an arbitrary modification to each item in the products array:
"products": [{
"name": "Quad Biking",
"id": "15727899",
"category": "Vehicle Track",
"price": "14.99",
"quantity": "1",
"dimension3": "Bristol" // Setting a custom dimension
}]
For various (completely valid) reasons, our development team do not wish to make this change:
- Key name (“dimension3”) is specific to GA and not intuitive
- Hard-coded dimension index number, which is liable to change
- Property must be added to every item in products array, despite other analytics platforms accessing it from its logical position in
actionField
So, what do we do?
The Solution: A GTM JavaScript Variable
In the Ecommerce settings area of your GA tag, you can choose to use a GTM variable instead of grabbing the information directly from the Data Layer. This means we can fetch our platform-agnostic ecommerce payload, manipulate it with a custom JavaScript variable, and feed it back into our GA tag in precisely the required format.
First, we’ll create a Data Layer variable which fetches the ecommerce
object. We’ll call it ‘dlv – ecommerce – full’. Be sure to select Version 1 of the Data Layer, since this will ensure that GTM only accesses the payload which was most recently pushed into the Data Layer – see this excellent primer on Data Layer versions by Simo Ahava.
What we want to do is copy the value of the location
property in our ecommerce payload and add it to each item in the products
array. To do this, we’ll create a Custom JavaScript variable which we’ll call ‘ecom – Purchase with Dimension’.
The script is quite simple – we access our original ecommerce Data Layer Variable under the name ecom
, and get the value of its location
property from actionField
using dot notation. We then have a simple loop which iterates through each item in the products
array and adds a dimension3
property to each, with the location as its value. Finally, we return the manipulated data as a new ecommerce object.
The last step is to open your Enhanced Ecommerce enabled GA tag and untick the box for ‘Use Data Layer’. Instead, reference your newly-created ecommerce object:
And that’s all you need to do. Assuming your product-scoped custom dimension in slot 3 is configured in your GA property, valuable data will start accumulating immediately.
The most important thing to remember is that your Custom JavaScript variable must return a correctly-formatted and valid ecommerce object, exactly as you might find in a GA-specific Data Layer. As long as it does, and you’ve referenced this variable in your GA tag, GTM will use your new version instead of the generic on-page version.
While I’ve used a product-scoped custom dimension as my example, you can really get quite imaginative with this – by combining your Custom JavaScript variable with other variable types such as DOM Elements and Lookup Tables, you can create a highly customised ecommerce payload for GA.
However, don’t get carried away. Ideally this technique should be used to avoid proprietary customisations to your Data Layer, rather than as a hack to sidestep any of its fundamental shortcomings. Don’t start screen scraping, or doing anything that will incur loads of development debt further down the line. In the words of esteemed GTM expert Uncle Ben, “with great power comes great responsibility”.
If you need assistance with an Enhanced Ecommerce implementation or would like to discuss your GTM setup with a consultant, you can reach our experts here.
Thanks for reading! Let me know what you think in the comments or on Twitter.