Elementor forms are visually powerful and easy to build — but tracking them with full form data in Google Tag Manager (GTM) is not straightforward.
Out of the box, GTM can detect that an Elementor form was submitted (for example using Elementor's built-in JS events or a generic form submission trigger). However, it does not receive the actual field values.
Elementor sends the form payload through background AJAX requests, so:
- you may know that "a form was submitted", but…
- you don't see the name, email, phone, service, etc.
- no form field values are exposed to the dataLayer
- you can't build robust, field-based GA4 or ads conversions
If you've tried tracking Elementor forms for GA4 or advertising, you've probably seen problems like:
- missing or duplicated conversions,
- no access to submitted form data in GTM,
- and plugins breaking after updates.
This guide solves that.
You'll get a production-ready JavaScript snippet that listens to Elementor form submissions, extracts the submitted field values, and pushes a clean GTM event into the dataLayer — without modifying the form or installing extra plugins.
Why GTM Can't Track Elementor Forms by Default
Elementor submits its forms using background requests like:
POST /wp-admin/admin-ajax.php
All of the form field values are sent inside this AJAX request body.
GTM can react to a high-level submission event, but it does not automatically see the form payload, because:
- the field values are only present in the AJAX request, not the DOM,
- Elementor does not write those values into the dataLayer by default,
- and GTM has no native way to read XHR request bodies on its own.
So with standard GTM setups you get:
- "a form was submitted" ✅
- "what was inside the form" ❌
To track Elementor forms properly, we need to:
- intercept the AJAX request,
- extract form field values (name, email, phone, custom fields…),
- verify successful submission,
- push a structured GTM event.
The script below does exactly that.
Production‑Ready Script for Tracking Elementor Form Data in GTM
<script>
(function () {
window.dataLayer = window.dataLayer || [];
var originalOpen = XMLHttpRequest.prototype.open;
var originalSend = XMLHttpRequest.prototype.send;
XMLHttpRequest.prototype.open = function (method, url) {
this._trackAjaxForm = typeof url === "string" && url.indexOf("admin-ajax.php") !== -1;
return originalOpen.apply(this, arguments);
};
XMLHttpRequest.prototype.send = function (body) {
if (this._trackAjaxForm && body instanceof FormData) {
this._formData = Object.fromEntries(body.entries());
}
if (this._trackAjaxForm && !this._gtmListenerAttached) {
this.addEventListener("loadend", function () {
if (!this._trackAjaxForm) return;
var json;
try {
json = JSON.parse(this.responseText || this.response || "{}");
} catch (e) {
return;
}
if (!json || !json.success) return;
var raw = this._formData || {};
var prefixes = ["form_id", "form_fields"];
var cleaned = {};
Object.keys(raw).forEach(function (key) {
var keep = prefixes.some(function (prefix) {
return key.indexOf(prefix) === 0;
});
var value = raw[key];
if (keep && value !== null && value !== "") {
cleaned[key] = value;
}
});
if (Object.keys(cleaned).length > 0) {
window.dataLayer.push({
event: "elementor_form_submit",
form_data: cleaned,
});
}
});
this._gtmListenerAttached = true;
}
return originalSend.apply(this, arguments);
};
})();
</script>
How the Script Works (Code Breakdown)
1. It watches only Elementor form submissions
We check if the AJAX request URL contains admin-ajax.php.
2. It safely extracts form field values
We read the FormData body using Object.fromEntries().
3. It waits for Elementor's response
Elementor returns JSON:
{"success": true}
We only track successful submissions.
4. It filters out unnecessary data
We keep only keys starting with:
form_idandform_fields.
This removes system fields and internal Elementor parameters.
5. It pushes clean data into the dataLayer
dataLayer.push({
event: "elementor_form_submit",
form_data: { ... }
});
Now GTM can use this event as a trigger.
What Elementor Form Data You Can Capture
This script lets you capture:
- Name
- Phone
- Message
- Select/Dropdown values
- Checkbox and radio values
- Hidden fields
- Form ID
- Custom Elementor Pro fields
- Multi-step form data
Every submission becomes a clean GTM event.
Example dataLayer Event
Your GTM debugger will show:
{
"event": "elementor_form_submit",
"form_data": {
"form_id": "23",
"form_fields[name]": "John Doe",
"form_fields[email]": "john@example.com",
"form_fields[service]": "Website Redesign"
}
}
How to Use This Event in GTM (Quick Guide)
1. In GTM → Create Trigger
- Trigger type: Custom Event
- Event name:
elementor_form_submit - Fire on: All Custom Events
2. Create a GA4 Event Tag
Example:
- Event name:
generate_lead - Event parameters:
form_id→{{form_data.form_id}}email→{{form_data.form_fields[email]}}name→{{form_data.form_fields[name]}}
3. Publish
You're now tracking Elementor form data with full field visibility.
Final Thoughts
Elementor makes beautiful forms, but hides their submissions inside AJAX requests—making tracking extremely difficult.
This script solves that problem completely.
You now have:
- a reliable way to detect Elementor form submissions,
- full access to form field values inside GTM,
- clean
elementor_form_submitevents, - and a system that works without plugins or form modifications.
