Typeform is one of the most used tools for quizzes, applications and lead qualification forms, and it is embedded in an iframe like most hosted form builders. That means your Google Tag Manager cannot see the submit happen. Typeform does post a message to the parent page on submission, and its embed SDK offers a callback. This guide covers both.
How Typeform Signals a Submission
Typeform's embed posts messages to the parent window as the respondent moves through the form. The one we care about has a type of form-submit and includes the form ID. Some versions also include a response ID. The embed SDK additionally exposes an onSubmit callback when you create the embed in JavaScript.
Method 1: Listen for the Submit Message
Step 1: Listener
Create a Custom HTML tag named Listener - Typeform Submit on All Pages or on the pages with the embed:
<script>
(function () {
window.addEventListener('message', function (e) {
if (!e.origin || e.origin.indexOf('typeform.com') === -1) { return; }
var data = e.data;
if (typeof data === 'string') {
try { data = JSON.parse(data); } catch (err) { return; }
}
if (!data || data.type !== 'form-submit') { return; }
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'form_submit_success',
form_tool: 'typeform',
form_id: data.formId || '',
response_id: data.responseId || ''
});
});
})();
</script>
Step 2: Variables, trigger and tags
Data Layer Variables for form_id and response_id. A Custom Event trigger for form_submit_success, with a form_id condition if you embed several forms. Fire GA4 generate_lead with form_id and response_id, your Google Ads conversion tag, and your Meta Lead tag. Keep the Conversion Linker on All Pages.
Method 2: Embed SDK Callback
If you create the embed with Typeform's JavaScript SDK rather than the copy-paste snippet, you can pass an onSubmit callback and hidden fields:
<div id="typeform-embed"></div>
<script src="https://embed.typeform.com/next/embed.js"></script>
<script>
window.tf.createWidget('YOUR_FORM_ID', {
container: document.getElementById('typeform-embed'),
hidden: { gclid: new URLSearchParams(location.search).get('gclid') || '' },
onSubmit: function (event) {
window.dataLayer = window.dataLayer || [];
window.dataLayer.push({
event: 'form_submit_success',
form_tool: 'typeform',
form_id: 'YOUR_FORM_ID',
response_id: event.responseId || ''
});
}
});
</script>
The hidden field stores the Google click ID with the response, which lets you upload qualified leads back to Google Ads as offline conversions later. That is often more valuable than Enhanced Conversions for a qualification form.
Method 3: Thank-You Redirect With Enhanced Conversions
Set the Typeform ending to redirect to a thank-you page on your site and append the email as a parameter using Typeform's recall syntax. Fire your tags on a Page View trigger for that page, read the email with a URL variable into a User-Provided Data variable, then clean the URL with history.replaceState. Add noindex to the page.
Testing
- GTM Preview on the page with the Typeform. Complete the form.
- Confirm
form_submit_successappears with the form ID and response ID. - Confirm one fire each for GA4, Google Ads and Meta.
- Check the Google Ads request in a tag debugger such as the Insighter Debugger extension.
- If you used hidden fields, open the response in Typeform and confirm the gclid value was stored.
Common Problems
- No message arrives. Log messages in the console to see what the current Typeform embed sends. Message names have changed between embed versions.
- Fires on every question. You are matching on any message rather than
form-submit. Check the type condition. - No campaign attribution with GTM inside Typeform. Add cross-domain linking for typeform.com in the Conversion Linker, or use Method 1.
Recommendation
Use Method 1 for a quick, reliable conversion. Move to Method 2 when you want the click ID stored with each response for offline conversion uploads. Use Method 3 only when Enhanced Conversions matter more than keeping the email out of the URL.
