Tracking Clicks Using Custom Data Attributes, Google Tag Manager, and Google Analytics


Let's Go Pens

Let’s Go Pens!

By setting up some simple Macros, Rules and Tags in Google Tag Manager you can track anything you want on your site as an Event or Virtual Pageview by simply adding Custom Data Attributes to the on-page HTML elements, rather than adding additional Google Analytics tracking code to your website. This has several benefits:

  1. You keep all your tracking code in a single location, Google Tag Manager. Rather than have tracking code all over various pages and templates, now all your actual tracking is in one location.
  2. Your analytics become fuller with more insight. No other method lets you as easily track external links, downloads, or events on your site. Documents which before were untracked, now can be quickly tracked with various specific dimensions for much greater insight.
  3. Your site tracking becomes less prone to technical errors. Rather than 100 lines of tracking code all over the place, or even on specific links, now your actual tracking code is in one place and less likely to do something horrible like break your entire visitor session.
  4. You can easily add additional tracking in the future. By following the rules below you can almost immediately and easily track anything on your website that is clicked.

What are Custom Data Attributes?

Custom Data Attributes  let you add your own information to Tags in HTML. Let’s say you have a number of documents on your site, some involve Football, and some involve Hockey, and you want to be able to differentiate the two.  It’s not always obvious in their URLs or titles which is which. For instance maybe they look like this:

<a href=”/howtoscore.pdf”>How To Score</a>
<a href=”/howtohit.doc”>How to Hit</a>

There is very little information in those links, about those documents. To help differentiate them, we can add the following Custom Data Attributes:

<a href=”howtoscore.pdf” data-sport=”football”>How To Score</a>
<a href=”howtohit.pdf” data-sport=”hockey”>How to Hit</a>

The format is  “data-” followed by a unique word to identify the Custom Data Attribute. Now because of this Custom Data Attribute, “data-sport“, we can better tell which link refers to which sport . You can also have multiple custom attributes and have them refer to other information you want to convey. For instance, in this case, you could have the author of the document, or even the date of publication:

<a href=”howtoscore.pdf” data-sport=”football” data-author=”john smith” data-published=”august 2012″>How To Score</a>
<a href=”howtohit.pdf” data-sport=”hockey” data-author=”mary jones” data-published=”may 2013″>How to Hit</a>

Custom Data Attributes are a great way to attach metadata like this to HTML elements without having it be visible to the user, other than by viewing the source code of the page.

Pulling Custom Data Into Google Tag Manager

Google Tag Manager is just one way that we can interact with these Custom Data Attributes. We can reference the custom data of an element from within Google Tag Manager. An easy way would be to do this through a Link Click Listener Tag, and then referencing the custom data of a clicked element through a Macro.

1. In Google Tag Manager, create a Link Click Listener that fires on every page.

Each time a user clicks on a link on a page, an “event” gets pushed to the data layer named “gtm.linkClick.”


2. Create some Macros for your Custom Data Attributes.

Each attribute should have its own macro with a Macro Type of Data Layer Variable. The key is the Data Layer Variable Name. Each Custom Data Attribute has two parts as we mentioned above, the first being “data-” and the second being something unique like “sport” or “author“. Tag Manager takes care of the heavy lifting here and adds the clicked item to the data layer as “gtm.element.” If there are any data attributes on the element, it nests these values under “dataset.”  This is where you’ll find that second unique part. Putting this all together, you would reference these attributes by putting something like “” into the Data Layer Variable Name field of the Macro. For our other examples, we could use either “” or “gtm.element.dataset.published.”


To capture all three, create an individual macro for each Custom Data Attribute you have included on your link. I like to modify the default value to “(not set)” if there is no value.

3. Create another Macro for just the URL Path, by adjusting the Component Type.


This will extract just the path value of the element clicked, stripping off the hostname. In this case it would have the value of  “/howtohit.pdf” rather than

4. Create a Macro for the Element Text

Newer GTM accounts may get this by default, older ones you’ll need to create it manually. This gives you the value of the HTML text inside the element, in this case the words “How To Hit”


Results of These Macros

With the above implemented, whenever someone clicks on a link on the page, the Link Click Listener captures that link as the “element” that has been clicked, and the Macros pulls the data from that element. If you were to click the “How to Hit” document link, it would create an “event” called gtm.linkClick, and until the next “event” processed by Google Tag Manager, the macro values which you set up will contain the values of those data attributes, and the link itself.

So if you defined a Macro for dlv-sport defined as, and someone clicked on the “How to Hit” link then the Macro {{dlv-sport}} would hold the value of “hockey”, {{dlv-author}} would hold the value of “mary jones” and {{dlv-published}} would hold the value of “may 2013”.  Also, {{element url path}} would equal “/howtohit.pdf” and {{element text}} would equal “How To Hit.”

Keep in mind, that as soon as another element is clicked, it could overwrite these values, so if you want to act on them, you can use the “event” in Google Tag Manager to fire some tags.

Tracking These Clicks In Google Analytics

From this point it’s easy to create tags to fire events or virtual pageviews based on the Custom Data Attributes, and even leverage other attributes as Custom Dimensions. Let’s say we want to track all document clicks on our site, to pdf or doc files, as Virtual Pageviews, and we want to record the data-sport, data-author, and data-published Custom Data Attribute values as Custom Dimensions.

1. Create the Custom Dimensions inside of Google Analytics

In the admin section of Google Analytics, select the web property you are tracking into from the drop down in the middle column, then select Custom Definitions and Custom Dimensions under that property. Add three new custom dimensions as “hit” scope, and name them “Sport”, “Author”, and “Published.” Record their Index numbers (In this case Sport:1, Author:2, Published:3) so we can use them in Google Tag Manager.




2. Create a Macro to Check Whether The Link Clicked Is a Document


function (){
var thisURL = “{{element url}}”;
var docPatt = /.pdf$|.doc$/i;
return docPatt.test(thisURL);

This macro will check the clicked url for the pattern of pdf or doc, and if it ends in either of those extensions, thanks to our matching a Regular Expression pattern, pass “true” back as the value of the macro. This way, we can create a rule for just these documents.

5. Create a Rule for when someone clicks on a document link.


This rule will only fire a tag if someone has clicked a link, but also that document has to run through the IsDoc macro, and confirm that it ends with a .pdf or a .doc extension. If it does, the tag this rule is on will fire.

6. Create The Virtual Pageview Tag



Be sure to have this fire on the rule: On Document Download.

Congratulations! Once this is published, you will now track all clicks to any pdf or document on your site as Virtual Pageviews, and if they have Custom Data Attributes of Sport, Author, or Published then those will be recorded as Custom Dimensions as well. If we did this for the above example, the page would be seen in Google Analytics as “/document-downloads/howtohit.pdf” with a Page Title of “How To Hit” and the Custom Dimension values of Sport containing “hockey“, Author containing “mary smith“, and Published containing “may 2013“. You could not only see which of those documents were getting downloaded, but you could see which authors or sports were more popular for content, etc.

What Else Can We Do

There are many applications. For instance, you could track these items as events as well and pass the information for the Event as Custom Data Attributes. Let’s say you want to track the click of a buy now button as an event.

<a href=”buynow.htm”>Click Me To Buy Now</a>

First, you can add Custom Data Attributes to the link like this:

<a href=”buynow.htm” data-category=”Intent” data-action=”Buy Now” data-label=”Main CTA” data-value=”1″>Click Me To Buy Now</a>

That alone won’t do anything than surface that information to Google Tag Manager. Let’s assume you are still using the Link Click Listener, as well as capturing all thoee Custom Data Attributes such as data-category, data-action, data-label, and data-value as Data Layer Variables via Macros named {{dlv-category}}, {{dlv-label}}, {{dlv-action}}, and {{dlv-value}}, all with default values of 0. If this was the case, you could fire an event in Google Tag Manager, which has a Rule for when {{dlv-category}} does not contain 0. That could be enough to indicate that it should be tracked as an Event in Google Analytics.

You can even change the Non-Interaction Hit to be a value for another Macro named {{dlv-noninteraction}} and have the default set to false. Then if you WANT the item to be a non-interaction event, you can pass that as an additional Custom Data Attribute:

<a href=”buynow.htm” data-category=”Intent” data-action=”Buy Now” data-label=”Main CTA” data-value=”1″ data-noninteraction=”1″>Click Me To Buy Now</a>


What about firing an Event as well as a Virtual Pageview at the same time?

As long as the rules match, you can have multiple tags fire, and track something as a Virtual Pageview as well as an Event.


Using Custom Data Attributes along with Google Tag Manager is a great way to easily implement a variety of Google Analytics tracking Tags on your website now, as well as giving you a very flexible mechanism for easily adding new tracking in the future.

Can you think of some other cool ways to use Custom Data Attributes, GTM ,and GA together? Let me know in the comments!

Sayf is a former LunaMetrician and contributor to our blog.

  • Geo

    A nice post for all who are struggling to make GTM work. I would argue that instead of occupying a custom dimension slot pretty much the same result could have been achieved by simply using the EventAction or EventLabel fields of an event call. If it is a virtual pageview scenario – simply put what you want to analyze in the URL.

    Furthermore, almost every time I’ve been required to use GTM by a client it has been much more painful to do even the most basic of things, compared to a plain and simple setup. It’s mostly an unnecessary layer of complication for me. The little gains from using it are quickly dwarfed by the complexity of the rules and macros you have to setup for even the most basic of things.

    And, in the end, no matter how many containers you wrap the code in it will still rely on JS calls made from outside the containers (dataLayer pushes or others) for any advanced functionality. In this case – the altering of the links with the additional attribute is equivalent to setting up JS calls on them. So in fact that your code is NOT in one place anymore than it is with a trivial setup.

  • Sayf Sharif


    Certainly, how you track something should be adjusted on a case by case basis, and determine what’s the most appropriate, as far as events, virtual pageviews, custom dimensions, or tracking on parameters. The great thing about doing this through Google Tag Manager is how quickly and easily you could change this setup. If I had to manually tag 2,000 different document links, going back to manually change all of them would be tedious, whereas in GTM it would take all of 1 minute.

    I certainly was frustrated with GTM when I first started using it, but the more I work with it, the more I’ve been swung over to being an advocate for it. Even for just 1 analyst/developer on a small site doing nothing complicated, it’s great for it’s debugging abilities, as well as keeping record of older versions, allowing you to roll back your tags if necessary. On complicated and deep sites with long production schedules it’s been amazing.

    And while it’s true that with the dataLayer or a dataLayer.push, or even the Custom Data Attributes, you have “code” on the page, its code that is communicating with GTM, and in GTM you can have all the actual tags that communicate with Google Analytics. No longer will that trackEvent call buried in an included javascript file have to be dug up to explain why the landing page conversions have all dropped to zero.

    I honestly don’t think a single analyst here at LunaMetrics would go back to a non-GTM setup. There are just too many benefits we’ve discovered using it to succinctly list.

    If anyone is really struggling with it (which I understand as I was there at one point), i recommend that they explore it some more, or even take a course like the Google Tag Manager course we are offering coming up in New York or Washington DC.

  • Geo

    Thank you for your response Sayf. I’m glad GTM is helping the LM team in its setups, it shows because this is not the first post in this blog praising GTM. The benefits still allude me, however.

    Now, onto the points you make… In the example from the article – web devs usually have templates for the site so there is no need to go in and change all links individually. It’s really not different at all whether you use GTM or not. Or perhaps you can give me an and the other readers an example where GTM really makes the difference?

    For debugging and for calls buried somewhere on the site – the GA Debugger extentions for Chrome does wonders if you can’t spot the issue in the GA reports themselves. If it is a pure JS issue, you would still need to resort to the Chrome/Firefox/IE JS console, no matter if the code is in a GTM container or not.

  • Sayf Sharif


    If only every client I worked with had templates for every site. You’d be surprised how many companies, even modern tech companies, have a plethora of old static HTML pages, usually knowledge base type sections. Before GTM we would simply include a single JavaScript file on those pages, which would allow us to modify the code later. Add in some jQuery in addition to the tracking code, you name it. Of course that assumes that each page should use the same jQuery, or same GATC. I’ve worked with clients where those thousands of pages were across multiple domains, requiring a variety of setups, and you end up working with a number of different javascript include files for the tracking code with a variety of differences. It’s so much more convenient, and organized, to have just the single container code on all those pages, and worry about the differences inside of GTM.

    A GTM container code placed on 1,000 static pages across 10 domains can easily modify some setting of the GATC based on the URL Host macro, etc. One piece of code across all the sites and pages, and a couple simple macros.

    Not only can having a variety of implementations across a Cross Domain site require a variety of files, but it also presupposes that you have competent reliable developers who implement quickly. I’ve worked with a number like that and it’s wonderful, but it’s not always the case. I’ve also worked in conditions where you may have to wait 2 months for a developer to push a new version of the website live. Using GTM lets the marketing department make changes and additions to their tracking code without being beholden to the developers having the time for them.

    I love the GA Debugger extension, though I hate when it sometimes doesn’t load or work and I have to click and reload the page a few times. 🙂 It’s just not equivalent though. GA Debugger is a great way to find out what’s not working on your site, while GTM Debugging lets you see what’s wrong BEFORE it’s on your site. Particularly in the cases where you have little choice but to push changes to a live site, rather than a development site, the ability to debug something before it goes live can be extremely valuable.

    Who doesn’t have a development test site? Again… you’d be surprised.

    When you have situations with a single super competent developer with full access to all files, can do anything they want, on good and effective test servers, GTM may lose some of it’s necessity. Can a developer code Cross Domain tracking via on page, and JavaScript and jQuery? Sure, but even the best developers make mistakes, and miss links, where GTM won’t. Also why recreate the library? Why use jQuery rather than just code up your own scripts from scratch? There are a number of tags in GTM that already do the heavy lifting for you. Why recreate the script rules in a template to deliver different remarketing tags on various product pages, when you can do it much easier and quicker and cleaner in GTM?

    Another reason is more organization focused. Even if you have a super developer who can do anything and everything instantly, you won’t have him forever. As soon as he or she is gone you’ll hire someone new who might not know that person’s custom code, or where they put the remarketing tag.

    And let’s be honest the super developers are few and far between. More likely a new developer will show up and have to figure everything out from scratch through poorly commented code.

    There are even more benefits than what I’m listing out here. As someone who developed both front and server side code for over a decade before launching into Analytics, as well as being someone who took some time to get used to using Windows and Mac over the command line, I get the feeling of having more control over things when you are actually manually coding onto a page. I just have enough experience with GTM now that it’s become obvious that it doesn’t really replace coding, it just supplements it, in tons of great ways.

    I hope you don’t give up on it, I really think it’s worth it.

  • Geo


    I really appreciate the response!

    I definately get your point about the multiple domain scenarios and the old static sites. Lack of dev sites is a pain, indeed, another point for GTM.

    I get your point about developers as well. Being one I guess I have a much easier time doing GA related consulting than most people. I mean, I do have a case when an implementation instruction of literally *one line* was implemented completely the wrong way, but usually I have few problems with devs.

    I think you’ve made a good case for GTM here. I’m beginning to think that maybe I’ve been blessed with some really excellent clients over the years as I can’t really point to scenarios as problematic as yours.

    “I love the GA Debugger extension, though I hate when it sometimes doesn’t load or work and I have to click and reload the page a few times.” – it’s the norm for me, LOL.

    Again, thanks, I may in end try and push a bit more in the GTM direction.

  • Interesting post, Sayf!

    It’s funny how sometimes tagging solutions like GTM force us to look at markup in a new way, isn’t it? 🙂

    With data- attributes, one cause for concern is if you leverage JS libraries which make use of data attributes which happen to be similarly named. This is perhaps marginal, but I’ve seen it happen with other forms of markup (e.g. “reserved” style declarations).

    As to the really interesting GTM discussion in the previous discussions, tag management has completely spoiled me. I don’t really see myself doing GA implementations (or any other tag setups) without using a TMS. There’s a simple reason for that: I’m future-proofing my tagging and JS use. I find it far more sensible to leverage a centralized interface for all tagging than to maintain bits and pieces of code scattered around a complex website.

    I think the main benefit of a tag management system is the word in the middle: management. Being able to visualize tags, their relation with arbitrary variables and values (e.g. macros in GTM) and the triggers that make these tags go off makes me a better developer. I now see redundancies where I wouldn’t have known to look for before, I see ways to make JS neater and leaner by using shared function calls (macros, again), and using a data layer is something I would do any way even if there wasn’t a TMS involved.

    And as for future-proofing, it’s really so much easier to understand how a new script or library fits into the general infrastructure of website tagging, when you can look at it in the context of all your tags. That’s one of the reasons I love working with a TMS.

    But I’m biased since, like I said, I’ve been spoiled by great clients and a wonderful tool 🙂 There are definitely things that should be improved upon, but often it’s not just the TMS fault but rather crappy markup, obscure JS resources, or the Microsoft stack (SharePoint, ePiServer…) which cause problems.

  • Sayf Sharif



    It’s funny you mention that about custom data attributes. One of the reasons we started leveraging them, was because we had a number of clients unable to modify their class or id attributes for us to recognize additional information about the elements, so we started using data attributes. It’s a good note to always be mindful of namespaces.

    Great points about tag management and GTM, thanks for adding your thoughts.

  • Ollie

    Nice Post, custom dimensions are very interesting I am always needing to find further uses of macros!

    One thing however, you don’t need to create your own macro to test whether the link clicked is a document. I would recommend using the built in function and add a {element url} to the rule matching regex (.pdf)|(.doc) to test if it is not a webpage. That way it won’t need to process a custom script. 🙂

  • Sayf Sharif


    Excellent idea!

    I think my mind got caught in a loop because I had initially set this up for a client with a Macro because we had some other things going on than just tracking docs, and needed to reuse the Macro itself in several places, and couldn’t do it the way you’re describing, but this is even better for simple solutions, where you want to keep your macros/tags/rules to a minimum.

  • Anthony

    In your example using data attributes. Are you required to add any additional code for this on your website? Or is this all purely done inside of GTM?

    Are there any browser limitations when using “gtm.element.dataset”?

  • Sayf Sharif

    Anthony, per the section above “What are Custom Data Attributes”, the actual attributes need to be added to elements on your website. Other than that though, no, the rest can be done in GTM.

  • Klaudio

    What about perfomance?

    Great post. I am working on a large website and I’m in a need to track 50 different elements across the site.

    My initial thought was to use data-attributes to target elements as they are “markup friendly”. However, after some research i came to realize that I would need a custom JS to recognize that data-attribute since there is no built in macro for them.

    So my biggest worry is performance, since i will need to track up to 30 elements per page and not only does it need to go through gtm but it also needs to go trough custom JS which only adds on the weight.

    My solution is to just add custom classes for those elements with a prefix “gtm-” so they are only used as hooks for gtm and use the classes macro to pick them up.

    What do you think about this? Is it better or is it safe for performance to go with custom JS for data-attributes?

  • Sayf Sharif

    Yeah absolutely, Klaudio. If you want to do groups of items you can do it several ways. Classes with prefixes, or even ID’s with prefixes and just lookign for those. Like tagging every image with an id of “img-XXXX” and you can easily reference all of them, etc.

  • I will try this techniques to track outbound links

  • Audrey

    I’ve searched high and low for exactly this article. Thank you for writing it!

    However, I’m a bit confused as to the difference between using the custom data attribute and simply using a dataLayer.push to get the attribute as a data layer variable for the macro.

    For example, here: How To Score
    Couldn’t you have done: How To Score ?

    Or am I completely missing the point?
    Thanks a lot!

  • Sayf Sharif

    Audrey, those links look the same, so I’m not sure what you were looking to show. (maybe it stripped out your code).

    Could you put a datalayer.Push inline in the link to push in values (assuming that’s what you mean)? Sure. Then your code would be inline, and maybe there would need to be a change. Also if you pushed in something like “sport” as a value to the datalayer it would apply to anything else.

    By using the data attributes we’re giving just THAT element a value, which can easily be accessed via GTM. No need for inline code sending events we might want to change in the future, and no values in the datalayer for the page that belong to a single element. The attributes let us tag individual things with unique information, which we can then choose to work with, or not, in GTM.

  • Audrey

    Hi Sayf,
    Thanks for your quick reply.
    Indeed, the code was stripped out of the comment. So if I’m understanding correctly, if I added a dataLayer.push to send the “sport” as a value and put that bit of code within the link tag, that wouldn’t necessarily be associated exclusively to the link. Am I understanding correctly?

    Thanks a lot for your help.

  • Sayf Sharif


    You can certainly push values into the datalayer to be referenced on the click. This is essentially doing that, but they then can be referenced anywhere by anything which could lead to inaccuracies, while the data attribute is only associated with THAT element.

Contact Us.


24 S. 18th Street, Suite 100,
Pittsburgh, PA 15203

Follow Us



We'll get back to you
in ONE business day.