Tracking AJAX Form Submissions with Google Tag Manager

Post published: October 25, 2024 11:33 am

Author: Yury Parfentsov

Total views: 1,036

Reading time: 5.3 min

In this article

If you regularly use Google Tag Manager (GTM) to set up event tracking for form submissions, you’ve likely encountered forms that submit using AJAX, which can make capturing successful form submissions challenging with standard methods. Unlike traditional form submissions, AJAX forms do not trigger the typical submit events, making it difficult to track them using straightforward GTM configurations.

I encountered this problem frequently, and eventually developed a reliable, easy-to-implement solution that works consistently for AJAX-based forms. By using this approach, you can ensure that form submissions are tracked properly, allowing you to gather accurate data for your analytics. This solution is particularly helpful for marketers and developers who rely heavily on GTM for comprehensive event tracking.

Here’s a step-by-step guide to implementing it:

Step 1: Identify the Form Submission URL

First, we need to determine the URL to which the form is being submitted. This URL is typically where the AJAX request sends the form data. You can do this using your browser’s developer tools—in this example, I’ll use Chrome. Open the Network tab, submit the form, and locate the URL where the AJAX script sends the data. In my case, it’s ajax.php, and I’ll use this URL in my JavaScript code. By identifying this URL, we can set up a script to listen for when a request is made to it, allowing us to capture the submission event.

Ajax URL detection

Step 2: Create a Custom HTML Tag in GTM

Next, create a new Custom HTML Tag in GTM and insert the following JavaScript. This tag should be configured to fire on the page where the form is present. To simplify the setup, I configured it to fire on All pages. This ensures that the script is always active on pages where the form may be present, making it easier to manage in the long run.

GTM Tag Name: Form Request Listener

Trigger: All pages


<script>
(function() {
  var originalFetch = window.fetch;
  window.fetch = function(input, init) {
    // Call the original fetch function
    var promise = originalFetch.apply(this, arguments);

    // Check if the request URL contains 'ajax.php'
    if (typeof input === 'string' && input.includes('ajax.php')) {
      promise.then(function(response) {
        // Check if the request was successful (status in the range 200-299)
        if (response.ok) {
          // Assuming {{Form Data Extractor}} returns relevant form data
          var formData = {{Form Data Extractor}}();
          if (formData) {
            window.dataLayer.push({
              event: 'formSubmission',
              formData: formData
            });
            console.log('Form submission was successful:', formData);
          }
        } else {
          console.log('Form submission failed with status:', response.status);
        }
      }).catch(function(error) {
        // Handle network errors or request failures
        console.error('Form submission encountered an error:', error);
      });
    }

    return promise;
  };

  var originalXHR = window.XMLHttpRequest.prototype.send;
  window.XMLHttpRequest.prototype.send = function(data) {
    var xhr = this;
    var oldOnReadyStateChange = xhr.onreadystatechange;
    xhr.onreadystatechange = function() {
      if (xhr.readyState === 4 && xhr.status === 200) {
        if (xhr.responseURL && xhr.responseURL.includes('ajax.php')) {
          var formData = {{Form Data Extractor}}();
          if (formData) {
            window.dataLayer.push({
              event: 'formSubmission',
              formData: formData
            });
            console.log('Form submission detected (XHR):', formData);
          }
        }
      }
      if (oldOnReadyStateChange) {
        oldOnReadyStateChange.apply(this, arguments);
      }
    };
    return originalXHR.apply(this, arguments);
  };
})();
</script>
  

This script works by overriding the default behavior of both the fetch API and the XMLHttpRequest object. It monitors network requests made by the page, and if any request is made to the URL containing ajax.php, it checks whether the request was successful. If it was, the script pushes the form data to the dataLayer, allowing you to track the form submission in GTM.

Step 3: Extract Form Data

To extract form data and send it to GA4, you can implement a Custom JavaScript Variable. In my case, I wanted to extract data from a form with the ID request-showing. This step is crucial because it allows you to capture specific data points from the form, such as the user’s email, phone number, and other input fields that are relevant to your analytics goals.

GTM Variable (Custom JavaScript): Form Data Extractor


function() {
  return function() {
    var form = document.getElementById('request-showing');
    if (form) {
      return {
        formemail: form.querySelector('[name="formemail"]') ? form.querySelector('[name="formemail"]').value : '',
        formphone: form.querySelector('[name="formphone"]') ? form.querySelector('[name="formphone"]').value : '',
        formdate: form.querySelector('[name="formdate"]') ? form.querySelector('[name="formdate"]').value : '',
        formmessage: form.querySelector('[name="formmessage"]') ? form.querySelector('[name="formmessage"]').value : '',
        formsubject: form.querySelector('[name="formsubject"]') ? form.querySelector('[name="formsubject"]').value : '',
      };
    }
    return null;
  };
}

In GTM, Custom JavaScript Variables are useful for performing complex data extraction or calculations. The script above defines a function that extracts form values from a specified form element. This function runs whenever a GTM tag or trigger references this variable, such as during form submissions. By using this approach, you can ensure that you capture the specific data you need from the form, which can be incredibly valuable for analytics and marketing automation purposes.

For example, you can use this form data to create more personalized marketing campaigns or to track the effectiveness of different form fields in driving conversions. The extracted data can also be used for retargeting purposes, allowing you to create audiences based on users who submitted specific forms.

Step 4: Set Up a Trigger for the ‘formSubmission’ Event

Create a custom event trigger in GTM and set the Event Name parameter to ‘formSubmission’. You can now attach any tags to this trigger to send events, with or without form data, to GA4, Facebook, or other analytics platforms. This trigger is the key to connecting the form submission event with your various tracking tags, enabling you to properly capture and analyze user behavior.

For example, if you want to send form submission data to Google Analytics 4 (GA4), you can create a GA4 event tag that fires whenever the ‘formSubmission’ event occurs. Similarly, you can use this trigger to send data to Facebook for conversion tracking, allowing you to measure the effectiveness of your advertising campaigns.

This setup provides a robust way to track AJAX form submissions and ensure that you are capturing all relevant data. It not only allows you to track whether a form was successfully submitted but also gives you the flexibility to extract detailed form data, which can be crucial for optimizing your marketing strategies. By implementing these steps, you’ll have greater visibility into user interactions on your website, leading to more informed decision-making and better overall campaign performance.

Share This Story, Choose Your Platform!

Leave A Comment

Did you like it? Let´s talk

We have a range of effective strategies for promoting your business. Let us know what your specific needs and goals are, and we'll work with you to develop a customized plan.