GA Event Tracking in GTM - Custom HTML and JS

This is the second post in a series on design patterns for tracking events in Google Analytics (GA) using Google Tag Manager (GTM). This second pattern involves adding JavaScript through a Custom HTML tag.

GTM is a very flexible tool, opening up many potential implementation design patterns for tagging. There is a spectrum, where some of these patterns exclusively use GTM's built-in auto-event tracking, others primarily rely on developers adding values to a data layer, and others lie somewhere in the middle.

Below are the most common methods of collecting site interaction data using GTM to send event tracking data to GA.

Method 1: GTM's Built-In Interaction Tracking (aka Auto-Event Tracking / DOM Scraping)

Method 2 (this post): Custom HTML and JS Tags in GTM

Method 3: Developer Pushes to a Pass-Through Data Layer

Method 4: Combined Auto-Event & Data Layer


Advantage: The advantage of this method is that you can track virtually any element on the site, beyond what is possible using GTM's built-in interaction tracking. You can manipulate the output so it looks exactly how you want, and you can do it all yourself, without needing to touch the actual code on the page.

Disadvantage: Just like auto-event tracking, this method can break if the page layout changes. Also, while this method allows you to bypass your site developers, it requires that you yourself are a developer! You are injecting JS into the site, so you have to be careful not to break anything. Test, test, test.


  1. Create a new Custom HTML tag in GTM containing JavaScript that listens for some action on the page and pushes an event and one or more variables into the data layer
  2. Set up a trigger to fire that Custom HTML tag (usually this will be on All Pages or the page you're interested in)
  3. Create a new Data Layer Variable that collects the variable from your data layer push in step 1.
  4. Create a new Custom Event Trigger that matches the event set by your data layer push in step 1.
  5. Create a new Universal Analytics tag in GTM with Track Type = Event.  Populate the Category, Action, and Label fields with text and/or the Data Layer Variables from step 3. Fire it using the trigger from step 4.


In this example, I'll look for error messages on a form and fire an event tag for each error message, in order to produce an ordered list of most common error messages.

  1. Create a new custom HTML tag in GTM

    var errorArray = document.querySelectorAll(".error-message");
    var aLen = errorArray.length;
    for (i = 0; i < aLen; i++) { 
      	'event' : 'trackError',
      	'errorMessage' : errorArray[i].innerText

    This script loops through all error messages on a form and pushes an event called trackError into the data layer for each one. It assumes that the error messages are identified by the class .error_message. If you're doing this on your own site, you'll need to replace .error_message with your own value.

  2. Set up a trigger to fire that Custom HTML tag We want to set a trigger for when a user clicks Submit on the form.  To set this trigger, identify the class selector of the button, e.g. Click Element matches CSS selector #submit (if you're following along, you'll need to substitute in your own site's CSS selector).

    The caveat here is that error messages may not display until after the user clicks Submit. In that case, you'll want to add a delayed Submit event. You can do that with the following script:

    window.setTimeout(function() {
        event: 'delayedSubmit'
    }, 1000);


    Now, every time a user clicks Submit, a delayedSubmit event will fire 1 second later. Set a custom event trigger for your new event delayedSubmit, and use that trigger to trigger your custom HTML tag.

  3.  Create a new Data Layer Variable that collects the variable from your data layer push in step 1 Our script pushes a variable called errorMessage containing the text of the error message. To use this variable in GTM, navigate to Variables > New > Data Layer Variable and choose Data Layer Variable Name = errorMessage. You can name it anything you like but for this example we'll name it DL - Error Message Detail (the 'DL' indicates it's a data layer variable).custom-html-js-img1
  4. Create a new Custom Event Trigger that matches the event set by your data layer push in step 1 The script also pushes an event called trackError. To use this event in GTM, navigate to Triggers > New > Custom Event and enter Event name = trackError. Again you can name it however you like, but here I'll name it Event - trackError.
  5. Create a new Universal Analytics tag in GTM with Track Type = Event

    All the parts are in place now, so it's time to construct the GA event tag itself. Navigate to Tags > New > Universal Analytics and choose Track Type = Event. Fill in the details as follows:
    Category = Error Messages
    Action = {{DL - Error Message Detail}}
    Trigger = Event - trackError

In summary, the custom HTML & JS technique involves creating a two-tag sequence. The first tag listens for interactions with the page and in response to those interactions pushes values into the data layer. The second level tag is triggered by the first, and sends the data off to Google Analytics or any other analytics/marketing system.

This blog post contains another detailed walk through of the full process: Add a jQuery Function to Google Tag Manager (The blog post focuses on jQuery, but the process is exactly the same whether you use jQuery or vanilla JS.)


GTM's auto event tracking opens the doors to GTM-based analytics tracking, while adding in custom HTML/JS tags gets you into intermediate/advanced territory. Through this technique you can tag nearly everything a site developer can, with the exception of tags that require data from the back-end (e.g. ecommerce tags). You can start off with pre-built GTM scripts, but ultimately this technique requires a solid understanding of JavaScript and the DOM.