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
- 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:
- 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:
- 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.
