• Courses
    • Courses
    • Course bundles
  • Blog
  • Services
  • Resources
    • Youtube channel
    • E-books and Guides
    • GTM Recipes
    • View All Resources
    • GTM Community
    • GA4 community
  • About
    • About
    • Contact
  • Login
  • Courses
    • Courses
    • Course bundles
  • Blog
  • Services
  • Resources
    • Youtube channel
    • E-books and Guides
    • GTM Recipes
    • View All Resources
    • GTM Community
    • GA4 community
  • About
    • About
    • Contact
  • Login

Google Tag Manager AJAX Form Tracking

Updated: December 8th, 2022

In this post, I’ll show you how to implement Google Tag Manager AJAX Form Tracking. This article is a part of a much larger and more comprehensive guide – Google Tag Manager Form Tracking.

 

A video tutorial

If you prefer video content, here’s a tutorial from my Youtube channel.

 

GA4 event tag

You are probably already familiar with the 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 4, 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 the next chapter of this blog post.

In this article, I presume that you have already installed Google Analytics 4 and already have the GA4 configuration tag. If not, read this blog post first.

After you have a GA4 config tag in your GTM container, it’s time to create a GA4 event tag that will be used in all of the examples of this article.

  1. Go to Tags
  2. Press New button
  3. In Tag Configuration choose Google Analytics: GA4 Event
  4. In the Configuration Tag field, select your current GA4 configuration tag. The event tag that we are creating will reuse some of the settings from the configuration tag (e.g. Measurement ID)
  5. In the Event Name field, I enter generate_lead
  6. Leave the Triggering part empty (for now) and click Save. We’ll get back to it later.

Let me quickly explain some of the choices. The reason why I used generate_lead as an event name is that it is in the list of GA4 Recommended events. But if you want, you can name it something else.

 

Custom HTML tag with the AJAX listener

If you are reading this blog post, your form is probably not supported by the built-in Form Submission trigger 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 details here. The only thing here you should know is AJAX listener.

Bounteous have shared an awesome AJAX listener for GTM everyone can use for free. Here we’ll borrow their code to track form submissions. Copy the code below and paste it in the Custom HTML tag on Google Tag Manager:

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

 'use strict';
 var $;
 var n = 0;
 init();

 function init(n) {

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

 // Check for up to 10 seconds
 } else if (n < 20) {
 
 n++;
 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 = fullUrl.search[0] === '?' ? fullUrl.search.slice(1) : fullUrl.search;
 // 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
 dataLayer.push({
 '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(/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g, '');

 }

 }


 })();
 /*
 * v0.1.0
 * Created by the Google Analytics consultants at http://www.lunametrics.com
 * Written by @notdanwilkerson
 * Documentation: http://www.lunametrics.com/blog/2015/08/27/ajax-event-listener-google-tag-manager/
 * Licensed under the Creative Commons 4.0 Attribution Public License
 */
</script>

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. Try submitting the form on your website (with no errors).
  3. Did the ajaxComplete event appear in the Preview and debug console?
    1. If yes, the form uses AJAX.
    2. If not, then read this blog post.

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

Looks difficult for a non-developer, right? But it’s easier than you think.

This is data was passed to the data layer after the successful submission of the form. Each line is a separate dataLayer data point that can be used as a dataLayer variable in GTM.

Now you should look for something that helps identify successful form submissions. Scroll down and look for “response”.

Let’s take a closer look at it. Can you see the message “Thanks for contacting us! We will be in touch with you shortly”? Bingo! We can use it as a trigger.

 

Data Layer Variable and Custom Event Trigger

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

  1. Go to Variables
  2. Scroll down to the 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.data.message

You’re probably guessing why I entered attributes.response.data.message 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 the event named ajaxComplete – that’s the same name that 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.

Within that response (2), we see data (3), and within that, we see the message (4).

Think of this as accessing folders. First, you have to access the attributes, then you go to response, then you go do the data folder and then you access the message.

IMPORTANT: in your case, the structure of the data can be different, and parameters can be named differently. It will always start with attributes.response, but after that, things might differ in every form. It might be attributes.response.message or something like that. You will need to adapt.

Another example: let’s say you’re interested in Server data (from that very exact AJAX response). In that case, the Data Layer Variable’s Name should be attributes.headers.Server  .

After we create the Data Layer variable in Google Tag Manager, let’s debug. Refresh Preview and Debug mode (by clicking the Preview button in the GTM interface).

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

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

Now let’s create a trigger that fires when the event is ajaxComplete AND our new Data Layer variable contains “Thanks for contacting us”.

  1. Go to Triggers and click New
  2. Choose Trigger Type – Custom Event
  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.data.message contains Thanks for contacting us!

 

Let’s Test

  1. Assign this new trigger to the Google Analytics 4 Event Tag that you created at the beginning of this blog post.
  2. Open (or refresh) a Preview and Debug mode
  3. Then fill in the AJAX form and submit it. After successful submission, Google Analytics 4 Event Tag should fire (it will be displayed in Preview and Debug mode. You should also check Google Analytics 4 Debug View.

Things to keep in mind when tracking AJAX forms:

  1. The response of your form might look different so you should adjust your Data Layer Variable and Custom Event trigger.
  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.

 

If Google Tag Manager AJAX Form Tracking Doesn’t Work for You

I have created a very detailed Google Tag Manager form tracking guide that includes many different form tracking techniques. If this Google Tag Manager AJAX form tracking method didn’t work for you, check the other options mentioned here.

If you have questions, feel free to contact me via social media accounts or write a comment on this blog post.

Google Tag Manager Ebook Bundle
Hi, I'm Julius Fedorovicius and I'm here to help you learn Google Tag Manager and Google Analytics. Join thousands of other digital marketers and digital analysts in this exciting journey.Read more
Analytics Mania
  • Google Tag Manager Courses
  • Google Tag Manager Recipes
  • Google Tag Manager Resources
  • Google Tag Manager Community
  • Login to courses
Follow Analytics Mania
  • Subscribe to newsletter
Recent Posts
  • Introduction to Google Tag Manager Server-side Tagging
  • 3 Ways to Pull Data from Data Layer with Google Tag Manager
  • Cannot See the Google Tag Manager Option in Google Ads Conversion?
Analytics Mania - Google Tag Manager and Google Analytics Blog | Privacy Policy
Manage Cookie Settings