Track Gravity Forms Submissions
Gravity Forms has two submission modes — AJAX and traditional page-reload — and a native jQuery event that fires only after the server accepts the submission. This recipe covers both modes, plus multi-page form step tracking.
Valid as of April 2026, Gravity Forms 2.8.x.
The success signal
Section titled “The success signal”Gravity Forms emits three jQuery events you can hook:
gform_confirmation_loaded— fires after an AJAX submission succeeds and the confirmation HTML has rendered. PassesformIdas the second argument. Use this for conversions.gform_page_loaded— fires when a multi-page form advances to a new page. PassesformIdandcurrentPage. Use for funnel/step tracking.gform_post_render— fires on form render, including initial load and after AJAX validation errors. Do not use for conversions.
For non-AJAX forms, Gravity Forms reloads the page to a confirmation URL and none of these events fire. Use a thank-you page push or an entry-ID detection pattern.
dataLayer push pattern
Section titled “dataLayer push pattern”Fires only on successful AJAX submissions — no false positives on validation errors.
(function () { if (!window.jQuery) return;
window.jQuery(document).on('gform_confirmation_loaded', function (event, formId) { var $confirmation = window.jQuery('#gform_confirmation_wrapper_' + formId); var formTitle = window.jQuery('#gform_wrapper_' + formId + ' .gform_title').text().trim() || 'gform_' + formId;
window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'form_submission', form_vendor: 'gravity_forms', form_id: String(formId), form_title: formTitle, confirmation_type: $confirmation.length ? 'message' : 'redirect' }); });
// Multi-page step tracking window.jQuery(document).on('gform_page_loaded', function (event, formId, currentPage) { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'form_step', form_vendor: 'gravity_forms', form_id: String(formId), step_number: currentPage }); });})();Non-AJAX forms redirect to a confirmation URL or render a confirmation message via PHP. Add this on the confirmation page (via the theme or a Custom HTML tag triggered on the confirmation page path):
<script> window.dataLayer = window.dataLayer || []; window.dataLayer.push({ event: 'form_submission', form_vendor: 'gravity_forms', form_id: '42', form_title: 'Contact Us', confirmation_type: 'redirect' });</script>Or, if the confirmation is rendered inline on the same page after reload, use a Custom HTML tag with a trigger on Page URL contains gform_confirmation=1 (Gravity Forms appends this query parameter by default on same-page confirmations).
GTM setup
Section titled “GTM setup”-
Create a Custom Event trigger for submissions
- Trigger type: Custom Event
- Event name:
form_submission - This fires: Some Custom Events →
DLV - form_vendorequalsgravity_forms
-
Create a Custom Event trigger for steps (optional)
- Event name:
form_step - Same vendor filter
- Event name:
-
Create Data Layer Variables
DLV - form_vendor→form_vendorDLV - form_id→form_idDLV - form_title→form_titleDLV - step_number→step_numberDLV - confirmation_type→confirmation_type
-
Create a GA4 Event Tag
- Event name:
generate_lead - Parameters:
form_vendor→{{DLV - form_vendor}}form_id→{{DLV - form_id}}form_title→{{DLV - form_title}}
- Trigger:
form_submissionCustom Event trigger
- Event name:
-
Create a GA4 step-tracking tag (optional)
- Event name:
form_progress - Parameters:
form_id,step_number - Trigger:
form_stepCustom Event trigger
- Event name:
GA4 - generate_lead (Gravity Forms)
- Type
- Google Analytics: GA4 Event
- Trigger
- Custom Event - form_submission (gravity_forms)
- Variables
-
DLV - form_vendorDLV - form_idDLV - form_title
Capturing the entry ID
Section titled “Capturing the entry ID”Gravity Forms does not expose the entry ID in gform_confirmation_loaded. To capture it, enable the Entry ID merge tag in your confirmation message:
Thanks — your entry number is {entry_id}.Then extract it from the confirmation DOM:
window.jQuery(document).on('gform_confirmation_loaded', function (event, formId) { var $wrap = window.jQuery('#gform_confirmation_wrapper_' + formId); var match = $wrap.text().match(/entry number is (\d+)/i); var entryId = match ? match[1] : undefined;
window.dataLayer.push({ event: 'form_submission', form_vendor: 'gravity_forms', form_id: String(formId), gf_entry_id: entryId });});Prefer a hidden data-entry-id attribute on the confirmation wrapper if you can edit the confirmation HTML — far more robust than text matching.
Test it
Section titled “Test it”- Open GTM Preview mode and visit a page with a Gravity Form.
- Submit the form successfully. The
form_submissionevent should appear in the Summary pane. - For multi-page forms, advance through each page and verify a
form_stepevent fires with the correctstep_number. - Click the event in the Summary pane and verify
form_idandform_titlein the Variables tab. - Check Tags Fired for the GA4 tag, then confirm in GA4 DebugView.
- Test failure path: submit with a required field empty. No
form_submissionevent should fire (butgform_post_renderwill — which is why we don’t listen to it).
Common gotchas
Section titled “Common gotchas”Confusing gform_post_render with success. gform_post_render fires on every render including validation errors. Listening to it will count failed submissions as leads. Only gform_confirmation_loaded is the success signal.
Confirmation set to Redirect. If your form’s confirmation is a redirect to an external URL, gform_confirmation_loaded never fires — use a thank-you page push on the destination URL.
Conditional logic re-renders. Fields hidden by conditional logic trigger gform_post_render without the form being submitted. This is exactly why you must not use gform_post_render.
Nested forms. Gravity Forms’ nested forms add-on fires the event for the child form when the parent is still mid-submission. Filter by parent form_id if you care about the outer conversion only.
Multiple forms on one page. The event passes the specific formId, so your handler disambiguates correctly. Do not hard-code a single form ID in the listener.