Thursday, July 18

Google Tag Manager Form Tracking: 7 Ways To Reach Your Goal

Updated: August 24th, 2018. While talking with marketers, I noticed that one of the most popular topics among them is form tracking. Unfortunately, in some cases form tracking might become a real pain in the butt (especially if a marketer has no clue what CSS or HTML is). But do not fear because in this blog post I’ll show you 7 Google Tag Manager form tracking techniques. Hint: some of them will require the developer’s input, but I’ll try my best to put everything in plain English.


Chapters of this blog post:


Google Tag Manager form tracking: Basic Context

In this wonderful thing called THE INTERNET, there are various types of forms. Some of them refresh after a successful submission, some of them don’t, some of them might redirect you to a “thank you” page, etc. The main problem with form tracking is that there are no global standards of how forms must be developed. Some developers may prefer one technology (e.g. AJAX) over another – and they have a full right to do so.

Since you are interested in form tracking, you have probably noticed Form triggers and built-in Form variables in Google Tag Manager. Enable at least one form variable and create a Form Submission trigger (which listens to all form submissions), hereby you’ll turn on GTM’s Form auto-event listener.

google tag manager form tracking

Form auto-event listener listens for a standard submit browser event. However, a vast majority of forms use other ways to send their data (e.g. jQuery’s $.ajax) thus the submit event is prevented from working. In that case, Google Tag Manager never records a form submission. And that’s a pretty common problem.

If GTM’s form listener does not work in your situation, there are other alternatives how you can reach the goal. In this blog post, I will explain both standard options and workarounds for Google Tag Manager form tracking.
Google Tag Manager Course - Learn More

Tag + Trigger

You are probably already familiar with main Google Tag Manager concept: every interaction you want to track needs a tag and a trigger. If you want to track all form submissions with Google Analytics, you’ll need to create a Google Analytics Tag and a Trigger (rule) when a tag must fire. Creating a tag is the easy part of this process. Let’s make one – you’ll need it in next chapters of this blog post):

  1. Go to Tags
  2. Press New button
  3. In Tag Configuration choose Universal Analytics:
    1. Choose Track Type – Event
    2. Event Category – Form submission (feel free to choose another appropriate title)
    3. Event Action – Contact Form (feel free to choose another appropriate title)
    4. Event Label – {{Page URL}}. P.S. Feel free to choose other values for an event category, action and label.
    5. Select Google Analytics Settings Variable.
  4. Leave the Triggering part empty (for now) and click Save. We’ll get back to it later. 80% of this blog post is dedicated to various types of triggers you can make use of. The choice of trigger type depends on the way a form was developed.

Updated Google Analytics Tag - Form Submission

Those 7 form tracking techniques I mentioned in the title of this blog post are triggers. Each one of them depends on different elements/events that occur on a website after the form submission:

  • Form auto-event listener.
  • Thank you page.
  • AJAX form tracking.
  • Tracking with Element Visibility trigger
  • Writing your own form auto-event listener.
  • Datalayer event (dataLayer.push).
  • DOM scraping.

An incorrectly configured trigger will result in false data and reports (this will lead to wrong conclusions and actions). So read everything carefully. If you have any questions or if some parts of this blog post are misleading, let me know in the comment section below, Twitter or LinkedIn. I will be glad to help.


Before we continue: REady-made guides

Now, before we dive deep into this guide, there’s something you should know. This entire guide is universal and covers pretty much every form on the planet (well, not maybe every, but around 95% (made-up statistics)).

However, to save you some time, I’d like to ask this: are you using Contact Form 7, Caldera Forms or Gravity Forms plugins?

If yes, then I have some good news for you. Here are three guides tailored to those popular form plugins:

If your form is custom or built using another technology, don’t worry. I have covered all the tips in next chapters.


Which Form Tracking Method Should You Choose?

Before diving into the pool triggers, we’ll need to inspect a form and decide which technique fits our needs the best. I have prepared a flow scheme which should help you choose the right Google Tag Manager form tracking method. Google Tag Manager Form Tracking Flow

Open full scheme on a new window


I am sure that some parts of that scheme might look vague. Continue reading and everything will become much clearer.


#1. Google Tag Manager form TRACKING (with FORM listener)

First, let’s try GTM’s built-in form listener. Open a list of Variables in your GTM account. By default, form variables are disabled and hidden, therefore, you need to enable them. Under built-in variables, click Configure and in the right sidebar enable all Form variables (all changes are automatically saved).

google tag manager form variables

Then open a list of all your triggers (by clicking Triggers in the left sidebar). Create a new trigger:

  • Title “All form submissions”.
  • Trigger type – Form submission.
  • Leave Wait for tags unchecked.
  • Click Check validation checkbox. Once this is checked, GTM will not fire the Trigger if the default action of the form (submit and redirect) is prevented. If left unchecked, the Trigger will go off whenever a submit event is registered (even when a form is submitted with errors (e.g. several required fields are left blank)). In the screenshot below, I’ve enabled this trigger ONLY on the page where my contact form is located (Page Path contains contact-us)
  • Fire on. In this example, I set to track All forms (which are located in Contact Us page (because in the previous paragraph of this guide, I’ve set the trigger to be enabled only on a particular page).

Updated Form Tracking Trigger in Google Tag Manager

Now, let’s use GTM’s Preview and Debug mode to find out whether default form auto-event listener works for us. At the top-right corner of your Google Tag Manager account, click Preview.

Enable Google Tag Manager Debug Mode

Once the preview mode is enabled, you’ll see an orange banner looking like this:

Preview and Debug mode

It MUST appear. If the banner is missing, read this guide on how to fix GTM preview and Debug mode.

After Preview and Debug mode is enabled, navigate to the site where the form is and you will see a debug console at the bottom of your browser showing detailed information about your tags, including their firing status and what data is being processed. This console window will appear only on your computer as you preview the site, and is not visible to your other website visitors. It should look something like this:

preview and debug console

If you have already opened that page with the form but don’t see GTM’s debug console, refresh the page. If you still face problems, I suggest reading more about most common Google Tag Manager mistakes to find the solution.

Let’s get back to form tracking. Fill in the form (try not to leave any fields blank):

  1. Hit the submit button. Did a gtm.formSubmit event appear in the Preview and Debug console? If not, then GTM’s Form auto-event listener will not work with this form and you should choose next form tracking option described in this blog post.
    formSubmit event
  2. If gtm.formSubmit event did appear in Preview and debug console, then you should do another test – try leaving at least one required form field empty and submit the form again. This way you’ll imitate an error in your form:
    1. If gtm.formSubmit event fired once again, then you should check other form tracking options mentioned in this blog post.
    2. If gtm.formSubmit event did not fire – that’s great! It means that GTM will track only those form submissions which were successfully completed (and this is exactly what you need).

Great! We’ve identified that our form can be tracked with GTM’s built-in form listener. Let’s create a trigger specifically for that form. Remember gtm.formSubmit event that was previously mentioned? Click on it (in Preview and Debug mode), then click Variables.

Google Tag Manager form tracking

Then scroll down and start looking for any Form variable that is unique for that form. Usually, it will be Form ID variable, in other occasions – Form Classes (but Form ID is the best option (if possible)). As you can see in the image below, I have submitted a form (of which Form ID variable is form_contact2).

form submission variables

This is a good identifier that is not used on any other elements in the website, so I’ll use it for my trigger:

  1. Go to Triggers and click New
  2. Click Trigger configuration section and choose trigger type – Form submission
  3. Click Check validation and set the rule Page URL matches RegEx (.*)This rule means that this form submission trigger will be available on all pages. If you want to make it accessible only on particular pages, you can add more specific rules, such as Page URL contains /contact-us/ (it depends on URL of your contact form).
  4. Then configure this trigger to fire only on some forms and enter the following rule: Form ID equals form_contact2.
    1. If you don’t see Form ID variable – Enable it in the list of Built-in variables of Google Tag Manager.
    2. Form ID may (and probably will) be different in your situation (compared to my example).

Updated - Form Submit Trigger


Let’s test

  1. Assign this new trigger to Google Analytics Tag that you created at the beginning of this blog post.
  2. Open (or refresh) a Preview and Debug mode, refresh a web page with a form you want to track.
  3. Then fill in the form and submit – if Google Analytics Tag fired, that’s good news! Also (if possible), try submitting a different form on your website: in case of successful submission, a GA tag should not fire.



#2. “Thank you” page Tracking with GOOGLE TAG MANAGER

If standard form listener in Google Tag Manager does not work in your case, you should check whether that form redirects a user after a successful submission to another page.

  • If yes, what URL (web address) does it redirect to?
    form success URL
    • Is that address unique?
    • If yes, can users just navigate to that page without actually submitting a form? If the answer to the last question is nothen you can create a pageview trigger which fires only on that success page. Tip: you can always check your Google Analytics Behavior flow reports to see whether users access success page from different locations of your website. Your goal here is to avoid accidental visits of success (a.k.a. “Thank you” page) as much as possible.

Now let’s create a trigger which fires only on success page.

  1. Go to Triggers in Google Tag Manager
  2. Press New button
  3. Choose trigger type – Pageview and Some page views
  4. If the visitor is redirected to, then you can set one of the following rules for this trigger:
    1. Page Path equals /form/thankyou.html.
    2. or Page URL contains /form/thankyou.html. Try being as specific as possible. Setting just “thankyou” as the rule for this trigger might not be the best idea because there might be other pages, that can contain that word (and we don’t want that!) in URL.
  5. And do not forget to properly name the trigger – “Pageview – Successful Form Submission”. A title must be clear, otherwise, you’ll have a mess in your GTM account (in the long run). You can read more about naming tips (a.k.a. Naming Convention) here

Google tag manager form tracking - pageview success page


Let’s test

  1. Assign this new trigger to Google Analytics Tag that you created in the beginning of this blog post.
  2. Open (or refresh) a Preview and Debug mode, refresh a web page with a form you want to track.
  3. Then fill in the form and submit. After successful submission, you’ll be redirected to a “Thank you” page – if Google Analytics Tag fired, good job! Also (if possible), try submitting a different form on your website (to see if the tag did not fire on accident).

Subscribe and Get the Ebook - Real Book Img - GTM for Beginners

#3. AJAX form tracking with GOOGLE TAG MANAGER

If you are reading this part, your form is probably not sending valid form submit events and is not redirecting users to a “thank you” page. It probably just refreshes itself and then displays “You have successfully filled in the form” message without the actual page refresh. There’s a big chance that this form is using AJAX. I suggest skipping all the technical mumbo-jumbo here (since I am not a developer + I don’t think I am capable of clearly explaining how it works). The only thing here you should know is AJAX listener.

Lunametrics have shared an awesome AJAX listener for GTM everyone can use for free. If you want to read more about how it works, you can do that on Lunametrics blog. Here we’ll borrow their code to track form submissions. Copy the code below and paste it in the Custom HTML tag on GTM:

<script id="gtm-jq-ajax-listen" type="text/javascript">
 (function() {

 'use strict';
 var $;
 var n = 0;

 function init(n) {

 // Ensure jQuery is available before anything
 if (typeof jQuery !== 'undefined') {
 // Define our $ shortcut locally
 $ = jQuery;

 // Check for up to 10 seconds
 } else if (n < 20) {
 setTimeout(init, 500);



 function bindToAjax() {

 $(document).bind('ajaxComplete', function(evt, jqXhr, opts) {

 // Create a fake a element for magically simple URL parsing
 var fullUrl = document.createElement('a');
 fullUrl.href = opts.url;

 // IE9+ strips the leading slash from a.pathname because who wants to get home on time Friday anyways
 var pathname = fullUrl.pathname[0] === '/' ? fullUrl.pathname : '/' + fullUrl.pathname;
 // Manually remove the leading question mark, if there is one
 var queryString =[0] === '?' ? :;
 // Turn our params and headers into objects for easier reference
 var queryParameters = objMap(queryString, '&', '=', true);
 var headers = objMap(jqXhr.getAllResponseHeaders(), 'n', ':');

 // Blindly push to the dataLayer because this fires within GTM
 'event': 'ajaxComplete',
 'attributes': {
 // Return empty strings to prevent accidental inheritance of old data
 'type': opts.type || '',
 'url': fullUrl.href || '',
 'queryParameters': queryParameters,
 'pathname': pathname || '',
 'hostname': fullUrl.hostname || '',
 'protocol': fullUrl.protocol || '',
 'fragment': fullUrl.hash || '',
 'statusCode': jqXhr.status || '',
 'statusText': jqXhr.statusText || '',
 'headers': headers,
 'timestamp': evt.timeStamp || '',
 'contentType': opts.contentType || '',
 // Defer to jQuery's handling of the response
 'response': (jqXhr.responseJSON || jqXhr.responseXML || jqXhr.responseText || '')



 function objMap(data, delim, spl, decode) {

 var obj = {};

 // If one of our parameters is missing, return an empty object
 if (!data || !delim || !spl) {

 return {};


 var arr = data.split(delim);
 var i;

 if (arr) {

 for (i = 0; i < arr.length; i++) {

 // If the decode flag is present, URL decode the set
 var item = decode ? decodeURIComponent(arr[i]) : arr[i];
 var pair = item.split(spl);

 var key = trim_(pair[0]);
 var value = trim_(pair[1]);

 if (key && value) {

 obj[key] = value;




 return obj;


 // Basic .trim() polyfill
 function trim_(str) {

 if (str) {

 return str.replace(/^[suFEFFxA0]+|[suFEFFxA0]+$/g, '');



 * v0.1.0
 * Created by the Google Analytics consultants at
 * Written by @notdanwilkerson
 * Documentation:
 * Licensed under the Creative Commons 4.0 Attribution Public License

Set that Custom HTML tag to fire on all pages. Now, let’s check whether a form is built on AJAX:

  1. Enable (or refresh) Preview and Debug mode.
  2. Refresh the web page with a form.
  3. Try submitting the form (with no errors).
  4. Did the ajaxComplete event appear in the Preview and debug console?
    1. If yes, the form is using AJAX.
    2. If no, skip to the next chapter of this blog post.

If your answer to the previous questions was Yes, let’s take a look at what can we do with that AJAX form. Click ajaxComplete event in Preview and Debug mode, then click Data Layer:

ajax complete

Looks difficult for a non-developer, right? But it’s easier than you think. This is the data that was passed to data layer after successful submission of the form, each line is a separate dataLayer data point which can be used as dataLayer variable in GTM. You should be looking for something which helps identify successful form submission. Scroll down and look for “response”.


ajax form response

Let’s take a closer look at it. Can you see a message “This message has been successfully sent”? Bingo! We can use it as a trigger.

First, let’s create a Data Layer variable in Google Tag Manager.

  1. Go to Variables
  2. Scroll down to User-Defined  variable and hit New
  3. Click Variable configuration and choose variable type – Data Layer Variable
  4. Enter Data Layer Variable Name – attributes.response. Leave all other settings as they are.
  5. My recommendation for Title of this GTM variable is dlv – attributes.response (“dlv” stands for Data Layer Variable).

Data Layer variable - attributes.response

You’re probably guessing why I entered attributes.response as Data Layer Variable Name, instead of just response. Let’s take a closer look at Data Layer in Preview and Debug mode. In line 2 you see event name ajaxComplete – that’s the same name which appears in Preview and Debug console’s left side. Then we see attributes which is an object containing various data points (key-value pairs). And the response is one of those keys.

ajaxComplete - full response

So when we want to tell Google Tag Manager that we are interested in response’s value, we need to tell the exact path to that data. In our case, it’s attributes → response. Each level of the path must be separated with dot → attributes.response . Another example: let’s say you’re interested in Server data (from that very exact AJAX response). In that case, Data Layer Variable’s Name should be attributes.headers.Server  .

After we created an attributes.response Data Layer variable in Google Tag Manager, let’s debug. Refresh Preview and Debug mode and refresh the page where the AJAX form is. For educational/testing purposes, I’m using forms from this website (use Example 1). Feel free to try them by yourself.

Fill in the form and submit. Click the most recent ajaxComplete event in Preview and Debug console, then navigate to Variables tab and find the new variable dlv – attributes.response. If you did everything correctly, it should look like this:

attributes.response dlv

That’s a message of successfully submitted form. If the value of that variable is undefined, then you should start looking for mistakes. Most common ones are typos in the variable name or inaccurately defined variable’s path. Some guys just try using response instead of attributes.response. 

Now let’s create a trigger which fires when the event is ajaxComplete AND our new Data Layer variable contains text The message has been successfully sent.

  1. Go to Triggers and click New
  2. Choose Trigger Type – Custom Event. If you’re new to this, Custom event = Data Layer event. Lunametrics’ AJAX listener creates a Data Layer event (via dataLayer.push method) each time an AJAX request is made.
  3. Enter Event name – ajaxComplete
  4. This trigger should fire on Some Custom Events.
  5. Define a condition when the trigger will fire – dlv – attributes.response contains The message has been successfully sent.

Custom Trigger - Ajax Complete Form Submission


Let’s test

  1. Assign this new trigger to Google Analytics Tag that you created at the beginning of this blog post.
  2. Open (or refresh) a Preview and Debug mode, refresh a web page with a form you want to track.
  3. Then fill in the AJAX form and submit. After successful submission, Google Analytics Tag should fire (it will be displayed in Preview and Debug mode. You can also check Google Analytics Real-time event reports).

Things to keep in mind when tracking AJAX forms:

  1. The response of your form might look different so try adjusting my tutorial to your situation.
  2. If developers change the response’s data, your trigger will fail. Inform developers about your GTM implementation.
  3. If the page contains more than one AJAX form, try looking for more information in Data Layer which can help Google Tag Manager tell the difference between those forms.

Google Tag Manager Course - Learn More


#4. Track Forms with Element Visibility trigger

One of the most awesome triggers in GTM (in my opinion) is the Element Visibility trigger. It enables you to track when a particular element appears on the screen (due to scrolling or some other circumstances).

The same technique can be applied to forms when a particular message (e.g. “Thank you”)  appears after a form is successfully submitted.

The first thing we need to do here is to inspect the success message of a form. We’ll need to find a way how to instruct Google Tag Manager which particular website element are we interested in.

After you submit the form successfully, right-click on the success message and choose Inspect Element.

Inspect Element - Form Success Message

You will then see browser’s developer tools that contain various information about the message: its content, CSS class, etc. In the example below I see that the message has a class “thanks” which could be used as a condition in the Element Visibility trigger. It was even better if the success message had a parameter called “id” but since it’s not available, we’ll use CSS class.

Thank you message of a form

Let’s go to your Google Tag Manager container and go to Triggers. Create a new trigger and choose Element Visibility as its type. The key ingredient here is the Selection Method that will help GTM understand what we are looking for.

selection method

Selection method has two options: Element ID and CSS Selector. Since the success message in my example has no id (but “class”, we’ll go with CSS Selector.

In the Element Selector field, we need to paste that class “thanks”. In CSS, every class is defined with a dot in front of it, so let’s do the same.

Finally, make sure you tick “Observe DOM changes”. This setting means that if an element appears on the screen not due to scrolling but under some other circumstances (e.g. “just simply pops in”), GTM will catch it (most likely).

Take a look at the screenshot below. If you want, you may do some other tweaks but what I did was a bare minimum.

Element Visibility Trigger in form tracking

Save the trigger.



  1. Assign this new trigger to Google Analytics Tag that you created at the beginning of this blog post.
  2. Open (or refresh) a Preview and Debug mode, refresh a web page with a form you want to track.
  3. Then fill in the form and submit. After successful submission, in P&D console you will see gtm.elementVisibility event. Click it and you will see that GA tag has fired. If you don’t see the gtm.elementVisibility event, you probably made some mistake in the Selection method or CSS selector field. Or forgot to enable Observe DOM changes checkbox.

If your success message has no ID or proper CSS class, you’ll need to dive deeper into CSS selectors because their possibilities are enormously huge.



#5. Write Your Own Form Auto-Event Listener

Yes, I know that this sounds complicated. Actually, this can’t be further from the truth. In one of my blog posts, I’ve explained how you can write an auto-event listener with no coding skills. You should definitely check it out.

Auto-event listeners are these super useful JavaScript functions which track particular interactions on a web page. In case something noteworthy occurs, they fire Data Layer events which can be used as triggers in GTM. Furthermore, those events contain valuable data which can be transferred to other tools, like Google Analytics, Adwords, Mixpanel, you name it.

By default, Google Tag Manager offers a built-in Form Auto-Event Listener, but as you already know, its support is pretty poor (otherwise, this blog post wouldn’t exist).

Anyway, in the aforementioned blog post, I’ve explained 7 steps how you can validate the idea and create an auto-event listener. And for sake of clarity, I’ll illustrate with the actual example.

Before we continue, check what kind of form are you using. Is it custom made and created exclusively for you? If yes, skip to the Chapter #6 of this blog post. Otherwise, continue reading.

If your website is running on WordPress, then you definitely are using some sort of form plugin. Find out its name/brand/title/etc. Found it? Great. Let me take you through the 7-step-process of writing your own form auto-event listener without coding skills.

As an example, I’ve chosen Gravity Forms, a WordPress Plugin.



First of all, you need to check whether there is a ready-made Gravity Forms GTM listener somewhere on the web. Last time I checked it, there was none. Although you might say Hey, I’ve googled “Gravity Forms Google Tag Manager” and there ARE some tutorials, all I can say is that they aren’t as good as you might think.

I tried to track Gravity Form once. The problem was that the form dispatched a form submission event even if the form was submitted empty (with no fields filled in!). And those blog posts did not help me to solve this issue, so I had to find a way around.

That’s where this GTM Form Tracking Method #4 became really useful. Continue reading.



Open Google and enter Gravity Forms Javascript API. It’s crucial that you look for JavaScript API, not regular API. Your search results should look like this:

Gravity Forms JavaScript API

The 2nd search result looks promising. Let’s click it. We should be one step closer to writing an auto-event listener.




Now, check whether the API is well documented and easy-to-understand even for those who do not know how to code. Since we want to track ONLY successful form submissions we should keep looking for some terms which contain “success”, “form submission”, “confirmation”, etc. You get the idea right?

What we are looking for is some kind of API method which is related to successful submissions. Honestly, it took me a while to find a proper page in Gravity Form’s documentation (because they offer A LOT of stuff).

On the left side of the Gravity Forms API reference, you’ll find a navigation bar. Go to Hooks > Filters > Confirmations > gform_confirmation_loaded. This JavaScript hook (gform_confirmation_loaded) fires when the form’s “Success” page is loaded (which is exactly what we’re looking for!).

Gravity Forms Confirmation Loaded API Reference

Bingo! We’re one step closer to success but there’s still something we need to verify.



Even if the API offers useful methods and the documentation is very well written, there’s still one requirement left. Is the API Reference really dummy-proof? Will a non-developer be able to use it with ease?

Honestly, it is not a very common practice to write super simple code examples in API references which could be useful for non-devs or beginners. Sometimes it’s even next to impossible.

For example, Wistia offers a very well-written Javascript API reference, but examples are not designed for entry-level developers, thus you and I won’t able to write our own custom auto-event listeners.

In Wistia’s case, we’re lucky to have Lunametrics because their developers posted this awesome Wistia listener for GTM. But there are still lots of situations where a ready-made tracking solution just simply does not exist.

OK, let’s go back to Gravity Forms. I have navigated to gform_confirmation_loaded JavaScript hook and found this example of code:

gform_confirmation_loaded javascript snippet

This is perfect! Let me explain what’s happening.

This code is ready to use. It states: if gform_confirmation_loaded occurs, initiate a function. Currently, that function is empty but we can easily embed the dataLayer.push event just by replacing the text //code to be trigger when the confirmation page is loaded with the actual data layer code.



Copy that code from Gravity Forms API documentation and paste to some plain text or code editor (e.g. Notepad, Notepad++, Sublime, etc.)

<script type="text/javascript">
jQuery(document).bind('gform_confirmation_loaded', function(event, formId){
 // code to be trigger when confirmation page is loaded

Remove //code to be trigger when confirmation page is loaded

<script type="text/javascript">
jQuery(document).bind('gform_confirmation_loaded', function(event, formId){


Prepare dataLayer.push event code (various GTM experts recommend to use window.dataLayer.push instead of plain dataLayer.push):

window.dataLayer = window.dataLayer || [];
 'event': 'formSubmission', //you can actually name this even whatever you want
 'formID': formId

Why did I add “formId”? Well, that’s because the Gravity Form’s JavaScript webhook returns the ID of the form (see function(event, formId) ?). It’s optional, so feel free to remove it.

Now, merge the Gravity Form’s code snippet with window.dataLayer.push. This is what the final result should look like:

<script type="text/javascript">
 jQuery(document).ready(function() {
   jQuery(document).bind("gform_confirmation_loaded", function(event, formID) {
     window.dataLayer = window.dataLayer || [];
       event: "formSubmission",
       formID: formID

Great! We’re very close to finishing the Gravity Form auto-event listener!



In Google Tag Manager account, create a new Custom HTML tag. Paste the code you have created in the previous step.

Gravity Forms Listener

Done! Save the tag and assign the trigger you want, e.g. All Pages (or just on those pages where the form is located).

Don’t forget to test the listener with GTM Preview and Debug mode. Load the page with any Gravity Form and complete a test submission. A Data Layer event called formSubmission should appear in the event stream. Click it and check what data was passed to the Data Layer. It should look like this.

Form Submission Data Layer Event



If everything worked as I have described, create Data Layer variable formId (learn how to access data in the Data Layer) and create a Custom Event Trigger formSubmission. Use this variable and trigger in your Universal Analytics or any other tag.

Congratulations! You have written your first GTM Auto-Event Listener. If this Google Tag Manager Form Tracking method didn’t work, continue reading and maybe you’ll what you’re looking for.


#6. FORM TRACKING with datalayer events

Disclaimer: Although this form tracking method is equally robust solution compared to standard GTM’s Form Listener (see Technique No. 1), I placed it as a No.6 option in this list for a reason.

When other marketers approach me for form tracking advice, they’re looking forward to a solution when developer’s input can be avoided. “Manage your marketing tags without help from developers” is one the main reasons why they start considering Google Tag Manager in the first place. This statement was among GTM’s key “selling” points when it was launched, so it’s no surprise marketers are expecting this to be 100% true. Although we know that in a lot of situations developer’s help is strongly advised. My position here:

  1. If you have access to developers and Google Tag Manager’s Form listener isn’t working for you, I recommend using dataLayer.push method which I will describe further.
  2. If you don’t have access to developers or they are super busy (and they probably are), then it’s okay to track with other techniques mentioned in this blog post. Just be aware, that other solutions have a bigger chance to break when developers make constant updates to a website you’re tracking. This especially applies to technique No. 7 – DOM scraping.

I hope I made my point clear and we can continue.

As it was mentioned above, if standard Google Tag Manager Form listener does not work with your form, the next best thing is to ask the developer to implement a custom dataLayer.push() into the callback function which is invoked upon a successful form submission. The piece of code could be something like:

window.dataLayer = window.dataLayer || []
   'event': 'formSubmission',
   'formType': 'Contact us',
   'formPosition': 'Footer'

You’ll need to prepare a short but well-written and clear task for a developer:

  1. First, choose a name for the event. In the example above I chose formSubmission.
  2. Then think of any additional data you may need. Write those data points down and try categorizing them.
    1. In my imaginary website, I have several types of forms – “Contact us” and “Newsletter Subscription”. So I decided to have a dataLayer variable formType.
    2. Another useful parameter (in my opinion) is form position, because some forms are in the footer, and others are in the sidebar of a website. Why not make it another dataLayer variable?
  3. If a developer is new to dataLayer events and Google Tag Manager in general, hand them a link to this dataLayer.push guide with clear examples. Explain to them that you need an event with additional variables pushed into dataLayer after the successful form submission. If developers still have questions, this blog post should enlighten them.

Done! After the developer implements dataLayer.push in all forms, you should test it:

  1. Open Preview and Debug mode.
  2. Refresh the page with the form.
  3. Try submitting the form:
    1. Leave at least one required field blank. In this ca, e dataLayer event must not be pushed.
    2. Fill in all fields and try submitting again. Did the event appear in Preview and debug console? It should look like this:
      formSubmission event
    3. Check whether all data is correctly pushed to dataLayer. Click formSubmission event and then open Data Layer tab in Preview console. Data should look like this:
      formSubmission dataLayer

Setup variables and triggers in GTM. In my dataLayer.push example, there are two data points I’d like to use as variables – formType and formPosition, so I need to include them to Google Tag Manager by creating Data Layer variables.

1st variable:
dlv – formType
Variable type: Data Layer Variable
Data Layer Variable Name: formType
Leave all other settings as they are

2nd variable:
dlv – formPosition
Variable type: Data Layer Variable
Data Layer Variable Name: formPosition
Leave all other settings as they are

Now, let’s create a trigger. Go to Triggers and click New. Enter the following settings:

Trigger Type: Custom event
Event name: formSubmission (it may differ depending on your situation. Just make sure you and your developer are using the same name).
This trigger fires on: All custom events. This means that all formSubmission events will be tracked.


Let’s test

  1. Assign this new trigger to Google Analytics Tag that you created in the beginning of this blog post.
  2. Open (or refresh) a Preview and Debug mode, refresh a web page with a form you want to track.
  3. Then fill in the form and submit. After successful submission, Google Analytics Tag should fire (it will be displayed in Preview and Debug mode. You can also check Google Analytics Real-time event reports).

Tip: In this example, I’d recommend making a few changes to Google Analytics Event Tag. In the beginning of this blog post, I suggested creating a GA event tag with the following values:

  • Form submission as Event Category
  • Contact form as Event Action
  • {{Page URL}} as Event Label.

Updated Google Analytics Tag - Form Submission

Since we asked our developer to add few additional variables via dataLayer.push, we can utilize this data and push it to GA. We could change:

  • Event Category – from Form submission to Form submission: {{formType}}
  • Event Action – from Contact form to {{formPosition}}
  • Leave Event Label as {{Page URL}}

How will this event be displayed in Google Analytics event reports? Let’s say a visitor subscribed to our newsletter. The values pushed with Google Analytics Event will be:

  • Event Category: Form submission: Newsletter Subscription
  • Event Action: Footer
  • Event Label:




This method should never be your first option. Try using the aforementioned 6 Google Tag Manager Form tracking methods before you continue reading this chapter.

If developers often update the website’s code, you should treat DOM scraping as the last resort due to its riskiness. It’s better than “no form tracking at all”, but it’s less robust than other options described in this blog post.

Although you gain a lot of flexibility and agility, it hardly depends on the website front-end’s structure. Even a slight change committed by developer might break your implementation. Also, it requires some knowledge of Javascript and DOM concepts (which is not a very common skill among marketers).

For this example, we’ll be using DOM Element Variable. It is a variable in Google Tag Manager which lets you scrape content directly from Document Object Model (in other words: with its help you can transfer any text on your website into a Variable and pass it on to your Marketing tools (e.g. Google Analytics)).

Now let’s open a demo Shopify store Brooklyn Theme and see everything in action. I’d like to apologize Shopify folks in advance for spamming their demo website with fake email submissions (but I’m sure they’re fine with it). There is a Signup up to our mailing list form at the bottom of their homepage.

email form
Quick off-topic note: If you haven’t, consider subscribing to my monthly email newsletter for more useful Google Tag Manager guides

Enter in that Shopify form and hit Subscribe. A page will refresh, the web address will change to, and that little form displays a “Thank you” message.
thank you for subscribing

In this case, we could easily track form submissions with Pageview trigger of Thank you page, but let’s imagine that page’s address (URL) did not change. This is not a common situation, but it’s possible. That’s where DOM Element Variable might come in handy. We could create a trigger which could scan a website and look for a success message “Thanks for subscribing”.

First, let’s create a DOM element variable looking for that particular success message. Hover your mouse cursor over success message’s text, click right mouse button and choose Inspect.

Right click - Inspect Element

A developer’s console will appear with a lot of HTML code. Note that success message’s code is already selected in that console. That message does not have any unique ID so we’ll need to utilize CSS Selectors.

Inspect element

At the bottom of the screenshot, you can see a line of CSS selectors, e.g. div.note.form-success. These selectors can help us identify the exact element of the website.

Let’s create a DOM Element variable and try to scrape “Thanks for subscribing” text.

  1. Go to Variables
  2. Scroll down to user-defined variables and click New
  3. Choose Variable type – DOM Element Variable
  4. Selection method – CSS selector
  5. In Element selector field enter div.note.form-success
    CSS selectors - short
    See what I did there? I entered the last CSS selector from the screenshot above. I also verified CSS selector according to Measureschool’s DOM scraping tutorial (start from 3:12), because there’s a possibility of more website elements with similar CSS selector. I want to track only that particular success message, so I need to make sure my CSS selector is unique.
  6. In case there were more than one possible success messages on a website with similar CSS selector, I would have used a longer CSS selector, for example, “#contact_form div div.note.form-success” (without quotation marks)
    css selectors
  7. Leave Attribute name empty.
  8. Variable’s title could be DOM – Form Success Message.
  9. Hit Save.


Let’s test

  1. Enable Preview and Debug mode (or refresh if it’s already launched).
  2. Refresh the page with form (or delete ?customer_posted=true#contact_form in URL) and try submitting it.
  3. Choose Page view event in Preview and Debug console and click Variables.
    DOM variable in PD console
  4. If DOM – Form Success Message variable’s value is Thanks for subscribing, you did a good job.

Alright! Now we need to create a trigger which depends on our new DOM variable.

  1. Go to Triggers and click New
  2. Choose Trigger type – Pageview
  3. This trigger fires on: Some Pages
  4. Enter the following condition: DOM – Form Success Message equals Thanks for subscribing. This means that the trigger will fire only on those pages where Form success message is displayed to visitors.


Do not forget to test:

  1. Assign this new trigger to Google Analytics Tag that you created in the beginning of this blog post.
  2. Open a Preview and Debug mode (or refresh), reload a web page with a form you want to track.
  3. Fill in the form and submit. After successful submission, Google Analytics Tag should fire (it will be displayed in Preview and Debug mode. You can also check Google Analytics Real-time event reports).
  4. Also, try submitting a form with an intentional error and see whether the tag fires (spoiler alert: it shouldn’t).


Final word

In this blog post, I described seven form tracking methods with Google Tag Manager. This has been the largest guide on this blog so far and I hope you found it useful. You should now be able to track much more forms without a developer’s input. But remember – it’s okay to ask for the developer’s help. If possible, choose dataLayer.push method over DOM scraping. Robust solutions should be your priority.

Did I skip something in this post? Is there some aspect of form tracking that you’d want more information on? Drop me a comment, and let’s see what we can come up with!

Notify of

Inline Feedbacks
View all comments
Would love your thoughts, please comment.x