Form submission event listeners explained
7 min read
Enquiries in your inbox but zero form conversions in GA4 is the most common measurement fault there is. The missing piece is usually a form submission event listener.
If Tag Explorer named one of your tags a form submission event listener, it found a small piece of hand written JavaScript whose only job is to notice when somebody submits a form and tell your analytics about it. It is usually deployed as a Custom HTML tag in Google Tag Manager. Paste your page into Tag Explorer to see this tag on your own site.
That sounds like plumbing, and it is, but it is the plumbing that decides whether your enquiries exist as far as your reporting is concerned. Enquiries arriving in the inbox while the conversions report shows zero is the single most common measurement fault on a lead generation site, and a missing listener is usually why.
What it actually does
A form plugin’s job ends when it has sent you the enquiry and shown the visitor a confirmation. It does not tell analytics anything, because it has no reason to assume analytics is there.
The listener fills that gap. It watches for the moment the plugin confirms a successful submission, then pushes a named event, something like form_submit or a plugin specific name, into the dataLayer: a queue on the page that Tag Manager reads. A Tag Manager trigger watches for that event name, and a GA4 event tag fires and sends the event to your property. In GA4 you then mark that event as a key event so it counts as a conversion.
Four links in a chain, and all four have to be present. A break at any point produces the same symptom: an inbox full of enquiries and a reports screen showing none.
Why it has no ID
The listener is not a product and it belongs to no account, so there is nothing to identify. It sends nothing anywhere by itself; it only announces an event on the page for something else to pick up. Where a tag scan can read one out, the ID you will see belongs to the GA4 tag downstream of it, not to the listener.
What matters instead of an ID is the event name the listener pushes. That name has to match exactly what the trigger listens for, character for character. A listener pushing form_submission into a trigger waiting for form_submit is a working listener, a working tag and no data, and the mismatch is invisible unless you look.
Which forms it hooks, and why there is no template
Every form plugin signals success differently, which is why this is hand written per site rather than picked from a gallery. Common patterns:
- Gravity Forms raises
gform_confirmation_loadedwhen a confirmation is shown, and hands over the form ID. - Contact Form 7 raises
wpcf7mailsentonce the mail is away, carrying acontactFormId. - Ninja Forms and WPForms expose their own submit and success hooks along the same lines.
- Hosted and embedded forms, including booking and CRM widgets, typically post a message from inside their embedded frame.
The built in form submission trigger in Tag Manager listens for the browser’s native submit event, which sounds like it should cover all of this and often does not. Many modern plugins send the form in the background and swap in a confirmation message without the browser ever submitting anything, so there is no native event to hear. Google’s own form interaction measurement in GA4 has the same limitation for the same reason.
One more reason it is bespoke: the useful detail is site specific. Which form, on which page, for which service. Sending the form ID or name along with the event is what lets you tell a quote request from a newsletter signup later, and no generic template could know your forms.
What this looks like in Tag Explorer
Tag Explorer draws your page as a tree. Each Tag Manager container is a branch, the tags inside it are leaves underneath, and anything hard coded into the page HTML sits under DIRECT ON PAGE.
Because a listener is hand written, your container files it as a generic Custom HTML tag with no name attached. The scan reads the code inside and recognises the pattern, including the well known plugin hooks above, so it comes back named as a form submission event listener instead of an anonymous card. Where the code does not match a known pattern, the Details button gives you the actual JavaScript to read, and the event name it pushes is usually obvious in the first few lines.
The card has no ID as its title and no copy button, which is normal for anything without a public ID. The info icon opens a short definition with the Learn more link that brought you here, and Copy for AI lifts the whole tree out as text if you want a second opinion on the code.
The important limit here is bigger than usual. A scan reads the page, so it proves the listener is installed, not that it fired, and firing is the entire question with this tag. It also reads the published container only, so a listener sitting unpublished in a workspace will never appear. Scan the page the form is actually on rather than the homepage, because a listener scoped to one page is a common cause of partial data.
Proof of firing comes from Preview mode in Tag Manager and the GA4 Realtime report, as below.
What to do if it is missing, duplicated or dead
Missing. If no listener appears and your forms submit without changing the URL, assume your form conversions are not being recorded. Check first whether you need one at all: a form that redirects to a real thank you page can be measured by that page view with no code. Otherwise the work is to add a listener hooked to your plugin’s confirmation event, add a trigger on the event name, add a GA4 event tag, publish, and mark the event as a key event in GA4. Historic enquiries cannot be recovered, so the sooner it exists the sooner your reports mean something.
Duplicated. Two listeners for the same form, usually one added by a plugin integration and one added by hand, push two events for one enquiry and double your conversions. That flows straight into ad bidding, which makes it expensive as well as wrong. Keep one, and keep the one you can find and edit.
Dead or stale. This is the case that catches people out, because nothing looks broken. Plugins change their hooks between major versions, forms get rebuilt in a different plugin, a page is redesigned and the form ID changes. The listener keeps loading on every page and quietly hears nothing. Re-test your forms after any plugin update or redesign, and make a test enquiry part of routine upkeep rather than something you do once at launch.
To test: open Preview mode in Tag Manager, submit a genuine test enquiry on the live site, and confirm the dataLayer event appears in the timeline and the matching event lands in the GA4 Realtime report. If the event fires but no conversion is recorded, the fault is downstream, in the GA4 key event configuration rather than in the listener.
Related guides
- Google Analytics 4 explained
- Custom HTML tags in GTM: what is actually in them
- GTM containers explained
- Google Ads conversion tracking explained
- The Google tag (gtag.js) explained
If your enquiry count and your analytics have never agreed, run the page your form sits on through Tag Explorer and see whether a listener is there at all. Getting form tracking to match reality, then keeping it working through plugin updates and redesigns, is part of what our hosting and care plans cover.
Frequently asked questions
Why do my enquiries not show up in GA4?
Because nothing told GA4 they happened. A form plugin emails you the enquiry and shows a thank you message, and by default that is all it does. Unless something listens for the submission and sends an event, analytics has no way of knowing a form was completed, so the inbox and the reports disagree.
Does the built in form submission trigger in Tag Manager work?
Sometimes. It listens for the browser's native form submit, which many plugins never fire because they send the form in the background and swap in a message instead. When it does not work the fix is a listener that hooks the plugin's own completion event rather than the browser's.
Why is this a hand written tag rather than a template?
Because there is no official template for listening to a specific form plugin. The event name, the way the plugin signals success and the data it exposes differ per plugin, so the code is written per site and deployed as a Custom HTML tag. That is why it shows up unlabelled in a container.
How do I prove the listener is firing?
Open Preview mode in Google Tag Manager, submit a real test enquiry on the live site and watch for the dataLayer event in the timeline, then check the matching event appears in the GA4 Realtime report. Test on the page the form actually lives on, because a listener can be scoped to one page and missing everywhere else.
Should I track the thank you page instead?
If your form redirects to a dedicated thank you page, that page view is a perfectly good conversion signal and needs no custom code. It only works when there is a real redirect. Forms that show an inline confirmation without changing the URL need the listener.