When HubSpot CTAs Break Attribution: How to Track iFrame Conversions with Google Tag Manager
Attribution problems are often hard to spot because nothing appears to be broken. The form submits, the lead shows up in HubSpot, and the dashboard may even record a conversion.
But most modern websites are stitched together from several different systems, and those systems do not always share data cleanly. When one of those connections fails, attribution can become unreliable.
HubSpot CTAs are a good example, particularly pop-up CTAs and embedded lead forms that load inside iFrames. The CTA can work perfectly well for the user while the tracking behind it remains incomplete. Google Ads conversions may not fire consistently, GA4 events can go missing, and enhanced conversion tags may lose access to the information they need.
This affects more than the accuracy of a dashboard. Missing conversion signals can reduce retargeting audiences, weaken enhanced conversion matching, and give advertising platforms less reliable data for campaign optimization. For advertisers with relatively low conversion volume, even a small number of missed events can have a meaningful impact.
The Problem Finds a Partial Solution
The problem comes from the way these Hubspot CTAs are built. Because the form is hosted inside a cross-domain iFrame, Google Tag Manager on the parent page cannot directly observe the form submission or access the data entered into it. Common tracking methods such as form triggers, click listeners, and DOM observation therefore become unreliable or simply do not work.
We found several workarounds online, including a useful article from TrackFunnels that uses Google Tag Manager to listen for messages sent by the iFrame. That gave us a good starting point, but we needed the solution to do more: support conversions across several platforms, produce consistent GA4 events, capture the email address for enhanced conversions, and work reliably across different CTA implementations.
Getting there required more than detecting that a form had been submitted. We first had to understand how the HubSpot iFrame communicated with the parent page, then turn that communication into a dependable tracking event.
A More Complete Solution: Listening inside the iFrame
Our first instinct was to use the same techniques that work for most embedded forms: GTM form submission triggers, click listeners, DOM observation, and HubSpot’s traditional form callbacks. None of these produced reliable results.
The reason became apparent after inspecting the implementation. The CTA was rendered inside a cross-domain HubSpot iFrame (hs-web-interactive), meaning the parent page had no direct visibility into the form itself. Browser security restrictions prevented GTM from observing form interactions inside the iFrame, which immediately ruled out many common tracking approaches.
The breakthrough came from examining how the iFrame communicated with the parent page. Although the form contents remained inaccessible, HubSpot was sending structured postMessage events back to the parent window. To investigate, we attached a generic message listener and logged every event emitted during the CTA lifecycle. Most of the traffic consisted of operational messages—heartbeat (“PING”) events, resize notifications, and other framework-level communication. However, by observing the message stream while submitting the form, we were able to isolate a specific callback that appeared only on successful submission:
hsCallsToActionCallback → onCallToActionFormSubmittedThis proved to be the critical discovery. Rather than attempting to access the form directly, which browser security restrictions prevent, the solution focused on the communication channel between the HubSpot iFrame and the parent page. Once the submission callback had been identified, it became possible to extract the associated metadata and reliably trigger attribution events from the parent page.
Unlike the generic heartbeat and resize messages emitted by the CTA framework, this event fired only after a successful submission and contained useful metadata, including the CTA ID, form ID, conversion ID, and—critically—the submitted email address within the submissionValues object.
This allowed us to build a lightweight listener that intercepted the submission event and pushed a normalized event into the dataLayer:
hubspot_popup_submitFrom there, Google Tag Manager could treat the CTA submission exactly like any other conversion event. GA4 events, Google Ads conversions, and downstream attribution workflows could all trigger from a consistent dataLayer event rather than attempting to interact directly with the iFrame.
The implementation also provided access to the submitted email address, which can be used for enhanced conversion workflows where appropriate. Importantly, raw email addresses should never be passed directly into GA4. Instead, they should either be excluded from analytics platforms entirely or used only within platforms that explicitly support hashed first-party identifiers, such as Google Ads Enhanced Conversions.
Perhaps the most interesting outcome was that the solution required no modification to the HubSpot CTA itself. The form remained fully managed within HubSpot while the parent page simply listened for the messages HubSpot was already broadcasting. This reduced implementation complexity while preserving attribution fidelity across advertising and analytics platforms.
The key lesson is that many modern embedded experiences are not completely opaque. While direct DOM access may be impossible, the underlying application often exposes communication channels that can be leveraged for measurement. In this case, the challenge was not tracking the form itself, it was discovering the right event stream to listen to.
How to Implement the Tracking Script
The setup is relatively straightforward and can be completed entirely in Google Tag Manager.
1. Add the script to Google Tag Manager
Copy the code from the snippet below and paste it into a new Custom HTML tag in Google Tag Manager.
<script src="https://gist.github.com/paulnewnes/2ca66a4258c884cbf8ce5fe68d9182bb.js"></script> This script listens for the HubSpot message that confirms a successful CTA form submission.
2. Choose where the script should run
Add a trigger that loads the tag on pages where a HubSpot pop-up CTA may appear.
Depending on your website, this could be:
an All Pages trigger, if the CTA can appear anywhere
a Page View trigger limited to specific pages or URL patterns
Limiting the trigger to relevant pages can reduce unnecessary script activity.
3. Test the submission event
Open Google Tag Manager’s Preview mode and visit a page containing the HubSpot CTA.
Complete and submit the form.
After a successful submission, you should see a new data layer event named:
hubspot_popup_submitThe event should include additional information about the submission, such as the CTA ID, form ID, conversion ID, and submitted email address.
Review the event in Preview mode and note the exact names of any values you want to use in your tracking tags.
4. Create data layer variables
For each submission value you want to capture, create a new Google Tag Manager variable using the Data Layer Variable type.
For example, you might create variables for:
CTA ID
form ID
conversion ID
email address
The data layer variable name must exactly match the parameter name shown in Preview mode.
5. Create the submission trigger
Create a new Custom Event trigger in Google Tag Manager.
Set the event name to:
hubspot_popup_submitThis trigger will fire whenever the script detects a successful HubSpot CTA submission.
6. Connect the event to your tracking platforms
Create the tags you want to fire when the submission occurs, then attach the new custom event trigger.
Depending on your measurement setup, these might include:
a GA4 event
a Google Ads conversion
a Meta event
another analytics or advertising platform
You can also pass selected data layer variables into those tags where appropriate.
Raw email addresses should not be sent to GA4. Email should only be used with platforms and workflows that explicitly support first-party identifiers, such as Google Ads Enhanced Conversions, and should be handled according to the platform’s requirements.
7. Test and publish
Run through the full process again in Google Tag Manager Preview mode.
Confirm that:
the hubspot_popup_submit event appears
the expected data layer values are available
the relevant tags fire only after a successful form submission
no tags fire when the form is opened but not submitted
Once everything is working correctly, publish the Google Tag Manager container.
An Advanced Use Case
For more advanced attribution analysis, the submission event can also be sent to a data warehouse such as BigQuery.
For example, you could store:
the GA4 client ID
the submitted email address or an appropriately protected identifier
the date and time of submission
the CTA and form identifiers
This data can then be matched with the GA4 BigQuery export to examine the acquisition history associated with the submission, including the traffic source from the user’s first visit and from later sessions.
This requires careful handling of personal data and a reliable method for joining records, but it can provide a much more complete view of the path that led to a conversion.
What This Reinforced For Us
This project highlighted a broader truth about modern analytics implementations: The biggest measurement problems are rarely caused by missing tools. They’re caused by invisible boundaries between tools.
As platforms become more composable, attribution increasingly depends on understanding how systems communicate, or fail to communicate, across those boundaries.
HubSpot’s iFrame architecture is not inherently flawed. It solves legitimate security and portability challenges.
But it also creates a separation layer that marketers and analysts need to account for intentionally if they care about clean attribution.
If your team is struggling with attribution gaps, inconsistent conversion tracking, or GA4 implementation challenges across embedded experiences, Deducive can help design measurement systems that are resilient, observable, and built for modern marketing stacks.