One common method of event tagging in Google Tag Manager uses GTM's built-in interaction tracking to fire tags off the classes and IDs that are already on the page. This method is fast and convenient, but not always robust in the long term because site updates often edit or remove the HTML elements that your tracking is based on.
There are a few options to deal with this, e.g. moving to a fully developer-maintained data layer. This option comes with its own disadvantages, though, since it brings you back to long wait times and lack of flexibility.
In this post I'll discuss another approach to event tracking: custom data attributes. Custom data attributes get added to the HTML just like regular IDs and classes, and can therefore leverage all the benefits of GTM's built-in triggers. However, they're explicitly designed to contain data, so your developers can change site layout and design without altering the site elements that your tracking is based on. In a practical sense, data attributes also keep analytics top-of-mind (i.e. less likely to overlooked) for your site developers, as they'll be visible to them every time they edit the source code.
DATA ATTRIBUTES HTML SYNTAX
Data attributes are input as key-value pairs consisting of an attribute name and an attribute value.
- Attribute name: should be prefixed with "data-" and shouldn't contain any capital letters.
- Attribute value: any string (numbers would be treated as a string as well)
For example, a data attribute may contain detail about the position of a product tile on a page, where the attribute name is data-tile-position, and the attribute value is the position in the list.
<id = "products">
<div class="product_tiles">
<div class ="product_box" data-tile-position="1">
<div class ="product_box" data-tile-position="2">
</div>
</div>
In this example, there is a product listing page containing 2 products that have been marked with data-tile-position = "1" and data-tile-position = "2". Now your developers can freely change the class name from "product_box" to, say, "product_card", without breaking your analytics tracking.
ACCESS DATA ATTRIBUTES WITH JAVASCRIPT
1) Select HTML elements:
Using the above example, if we wanted to select all the HTML elements with a data-tile-position data attribute, we could using the following JS:
document.querySelectorAll('[data-tile-position]');
If we want to select HTML elements with a specific attribute value, it would be like this:
document.querySelectorAll('[data-tile-position="1"]');
2) Return data attribute values:
Returning the values associated with data attribute requires accessing the element's dataset
property. There are a couple things to be aware of that make accessing data attribute values different from other HTML elements: 1) you need to drop the "data" prefix, and 2) all dashes are converted to camelCase, like this:
var tilePosition = dataset.tilePosition;
DATA ATTRIBUTES FOR GOOGLE TAG MANAGER
VARIABLES:
Adding data attributes into a GTM variable will let you collect the value of your data attribute when the element is clicked. In this example, you'd use this to identify what tile position was clicked on.
In Google Tag Manager, navigate to Variables > New > Data Layer Variable.
Add your data attribute name like this: gtm.element.dataset.{attribute name in camelCase}
. So data-tile-position would be entered as gtm.element.dataset.tilePosition
.
TRIGGERS:
Adding data attributes to a GTM trigger lets you fire events when a user clicks on an element containing your data attribute.
In GTM, navigate to Triggers > New > Click Just Links. Choose "Some Link Clicks" and choose the following condition:
Click Element matches CSS selector [data-tile-position], [data-tile-position] *
(the asterisk is to include clicks on any nested elements)
You can now put this all together in Google Tag Manager to create an event tag that tracks clicks the position of each product click, like this:
Track Type = Universal Analytics > Event
Category = Product Tiles
Action = Clicked Position {{DL - dataset.tilePosition}}
Label = {{Click URL}}
Trigger = Click - Product Tile
The resulting event report will look something like this:
ADVANCED CASE
Just to make things slightly more complicated (more realistic!), what if your HTML actually nests part of the product tile under the data attribute? For example, the HTML might look like this:
<id = "products">
<div class="product_tiles">
<div class ="product_box" data-tile-position="1">
<div class = "square">
<a class = "link" href="/product-link"> </a></div>
...
Here, someone might not click on the exact part of the element that contains your data attribute. In this case you'll want to look up the DOM with the "closest" function. You would add this into a custom JavaScript variable in GTM, and use this Variable in place of the dataset.tilePosition data layer Variable above.:
function(){
var e = {{Click Element}};
var closestTile = e.closest('[data-tile-position]');
return closestTile.dataset.tilePosition;
}
As before, it uses the data attribute name ("data-tile-position") in the closest function to retrieve the entire HTML element, and then uses camelCase to return the data attribute value.
Note that here you'd only need to replace your Variable. You can still use the Trigger as shown above, because the trigger already contains an asterisk to include nested HTML elements.
I didn't know about this trick! I've spent a month setting up GTM events based on classes, only to discover that a dev changed one of those classes two weeks later. Thanks fro the tip.
Haha, yeah, that's happened to me many times as well. Thanks for your comment!
is there a way to get data-attribute without click event?
Sure, the examples given in the Access Data Attributes with Javascript section don’t require click events. If you're adding it to GTM, you would just add those code snippets to a custom JS function like this:
function(){
document.querySelector("[data-tile-position]")
}
Hi, is possible to combine attributes with the classes they are nested in?
Thank you
Hey Martin, yep, they work the same as any other DOM element. So, if your data attribute is nested within a "product_title" class, with JS you could select it like this:
document.querySelector('.product_title [data-tile-position]');
Similarly, with GTM you could set your trigger like:
Click Element matches CSS Selector .product_title [data-tile-position]
Please let me know if that answers your question.
Hi, I configured my data layer variable, as you stated, with gtm.element.dataset.event.title (for receiving the value of "data-title="value"). But when I configure a click-event and trying to use this variable as a tag-label, the result is "undefined".
Any idea how to fix that?
Best wishes, and thanks for your tutorial so far!
Manu
Hey Manu, this is most likely because your data attribute is not on the exact element that gets clicked.
If so, it may help to do a link-click trigger instead of all clicks. If that doesn't work either, you will probably need to use the "Advanced Case" script to crawl up the DOM and return the data attribute with the closest function.
Hi Ana, I'm trying to grab an attribute from the element that was clicked but it doesn't use the dataset standard. I want to grab this "doctype" and pass it in a GA tag in GTM as an event and use that as a custom dimension. I tried using a DOM variable with CSS selector but that just grabs the first instance of class.
Thanks
Looks like it stripped my code out.
Any ways the a tag has the follow attributes I would like to capture when the link is clicked:
doctype="Terms of Service" mfg="Company Name" class="download-link"
You should be able to use a custom JS variable to get the value of an attribute, like this:
function() {
var e = {{Click Element}};
var closestDocType = e.closest('[docType]');
return closestDocType.getAttribute("docType");
}
Check if that works. I've written a few posts about this technique, you can find them categorized under "DOM Scraping": https://mixedanalytics.com/blog/category/dom-scraping/
Hey,
Very clear explanation and uses case.
Thks
Also I have a question.
How catch attributes when data attributes look like this :
data-gtm-autopromo="{"emplacement":"menu2","brand":"coca","campaign":"trade"}" class=nav
Thank you 🙂
Sorry, I haven't seen a whole JSON object stored in a data attribute before. You can use
gtm.element.dataset.gtmAutopromo
in a datalayer variable to grab the whole object, but I'm not sure how you'd break out the specific attributes. I think you'd need to use the JSON.parse() method in a custom JS var to parse it.