Form Tracking with Google Tag Manager

Track form submissions in GTM using built-in form triggers, custom events, element visibility, and validation-aware approaches.

Form Tracking with Google Tag Manager

Forms are the primary conversion mechanism for most websites. Contact forms, lead generation forms, newsletter signups, quote requests, and registration forms all represent moments where a visitor becomes a lead or customer. Tracking these submissions accurately is critical for understanding which channels, pages, and campaigns drive real business results.

Google Tag Manager offers several approaches to form tracking, from built-in triggers to custom data layer implementations. The right approach depends on how your forms are built and what counts as a successful submission.

For the official form trigger documentation, see support.google.com/tagmanager/answer/7679217.

The Built-In Form Submission Trigger

GTM includes a native Form Submission trigger that detects when an HTML form is submitted using the browser’s standard form submission mechanism.

How It Works

When a user submits a form, the browser fires a submit event on the <form> element. GTM intercepts this event and provides information about the form through built-in variables like Form ID, Form Classes, Form Target, Form URL, and Form Text.

Configuration

  1. Go to Triggers and click “New”.
  2. Select “Form Submission” as the trigger type.
  3. Check “Wait for Tags” to delay the form submission briefly so your tracking tag has time to fire. Set the maximum wait to 2000ms.
  4. Check “Check Validation” to only fire the trigger if the browser’s built-in form validation passes. This prevents tracking invalid submissions.
  5. Set conditions to target specific forms. For example: Form ID equals “contact-form”.

Enabling Form Variables

Before using form triggers, enable the form-related built-in variables:

  1. Go to Variables.
  2. Click “Configure” under Built-In Variables.
  3. Enable Form Classes, Form Element, Form ID, Form Target, Form Text, and Form URL.

Limitations of the Built-In Trigger

The Form Submission trigger only works with traditional HTML forms that use the browser’s native submit mechanism. It does not fire for:

  • AJAX form submissions where JavaScript handles the submission without a page reload or native form submit event.
  • Forms built with JavaScript frameworks (React, Vue, Angular) that often prevent the default form behavior.
  • Multi-step forms where individual steps do not trigger a full form submit.

For these scenarios, you need a custom approach.

Custom Data Layer Approach

The most reliable form tracking method is pushing a custom event to the data layer from your form’s submission handler. This works regardless of how the form is built or submitted.

Implementation

In your website’s form submission code, add a data layer push after a successful submission:

// After form submission succeeds
fetch('/api/contact', {
  method: 'POST',
  body: formData
})
.then(response => response.json())
.then(data => {
  if (data.success) {
    dataLayer.push({
      'event': 'form_submission',
      'formId': 'contact-form',
      'formName': 'Contact Us',
      'formLocation': 'footer',
      'formSuccess': true
    });
  }
})
.catch(error => {
  dataLayer.push({
    'event': 'form_submission',
    'formId': 'contact-form',
    'formName': 'Contact Us',
    'formSuccess': false,
    'formError': error.message
  });
});

GTM Configuration for Custom Events

  1. Create Data Layer Variables for formId, formName, formLocation, and formSuccess.
  2. Create a Custom Event trigger with event name form_submission.
  3. Add a condition: DLV - Form Success equals true (to only track successful submissions).
  4. Create a GA4 Event tag with event name generate_lead (or the appropriate GA4 recommended event).
  5. Add event parameters mapping to your data layer variables.

This approach has several advantages. It only fires after the server confirms the submission was successful. It works with any form technology. And it provides rich data about the form without needing to parse the DOM.

Element Visibility as a Confirmation Trigger

A practical middle-ground approach uses the Element Visibility trigger to detect when a success message appears after form submission. Many forms display a “Thank you” message or hide the form and show a confirmation element.

Configuration

  1. Create a new Element Visibility trigger.
  2. Selection Method: CSS Selector.
  3. Enter the CSS selector for the success message element (e.g., .form-success-message or #thank-you-message).
  4. Set “When does this trigger fire” to “Once per page”.
  5. Set the minimum percent visible to 1%.

When to Use This Approach

Element Visibility tracking is useful when:

  • You cannot modify the website code to add data layer pushes.
  • The form uses a third-party tool (HubSpot, Typeform, etc.) embedded via iframe or script.
  • The success state is clearly indicated by a visible DOM element.

Be cautious with this method. If the success element exists in the DOM but is hidden with CSS (display: none), and then shown after submission, the trigger works reliably. But if the element is added to the DOM dynamically, timing issues can occur. Test thoroughly.

Tracking Specific Form Fields

Sometimes you need to know not just that a form was submitted but what the user entered in specific fields. This is common for forms where the selection changes the conversion value, like a “Request Quote” form where the user selects a product tier.

Using the Data Layer

The cleanest approach is pushing selected values to the data layer:

dataLayer.push({
  'event': 'form_submission',
  'formId': 'quote-request',
  'selectedPlan': document.querySelector('#plan-select').value,
  'estimatedValue': document.querySelector('#budget-range').value
});

Privacy Considerations

Never track personally identifiable information (PII) like names, email addresses, phone numbers, or physical addresses through GTM. This data flows to GA4 and potentially other platforms, which may violate privacy regulations and platform policies.

What you should track:

  • Form ID and form name
  • Which form variant was submitted (for A/B testing)
  • Non-PII selections (product category, service type, budget range)
  • Success or failure status
  • Form location on the page

What you should not track:

  • Email addresses
  • Phone numbers
  • Names
  • Addresses
  • Any field that identifies a specific individual

Multi-Step Form Tracking

Forms with multiple steps benefit from tracking each step, not just the final submission. This reveals where users drop off in the process.

Data Layer Implementation

// Step 1 complete
dataLayer.push({
  'event': 'form_step',
  'formId': 'application-form',
  'formStep': 1,
  'formStepName': 'personal_info'
});

// Step 2 complete
dataLayer.push({
  'event': 'form_step',
  'formId': 'application-form',
  'formStep': 2,
  'formStepName': 'business_details'
});

// Final submission
dataLayer.push({
  'event': 'form_submission',
  'formId': 'application-form',
  'formStep': 3,
  'formStepName': 'review_submit',
  'formSuccess': true
});

GTM Configuration

Create a single Custom Event trigger for form_step and a separate one for form_submission. The step data feeds into GA4 as event parameters, allowing you to build funnel reports that show exactly where users abandon the process.

Preventing Duplicate Tracking

A common problem with form tracking is duplicate events. This happens when:

  • A user submits the form multiple times (double-clicking the submit button).
  • The success page can be refreshed, re-triggering the event.
  • The trigger fires on form start rather than actual completion.

Solutions

Data layer approach: Push the event only once by using a flag variable:

if (!window._formTracked) {
  window._formTracked = true;
  dataLayer.push({
    'event': 'form_submission',
    'formId': 'contact-form'
  });
}

GTM approach: Use a cookie or custom JavaScript variable to check if the form has already been tracked in the current session:

// Custom JavaScript Variable: CJS - Form Already Tracked
function() {
  return document.cookie.indexOf('form_tracked=true') > -1;
}

Then add a trigger condition: CJS - Form Already Tracked does not equal true.

Testing Form Tracking

Form tracking requires careful testing because you are often tracking events that have real consequences (sending emails, creating records, starting workflows).

Use GTM Preview mode to walk through the form submission process. For comprehensive testing guidance, see our debug mode guide. Verify the trigger fires at the right moment with the correct data.

Check for false positives. Submit the form with invalid data to ensure the trigger does not fire on failed validations.

Test edge cases. What happens if the user submits the form, navigates away, and comes back? What happens on a page refresh? What happens with browser autofill?

Verify in GA4 DebugView. Confirm the event arrives in GA4 with all expected parameters before publishing your changes.

Accurate form tracking is the foundation of lead generation analytics. Getting it right means every marketing dollar can be traced from ad click to form submission, enabling true ROI measurement across your campaigns.