How to Track Forminator Forms in Google Tag Manager with Enhanced or Hashed User Data ( Event listener code included)

Tracking Forminator form submissions in Google Tag Manager can be frustrating.

Standard GTM form triggers often fail with AJAX-based forms, fire too early, or miss important lead details entirely. If you are using Forminator for lead generation, relying on basic click or submit triggers can result in incomplete tracking and poor attribution.

In this guide, we will show you how to implement a robust Forminator tracking script that listens for native Forminator submission events, captures submitted form data, extracts user information, hashes sensitive identifiers, and pushes everything into the dataLayer for use in Google Tag Manager, server-side tagging, and ad platform enhanced matching.

Why Default Form Tracking Is Not Enough

Most default GTM form tracking setups only capture that “a form was submitted.”

They typically do not provide:

  • Form field values
  • Reliable AJAX submission confirmation
  • Failed submission tracking
  • User identifiers for enhanced conversions
  • Structured payloads for server-side tagging

For businesses running paid ads, this means weaker attribution and lower match quality in platforms like Google Ads and Meta.

What This Script Does

This custom script enhances Forminator tracking by listening to Forminator’s built-in JavaScript events and pushing rich structured data into the dataLayer.

It captures:

  • Successful form submissions
  • Failed form submissions
  • Form ID and form name
  • Full submitted form payload
  • First name and last name
  • Email and phone
  • SHA-256 hashed email and phone
  • Event timestamp

This setup is ideal for:

  • Google Ads Enhanced Conversions
  • Meta Conversions API
  • TikTok Events API
  • Server-side GTM implementations
  • CRM/Webhook forwarding

Forminator Tracking Script

<script>

jQuery(function ($) {

  function convertFormDataToObject(formData) {

    var obj = {};

    if (!formData || typeof formData.forEach !== ‘function’) {

      return obj;

    }

    formData.forEach(function (value, key) {

      if (obj.hasOwnProperty(key)) {

        if (Array.isArray(obj[key])) {

          obj[key].push(value);

        } else {

          obj[key] = [obj[key], value];

        }

      } else {

        obj[key] = value;

      }

    });

    return obj;

  }

  function getValueByPatterns(dataObj, patterns) {

    for (var key in dataObj) {

      if (!dataObj.hasOwnProperty(key)) continue;

      var normalizedKey = key.toLowerCase();

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

        if (normalizedKey.indexOf(patterns[i]) !== -1) {

          return dataObj[key];

        }

      }

    }

    return null;

  }

  function normalizeEmail(email) {

    if (!email) return null;

    return String(email).trim().toLowerCase();

  }

  function normalizePhone(phone) {

    if (!phone) return null;

    return String(phone)

      .replace(/[^\d+]/g, ”)

      .replace(/(?!^)\+/g, ”);

  }

  function sha256(value) {

    if (!value || !window.crypto || !window.crypto.subtle) {

      return Promise.resolve(null);

    }

    var encoder = new TextEncoder();

    var data = encoder.encode(value);

    return window.crypto.subtle.digest(‘SHA-256’, data)

      .then(function (hashBuffer) {

        var hashArray = Array.prototype.slice.call(new Uint8Array(hashBuffer));

        return hashArray.map(function (b) {

          return (’00’ + b.toString(16)).slice(-2);

        }).join(”);

      });

  }

  function extractUserData(dataObj) {

    var firstName = getValueByPatterns(dataObj, [

      ‘first_name’, ‘firstname’, ‘fname’, ‘given_name’, ‘name-1’

    ]);

    var lastName = getValueByPatterns(dataObj, [

      ‘last_name’, ‘lastname’, ‘lname’, ‘surname’, ‘family_name’, ‘name-2’

    ]);

    var email = normalizeEmail(

      getValueByPatterns(dataObj, [’email’])

    );

    var phone = normalizePhone(

      getValueByPatterns(dataObj, [‘phone’, ‘mobile’, ‘telephone’, ‘tel’])

    );

    return Promise.all([

      sha256(email),

      sha256(phone)

    ]).then(function (hashes) {

      return {

        form_firstname: firstName,

        form_lastname: lastName,

        form_email: email,

        form_phone: phone,

        form_email_sha256: hashes[0],

        form_phone_sha256: hashes[1]

      };

    });

  }

  function pushToDataLayer(eventName, dataObj) {

    extractUserData(dataObj).then(function (userData) {

      window.dataLayer = window.dataLayer || [];

      window.dataLayer.push({

        event: eventName,

        form_id: dataObj.form_id || null,

        form_name: dataObj.form_name || null,

        forminator_user_data: userData,

        form_data: dataObj,

        event_source: ‘forminator’,

        timestamp: new Date().toISOString()

      });

    });

  }

  $(document).on(‘forminator:form:submit:success’, function (event, formData) {

    var dataObj = convertFormDataToObject(formData);

    pushToDataLayer(‘forminator_form_success’, dataObj);

  });

  $(document).on(‘forminator:form:submit:failed’, function (event, formData) {

    var dataObj = convertFormDataToObject(formData);

    pushToDataLayer(‘forminator_form_failed’, dataObj);

  });

});

</script>

How the Script Works

Converts FormData into a Readable Object

Forminator returns submission data as a FormData object. Since GTM cannot easily work with that format, the script converts it into a standard JavaScript object.

This allows every submitted field to become accessible inside GTM.

Automatically Extracts User Information

The script scans form field names and attempts to match common naming conventions for:

  • First name
  • Last name
  • Email
  • Phone

For example, it can detect fields like:

  • firstname
  • fname
  • surname
  • mobile
  • telephone

This makes the script flexible across multiple forms without manual mapping.

Normalizes Email and Phone Data

Before hashing, the script standardizes values:

Email

  • Trims spaces
  • Converts to lowercase

Phone

  • Removes spaces/symbols
  • Preserves leading plus sign

Proper normalization improves matching accuracy in ad platforms.

Hashes Sensitive User Data

The script generates SHA-256 hashes for:

  • Email
  • Phone

These hashes can be sent directly to:

  • Google Ads Enhanced Conversions
  • Meta Advanced Matching
  • TikTok Advanced Matching

Pushes Structured Events to the DataLayer

Successful submissions trigger:

forminator_form_success

Failed submissions trigger:

forminator_form_failed

Example DataLayer Push

dataLayer.push({
event: “forminator_form_success”,
form_id: “1533”,
form_name: null,
forminator_user_data: {
form_firstname: “test test”,
form_lastname: null,
form_email: “test@gmail.com”,
form_phone: “01575050063”,
form_email_sha256: “87924606b4131a8aceeeae8868531fbb9712aaa07a5d3a756b26ce0f5d6ca674”,
form_phone_sha256: “d1bb28870b8b7d153e6064ddaa9c6eaba37f70ef4381f1a6f11dd68ebe00af75”
},
form_data: {
name-1: “test test”,
email-1: “test@gmail.com”,
phone-1: “01575050063”,
textarea-1: “test”,
referer_url: “”,
forminator_nonce: “481cc18c48”,
_wp_http_referer: “/contact-us/”,
form_id: “1533”,
page_id: “1493”,
form_type: “default”,
current_url: “https://analyticsrush.com/contact-us/”,
render_id: “0”,
action: “forminator_submit_form_custom-forms”,
form_uid: “69f5acb8101f2”
},
event_source: “forminator”,
timestamp: “2026-05-02T07:52:48.708Z”,
gtm.uniqueEventId: 6
})

How to Add the Script

Via Google Tag Manager

Create a Custom HTML Tag and paste the script.

Recommended trigger:

  • DOM Ready
    or
  • All Pages

Via WordPress

Alternatively, add it directly through:

  • Theme footer
  • Header/Footer script plugin
  • Code Snippets plugin

GTM Trigger Configuration

Create two Custom Event triggers:

Successful Form Submission

forminator_form_success

Failed Form Submission

forminator_form_failed

These triggers can then be used for:

  • GA4 Lead Events
  • Google Ads Conversions
  • Meta Lead Events
  • Server-side Tagging Workflows

Why This Method Is Better Than Standard GTM Form Triggers

Traditional GTM form submission triggers often break with AJAX forms because they depend on browser submit behavior rather than actual form completion.

Using Forminator’s native events ensures tracking fires only after the plugin confirms the submission result.

Benefits include:

  • More accurate firing logic
  • Access to actual submission payload
  • Support for failed submission tracking
  • Enhanced user data collection
  • Better server-side compatibility

Final Thoughts

If you are using Forminator for lead generation, implementing native event tracking provides significantly more reliable and useful data than standard GTM form triggers.

With this setup, you can build a stronger tracking foundation for:

  • Attribution
  • Enhanced conversions
  • Advanced matching
  • Server-side tagging
  • CRM enrichment

For advertisers and analytics teams, this leads to better data quality and improved campaign optimization.