Typeform Event Listener: Track Submissions and Steps
Typeform runs in an iframe and reports back by postMessage. This listener catches both completed forms and every step in between.

Typeform runs inside an iframe on its own domain, so your page cannot see anything happening inside it. What it can do is listen for the messages Typeform sends out.
This listener catches two of them: a completed form, and every step change along the way. The second one is more useful than it sounds.
How Typeform talks to your page
The embedded Typeform sends postMessage events to the parent window. Two matter:
form-submit. The person finished and submitted.
form-screen-changed. They moved from one question to the next.
The listener translates both into data layer events.
The listener code
This is the Typeform listener from DumbData.
The full listener is in the copy block at the bottom of this page, with a copy button. It is reproduced exactly as DumbData publish it, so you can copy it straight from here or from their page.
The two events
typeform_submitted
Fires on completion, with typeFormID. This is your conversion.
typeform_step_change
Fires on every screen change, with typeFormID and stepReference.
This is how you find out where people give up. A Typeform with twelve questions and a thirty percent completion rate is losing people somewhere specific, and the step reference tells you where.
Send it to GA4 as its own event, not as a conversion, then build a funnel on it: building a funnel exploration in GA4.
One change worth making
The listener includes two console.log lines. Useful while testing, noise in production. Remove them once you have confirmed it works. Nothing else about the listener changes.
Installing it in GTM
Create a Custom HTML tag and paste the listener.
Trigger on the pages containing the Typeform embed.
Save and Preview.
Creating triggers and variables
Custom Event trigger, event name typeform_submitted. Save as CE Typeform Submitted.
Custom Event trigger, event name typeform_step_change. Save as CE Typeform Step.
Data Layer Variable named typeFormID. Mind the capital F.
Data Layer Variable named stepReference.
Sending it to GA4
Create a GA4 Event tag.
Event name: generate_lead
Trigger: CE Typeform Submitted.
Sending conversions to Google Ads
Create a conversion action in Google Ads and note the ID and label.
Add a Google Ads Conversion Tracking tag with those values.
Trigger: CE Typeform Submitted.
Meta and everything else
Same trigger, different tag. A Meta Pixel tag with the Lead event, Mixpanel or Piwik PRO from their GTM templates, or a LinkedIn or Microsoft conversion tag.
Testing
Open GTM Preview on the page with the embed.
Answer the first question and confirm typeform_step_change fires.
Complete the form and confirm typeform_submitted fires once.
Check typeFormID is populated on both.
Confirm your conversion tag fired only on submitted, not on every step.
That last check matters. Attaching a Google Ads conversion to the step event would count one visitor as twelve conversions.
Common issues
Nothing fires. The embed may be a redirect to Typeform’s own domain rather than an iframe. In that case there is no parent page to listen on and you need Typeform’s own redirect tracking instead.
Steps fire but submit does not. The person is not reaching the end. Check the funnel rather than the listener.
Fires on other iframes. Unlikely, since the listener checks the message type, and worth knowing if you embed several third party widgets.
Privacy considerations
Never send names, emails, phone numbers or free text into GA4.
Hash anything you send to an ad platform for matching.
Gate the tags behind marketing consent: Consent Mode v2 in GTM
Final thoughts
Typeform is one of the few form tools that tells you about progress as well as completion. Track both. The step data usually reveals a fixable drop off within the first week.
Listener from DumbData.
Need this built properly?
Step data turns a form into a funnel you can actually fix. I set up and repair tracking for ecommerce stores and lead generation businesses, so the numbers in your ad accounts match the money in your bank account.
Have a look at what I do, or book a call and we can go through your setup together.
<script>
///LISTEN FOR MESSAGE FROM IFRAME TYPEFORM
var eventMethod = window.addEventListener ? "addEventListener" : "attachEvent";
var eventer = window[eventMethod];
var messageEvent = eventMethod == "attachEvent" ? "onmessage" : "message";
// Listen to message from child window
eventer(messageEvent,function(e) {
var key = e.message ? "message" : "data";
var data = e[key];
if(data.type == "form-submit"){
console.log("???? Typeform Conversion detected!")
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'typeform_submitted',
'typeFormID': data.formId
});
}
else if (data.type == "form-screen-changed") {
console.log("???? Typeform Step Changed!")
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'typeform_step_change',
'typeFormID': data.formId,
'stepReference': data.ref
});
}
},false);
</script>


















