Typeform GTM Event Listener
Track Typeform form submissions and step changes in Google Tag Manager. Capture typeFormID, stepReference and fire GA4 events on typeform_submitted.
Typeform
Overview
Typeform is a conversational form and survey tool that embeds via an iframe. Like HubSpot, it uses the window.postMessage API to communicate events to the parent page. This listener intercepts those messages and pushes two events: a submission event and a step-change event for tracking progress through multi-question forms.
Events fired:
typeform_submitted, successful form submissiontypeform_step_change, user advances to next question/step
Credit: Adapted from Codeandtonic
Why Use This Listener
Typeform's iframe architecture makes it invisible to GTM's built-in triggers. Without this listener, you cannot track:
- Who completed a Typeform survey
- Which step users drop off at
- Which form (if multiple) was submitted
This listener provides form-level and step-level granularity.
Common Use Cases
- Track completed lead qualification surveys
- Measure drop-off rates at specific survey questions
- Fire Google Ads conversions only on Typeform completion
- Build audiences of users who completed specific Typeforms
- A/B test different Typeform question orders
How It Works
Typeform dispatches postMessage events from its iframe as users interact with the form. The listener filters for form-submit and form-screen-changed message types and pushes them to the dataLayer.
GTM Setup Guide
Step 1: Create Custom HTML Tag
Tag type: Custom HTML, paste the code below. Fire on: All Pages.
Step 2: Create Event Triggers
| Trigger Name | Event Name |
|---|---|
| CE – Typeform Submitted | typeform_submitted |
| CE – Typeform Step Change | typeform_step_change |
Step 3: Create DataLayer Variables
| Variable Name | DL Key | Purpose |
|---|---|---|
| DLV – Typeform ID | typeFormID | Form identifier |
| DLV – Typeform Step | stepReference | Current step reference |
Installation
<!-- GTM Custom HTML Tag: Typeform Event Listener -->
<script>
window.addEventListener('message', function(event) {
if (event.data && event.data.type === 'form-submit') {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'typeform_submitted',
'typeFormID': event.data.formId
});
}
if (event.data && event.data.type === 'form-screen-changed') {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
'event': 'typeform_step_change',
'typeFormID': event.data.formId,
'stepReference': event.data.ref
});
}
});
</script>Data Layer Output
Submission Event
{
"event": "typeform_submitted",
"typeFormID": "AbC123De"
}Step Change Event
{
"event": "typeform_step_change",
"typeFormID": "AbC123De",
"stepReference": "email_question"
}Trigger Configuration
Trigger: typeform_submitted
Use for: GA4 generate_lead, Google Ads conversion, Meta Lead event
Trigger: typeform_step_change
Use for: GA4 form_progress event with step_name parameter
Variables to Capture
| Variable | DL Key | Example |
|---|---|---|
| DLV – Typeform ID | typeFormID | "AbC123De" |
| DLV – Typeform Step | stepReference | "email_question" |
GA4 Mapping Recommendations
| GA4 Event | Parameter | Value |
|---|---|---|
generate_lead | form_id | DLV – Typeform ID |
generate_lead | method | "typeform" |
form_progress | form_id | DLV – Typeform ID |
form_progress | step_name | DLV – Typeform Step |
Debugging
| Problem | Cause | Fix |
|---|---|---|
| No events firing | Typeform on different subdomain | Check iframe src origin |
typeFormID undefined | Old embed code | Use Typeform's standard <iframe> embed |
| Step changes not tracked | Using popup embed | Popup embeds may use different message format |
Best Practices
- Use
typeform_submittedfor all conversion tracking, never step changes - Track step changes for funnel analysis in GA4 Explorations
- If you have multiple Typeforms, always include
typeFormIDas a GA4 parameter - Use Typeform's hidden fields to pass UTM parameters into the response