
April 11, 2025
Track Gravity Forms With Google Tag Manager and GA4
Updated: April 11th, 2025
Gravity Forms is a customizable WordPress plugin that enables you to add simple or complex forms to your website, blog, or whatever you’re running on WP.
However, just like any important interaction, tracking form submissions is necessary to understand visitors’ behavior better. In this blog post, I’ll show you how to track Gravity forms with Google Tag Manager and send Form submission events to Google Analytics 4.

+ Here’s what you will learn in this article +
- #1. Short version
- #2. Long version
- Final Words
#1. How to track Gravity Forms with Google Tag Manager [short version]
If you’re in a hurry, just follow these quick steps. But if you want to understand how to evaluate different ways of doing this, read the full blog post.
#1.1. Gravity Forms Listener
Create a Custom HTML tag with the following code:
<script type="text/javascript"> jQuery(document).ready(function() { jQuery(document).bind("gform_confirmation_loaded", function(event, formID) { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'event': 'formSubmission', 'formID': formID }); }); }); </script>
Set the tag to fire on all pages with the embedded Gravity form (e.g., Page Path contains “contact-us”). This JavaScript code will listen to successful form submissions and fire a Data Layer event called formSubmission.
IMPORTANT: This listener supports AJAX-based Gravity Forms. The listener will work properly if the page doesn’t refresh after submission. If a successful submission sends the user to a separate Thank you page, you’ll have to add additional code to the form’s settings. Read the next chapter to find out more.

#1.1.1. What if my Gravity form refreshes the page or redirects a visitor to a ‘thank you’ page?
You’ve probably figured that the Gravity Form Listener given above does not work in these situations. Instead, you’ll need to log in to WordPress, find the form, and add an additional code snippet so that the listener identifies a successful form submission.
In WordPress:
- Go to Forms and open the one you wish to track.
- Then go to Settings
- Click Confirmations.
- Usually, the Confirmation type is “Text” and what you’ll need to do is add a small JavaScript code there. It will create a Data Layer event, “formSubmission”, which we’ll use later as a trigger.
The code snippet that you need to add after the Confirmation message is:
<script> window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'event': 'formSubmission' }); </script>
Two important things to keep in mind:
- Before pasting the code, switch the text editor to “Text” mode (instead of “Visual”)
- Disable the auto-formatting in that editor (there’s a checkbox at the bottom). Otherwise, it will break the code.
How to test if this is working? Save the Confirmation settings, enable GTM Preview and Debug mode, return to your form (on the website), and submit it. If you see “formSubmission” event in the Preview console, the code is working fine, and you can move on to the next chapter.
One more thing. If you have two or more Gravity forms on the same page and those forms refresh the page, then you need to modify some parts of the window.dataLayer.push code I’ve recently mentioned.
In this case, both forms should have different codes. The adjusted code of the first form could look like this:
<script> window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'event': 'formSubmission', 'formID': '1' // you can replace that 1 with anything you want. Just make sure it makes sense to you. }); </script>
As for the 2nd form, its code should contain ‘formID’: ‘2’.
<script> window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'event': 'formSubmission', 'formID': '2' // you can replace that 2 with anything you want. Just make sure it makes sense to you. }); </script>
Why did we do that? different form IDs will help you identify (in the data layer) which form was submitted.
By the way, if the form redirects a visitor to another page (a.k.a. “Thank you page”) and the “Confirmation type” in your gravity form is “Redirect”, read this guide on tracking such forms.
Important: It’s worth mentioning that I have seen a website where the user is redirected to a homepage after the form submission (without any success message displayed or any “Thank you” page). In that case, nothing in this guide will help you. Your only option would be to change the form settings and either display a success message for the visitor or redirect them to a dedicated confirmation page.
Also, think about the user experience. If you submit a form and are then just redirected to the homepage (without a success message), that looks confusing.
#1.2. Custom Trigger and (optional) Variable
In your GTM account, go to Triggers > New > Custom Events.
Also, create a Data Layer variable called formID if you want to pass its value to Google Analytics. This variable is optional, and you can skip it if you wish. Also, you don’t need this variable if your form refreshes the page and you use the solution described in the 1.1.1 chapter of this blog post.
#1.3. Google Analytics 4 Event Tag
Finally, pass the data to Google Analytics by creating a GA4 event tag with the following settings:
Note: there’s a little typo in the screenshot above. The name of the variable should have been “dlv – formID”, not “dlv – form_id”.
Feel free to remove the {{dlv – formID}} variable if you wish. Assign the formSubmission custom event trigger you have created in the previous chapter of this blog post.
That’s it! Don’t forget to test various scenarios:
- Submit the form when all required fields contain some values. Expected result: the GA4 Event tag should fire.
- Try leaving at least one required field empty and try to submit the form. Expected result: the GA4 Event tag should not be fired.
Also, don’t forget to check Google Analytics Real-time Event reports, as all successful form submissions should be visible there.

#2. How To Track Gravity Forms with GTM [Long version]
Believe it or not, you could have solved this puzzle by yourself, even if you don’t know how to code. In this blog post, I’ll explain various details of how a non-developer can write a little piece of code, use it in Google Tag Manager, and precisely track only successful Gravity form submissions.
#2.1. Important: Before we continue
If, for some reason, this blog post fails to help you track Gravity Forms with Google Tag Manager, here are a bunch of other form-tracking techniques.
After tracking hundreds (if not thousands) of various forms, I have polished the most common solutions, so you should definitely check the form tracking guide.
#2.2. Gravity Forms Listener
The entire form-tracking process looks like this:
- We implement an auto-event listener that tracks only successful form submissions and pushes those events to the Data Layer.
- Create a Custom Event trigger (which recognizes the Data Layer Event) and a Data Layer Variable (this one’s optional).
- Create a Google Analytics 4 Event tag and link it to the Custom Event Trigger.
You have probably already tried a built-in Google Tag Manager Form Submission trigger, which failed you with Gravity Forms. Otherwise, you wouldn’t be here, right? Well, you’re not alone because that trigger rarely works.
So what’s the solution? We should get (or maybe create) a Gravity Forms Listener, a JavaScript function that listens only to successful form submissions and fires a Data Layer event. As a result, we could utilize that event as a trigger and fire a Google Analytics Event tag.
Shall we start?
#2.3. Create a Gravity Forms listener
In 2017, I published a blog post on How to write an auto-event listener with zero coding skills. It received very positive feedback from the community. Today, I’ll demonstrate that technique in action with Gravity Forms.
#2.3.1. STEP 1. Let’s check whether there is a JavaScript API
Open Google and enter Gravity Forms JavaScript API. It’s crucial that you look for JavaScript API, not regular API. Your search results should look like this:
The 2nd search result looks promising. Let’s click it. We should be one step closer to writing an auto-event listener.

#2.3.2. STEP 2. Let’s see which JS API methods are available
Now you’ll need to check whether the API is well documented and easy to understand, even for those who do not know how to code. Since we want to track ONLY successful form submissions, we should keep looking for some terms which contain “success”, “form submission”, “confirmation”, etc. You get the idea, right?
What we are looking for is some kind of API method that is related to successful submissions. Honestly, it took me a while to find a proper page in Gravity Forms’ documentation (because they offer A LOT of stuff).
You’ll find a navigation bar on the left side of the Gravity Forms API reference. Go to Hooks > Filters > Confirmations > gform_confirmation_loaded. This JavaScript hook (gform_confirmation_loaded) fires when the form’s “Success” page is loaded (which is exactly what we’re looking for!).
Bingo! We’re one step closer to success, but there’s still something we need to verify.
#2.3.3. STEP 3. Are the code examples ready-to-use and very simple?
Even if the API offers valuable methods and the documentation is very well written, one requirement still remains. Is the API Reference really dummy-proof? Will a non-developer be able to use it with ease?
Honestly, it is not common practice to write super simple code examples in API references, which could be helpful for non-devs or beginners. Sometimes, it’s even next to impossible.
For example, Wistia offers a very well-written JavaScript API reference, but examples are not designed for entry-level developers. Thus, you and I won’t be able to write our own custom auto-event listeners.
In Wistia’s case, we’re lucky to have Bounteous because their developers posted this awesome Wistia listener for GTM. But there are still lots of situations where a ready-made tracking solution simply does not exist.
OK, let’s go back to Gravity Forms. I have navigated to gform_confirmation_loaded JavaScript hook and found this example of code:
This is perfect! Let me explain what’s happening.
This code is ready to use. It states: if gform_confirmation_loaded occurs, initiate a function. Currently, that function is empty, but we can easily embed the dataLayer.push event just by replacing the text //code to be triggered when the confirmation page is loaded with the actual data layer code.

#2.3.4. STEP 4. Add dataLayer.push event(s)
Copy that code from the Gravity Forms API documentation and paste it into some plain text or code editor (e.g., Notepad, Notepad++, Sublime, etc.).
<script type="text/javascript"> jQuery(document).bind('gform_confirmation_loaded', function(event, formId){ // code to be triggered when confirmation page is loaded }); </script>
Remove //code to be triggered when the confirmation page is loaded
<script type="text/javascript"> jQuery(document).bind('gform_confirmation_loaded', function(event, formId){ }); </script>
Prepare dataLayer.push event code:
window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'event': 'formSubmission', //you can actually name this even whatever you want 'formID': formId });
Why did I add formId? Well, that’s because the Gravity Form’s JavaScript webhook returns the form’s ID (see function(event, formId) ?). It’s optional, so feel free to remove it.
Now, merge the Gravity Form’s code snippet with window.dataLayer.push. This is what the final result should look like:
<script type="text/javascript"> jQuery(document).ready(function() { jQuery(document).bind("gform_confirmation_loaded", function(event, formID) { window.dataLayer = window.dataLayer || []; window.dataLayer.push({ 'event': "formSubmission", 'formID': formID }); }); }); </script>
Great! We’re very close to finishing the Gravity Form auto-event listener!
#2.3.5. STEP 5. Create a Custom HTML tag and test
In the Google Tag Manager account, create a new Custom HTML tag. Paste the code you have created in the previous step.
Done! Save the tag and assign the trigger you want, e.g., All Pages (or, preferably, just on those pages where the form is located).
Don’t forget to test the listener with GTM Preview and Debug mode. Load the page with any Gravity Form and complete a test submission. A Data Layer event called formSubmission should appear in the event stream. Click it and check what data was passed to the Data Layer. It should look like this.
#2.3.6. STEP 6. Success
Victory dance! But don’t relax too soon. There’s still something left to do to track Gravity Forms with Google Tag Manager.
#2.4. Create Trigger (and, optionally, a Variable)
Even though there is a formSubmission event in the Preview and Debug console, you cannot use it as a trigger. Why? Because Google Tag Manager, by default, does not recognize what’s happening in the Data Layer.
So what’s the solution? You’ll need to create a Custom Event trigger. Go to your Google Tag Manager account and click Triggers > New. Create a Custom Event trigger with the following conditions:
In the next step, we’ll create a Google Analytics 4 Event tag. If you want to pass a form ID with it, create a Data Layer Variable. It’s helpful if you have more than one Gravity form on a page or a website.
#2.5. Google Analytics 4 Tag
In this article, I presume that you have already installed GA4 with Google Tag Manager. If not, then read this guide first.
Finally, let’s pass the data to Google Analytics by creating an event tag with the following settings:
To send additional parameters along with the form_submission event, one needs to add them as an event parameter here and as a custom dimension inside GA4. This helps Google understand that the particular parameter passed must be shown inside the GA4 reports.
As I mentioned previously, feel free to remove the {{dlv – formID}} variable if you wish. Assign the form_submission custom event trigger you created in the previous chapter of this blog post.
That’s it! Don’t forget to test various scenarios with a GTM Preview and Debug mode:
- Submit the form when all required fields contain some values.
- Try leaving at least one required field empty and try to submit the form.
Also, don’t forget to check Google Analytics Real-time Event reports. All successful form submissions should be visible there.
Final Words: How To Track Gravity Forms with Google Tag Manager
I hope that this blog post was useful. Not only did you manage to track Gravity Forms, but you also learned how to write auto-event listeners without coding skills.
In conclusion, here’s the entire tracking workflow:
- First, you must check how your form works after the successful submission. If it refreshes itself (but not the entire page), implement an auto-event listener with a Custom HTML tag. A listener is a function that listens to particular interactions on a page. In this case, it’s a successful Gravity Form submission. You can either use a ready-made listener (if possible), try to write your own (here’s a guide for non-developers), or ask a developer to help you. A listener must push the event of a successful form submission to the Data Layer.
- If the form refreshes the entire page, you must edit its confirmation message by adding a little code snippet with window.dataLayer.push. After the successful form submission, it creates an event that you can catch with a custom trigger.
- If the form redirects a visitor to a Thank you page, you must use this tracking method.
- Create a Custom Event Trigger that would recognize the form submission Data Layer event. It’s a necessary ingredient for the Google Analytics 4 Tag to fire. Optionally, you can create a Data Layer Variable to help transfer Form ID to Google Analytics.
- Finally, create a Google Analytics 4 Event tag that fires when a successful form submission occurs on a page.
If this guide did not help you, don’t feel bad because I have a bunch of alternative solutions on how to track forms with Google Tag Manager. Give it a shot.

43 COMMENTS
I thought I'd jump in here with regard to the formID variable. If you have 2 forms on a single page and you're using the trigger for custom event formSubmission, you will receive a submission event for both forms on the page with the same formID. The trigger needs to distinguish the forms, in this case we used added the default form ID to the trigger, but that means you need 2 triggers, not just one for both forms, unless I'm missing something. Thanks for a great post!
Hey, you can use one trigger for both forms. Just in trigger's condition use "Matches Regex" operator. For example:
Form ID Matches Refex (ignore case) form1|form2. That way the trigger will be looking for forms which have ID "form1" or "form2".
Hi,
Thank you for your post.
I have tried the built-in Google Tag Manager Form Submission trigger and it is working when the Gravity form is submitted. The page also reloads after the submission.
is it okay to use this trigger despite your post suggesting other methods?
I also need to push some information in the forms to the data layer, do you have any article regarding the extraction of data from forms and pushing them into the data layer?
Many thanks
I just implemented this on a site and it did track the form submission when I was in Real Time, but when I look at the Goal Hits in the last 30 minutes, 1 submission is registering 4 times. Submitted it again and now that number was 8. So it looks like for each 1 form submission, 4 are getting registered. Any ideas on how that happens?
So is the tag also firing 8 times? If yes, you could try to set the GA tag to fire only once per page.
Hi Julius,
Thank you for the reply! The tag was actually firing 4 times per 1 submission. I switched from "once per event" to "once per page" and it seems to be working better. Just tested it and 1 submission matched 1 conversion. I will be leaving as is today and checking again tomorrow to make sure the number of actual submissions matches the conversion in Google Analytics. I will update this again if I find any other issues. Thank you again!
Julius, I've been using your method now for over a year without error, but now all of a sudden I'm seeing 2 events for each form submission.
While monitoring Analytics > Realtime > Events, I see both for one form submission:
formID = Contact Us
formID = 1
One event has the formID specified in the confirmation script: "Contact Us",
and the duplicate is showing the form's actual ID, formID = 1
As a temporary solution, I've deleted the confirmation script and just use the formID = 1 event. But I'd like to go back to how it was working before. Any ideas?
Maybe Gravity forms updated and changed something. Not sure.
You can also set the tag to fire once per page. That can also work.
@michael same here, i'm working with old gravityform 2.4.10
Hello! Love your website and tutorials. Quick thought on a question above about accessing particular form fields within the listener and pushing to variable - I found some definitions for form object on Gravity Forms API docs here (https://docs.gravityforms.com/form-object/). There must be some way to configure the listener function to access these fields via the data form object, no? They fact that they GF is passing formId variable indicates to me that we should be able to access it, I'm thinking. What do you think?
Hi, the link you shared is for the backend functionality. Not for tracking with Javascript. The listener returns only form id. Other fields are not passed.
Yep, after I post the comment yesterday I realized that's OK. This particular API allows us to access the form object data server-side only. So I guess what could be done is to use a GTM script to callback a script in the form submission hook, and push the response to data-layer variable, if it was my goal to handle form data with GTM. That might be useful to anyone else who read these comments and asked the same thing.
Hey Julius,
This works but I get an error in the console saying jQuery is not defined. Is there a way of writing the script without using jQuery(document).ready(function() ?
Fixed it. Changed the trigger to DOM Ready.
This is great! One thing I'm wondering is how would I track when someone x or closes out of a gravity form? I tried building a trigger based on the click element but that didn't work
I would still try to track the click on that button. If it does not work for you, then the problem is somewhere in the trigger condition.
My events will only fire and show as a conversion inside the tag assistant manager. But if I perform a form submission test just using the regular browser it doesn't. Any ideas????
Make sure you published the GTM container
Thanks for this super-useful guide - I always point people in the direction of your website.
The goal works on testing but actual form submissions are being under-reported in Google Analytics.
Could be some kind of plugin conflict I suppose. Or browser privacy settings of the user?
I'm pretty stumped TBH - anyone have any ideas at all?
Yes - love this website. Thanks for all your great content and help!
I'm having a similar issue. i.e., Under-reported form submissions in Google Analytics compared to actual form submissions in Gravity Forms. If the numbers were off just a bit, I wouldn't worry about it. But the difference is pretty huge. It's driving me bonkers.
I actually followed Gravity Forms documentation for the setup (https://docs.gravityforms.com/how-to-use-google-analytics-4-with-the-gravity-forms-google-analytics-add-on/). What's the difference/benefits of the different methods? Any ideas why GA4 would be displaying form submissions but at much lower numbers than I see in Gravity Forms? Privacy settings? Any thoughts or suggestions would be helpful.
Any luck at resolving this at all Dan?
No, unfortunately. Still working through it and hoping for any insight from others.
Hi Dan - FWIW I got to the bottom of my issue. I inspected the page using the Chrome Console and figured out that GTM was firing before jquery was loaded. So I got the devs to manually place the GTM code rather than through a plugin as it had been.
Hello Julius, Thanks for this tutorial.
I followed your blog post re: tracking events in universal Analytics and it was great. Now I am following this post to configure tracking events in GA4. However, this post shows the configuration for GTM only, where can I find the necessary configuration for GA4? What necessary steps should i do in GA4 to track events?
Hi Julius, I have a client site where their Gravity form redirects to a Calendly page to schedule an appointment I read the section on '#1.1.1. What if my Gravity form refreshes the page or redirects a visitor to a ‘thank you’ page?'
and I see how you said to use the text option to add JavaScript, but I don't know how to keep the redirect in place.
I'm trying to track form submissions from one specific form on this site.
A word of advice for anyone implementing this solution who has Cloudflare. Ensure you disable the Rocket Loader in Cloudflare as it stops the GTM Listener working correctly. It works fine in GTM debug/preview mode but not in live.
Hi,
it looks like here they use almost the same listener as you, but they also have all form fields available in the datalayer.
https://support.strattic.com/articles/how-to-use-google-tag-manager-to-track-gravity-forms-on-strattic/
The problem is though it is strattic so the code will not work for normal WP installations.
Do you think formDetails (form filed data) could be integrated in your script somehow?
Cheers
We would like to use thankyou pages. But we also want to send the emailaddress with the dataLayer. How can we achieve that? I did not see that in one of the existing solutions.
Hey Julius,
Thank you for the great, straight forward post to follow!
Just wondering how I'd go about tracking 19 different forms - i.e. get the form name & no successful/unsuccessful form submissions showing in Google Analytics.
For context, the forms are setup via Gravity Form and don't open to a new page once user presses 'submit'.
Can you advise how we can achieve this?
Hi Julius,
I have finally gotten events to trigger in GTM debug mode for 2 of my GF forms, but the events are still not showing in GA4.
They show up when I look at debugView there, but they're not showing up in Events, so I can't select "Mark as Conversion". My goal is to track form submissions as conversions, but I don't know how to make them show up in GA4 now that it seems like I have it set up correctly in GTM.
Any idea how to enable that?
HI Julius,
Great guide! The only thing is that appears to be blocked. When I try to save the text, it refuses due to safety concerns.
Is there anything I can do? Disabling the safety is not really an option unfortunately.
Hi Julius, Fantastic article! However i am struggling to configure enhanced conversions. My developer was unsure of how to capture the email and phone number dynamically for EC. Do you have any tips or documentation that can help? We are trying to implement offline conversion data and ideally I would like to do this through email rather than GCLID.
Thanks
We got help from TheColorClub. An Agency of developers in Denmark. They enabled Data Layer for all form inputs like Email and Phone. You can ask for Lasse. They have a script which you just have to put into the functions php of your theme.
Hey
First off, I just want to say that I love your work and content.
I was wondering if you know how I can grab the email address form the submission and create a data layer with this info that can later be used for a Google Ads User-provided Data Event.
I'm also here for this:
"I was wondering if you know how I can grab the email address form the submission and create a data layer with this info that can later be used for a Google Ads User-provided Data Event." from the previous comment.
I'm also here for this:
"I was wondering if you know how I can grab the email address form the submission and create a data layer with this info that can later be used for a Google Ads User-provided Data Event." from the previous comment.
Hi Julius, thanks for article! I’m having trouble setting up Enhanced Conversions. Do you have any tips or guides that could help?
Julius - A question about the above where I'm a bit confused.
In step 1.2, we create a variable "dlv - formID" and the Data Layer Variable Name is formID
In step 1.3, in your illustration, Event Parameter "form_id" has a value of {{dlv - form_id}}
Shouldn't that value be {{dlv - formID}}?
Good catch. It should have been formID in the 1.3
Same question:
I was wondering if you know how I can grab the email address form the submission and create a data layer with this info that can later be used for a Google Ads User-provided Data Event.
I could not follow #1.1.1. because GravityForms would not allow me to insert a script into the form submission text. I got around it by enabling AJAX in the Wordpress settings on the page where the form was embedded, which prevents the page from refreshing. Maybe this would be good to mention.
Sorry, disregard. I see it's mentioned there :S. Still probably would have missed that Wordpress setting the first time through though, ha.