How to use GA4 with iframe

Challenges with Iframes and GA4

Iframe and GA4 are not a match made in heaven.

#1 Same-origin policy

The use of iframes can potentially block the GA4 configuration tag from firing due to a concept known as the “same-origin policy.”

Suppose an iframe is loaded from a different domain.

In that case, the same-origin policy will restrict the iframe content from accessing the parent document’s properties, which can block the GA4 configuration tag from firing and collecting data.

Even when an iframe is loaded from the same domain as the parent document, it is still considered a separate document, and its content is isolated from the parent document.

Get weekly practical tips on GA4 and/or BigQuery to accurately track and read your analytics data.

 

#2 Data isolation

Iframes do not share cookies and local storage with the parent document. 

This isolation affects user identification and session tracking because the GA4 tag in the iframe cannot access cookies or local storage data set by the parent document and vice versa.

#3 Tracking limitations

The GA4 tag inside the iframe won’t have direct access to the parent document’s URL, which could affect the accuracy of the collected data, particularly the attribution of traffic sources and campaign parameters.

The GA4 tag inside the iframe will only be able to track interactions that occur within the iframe itself and won’t capture events on the parent document.

How to use GA4 with iframe

#1 Fire GA4 Configuration tag outside the iframe.

To avoid the same-origin policy issues, it is generally best to fire the GA4 configuration tag outside the iframe. 

This will ensure that the tag is not subject to the same-origin policy and has access to all the data it needs to track users’ interactions with your website accurately.

You can add the GA4 configuration tag to the parent document as follows:

<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'GA_MEASUREMENT_ID');
</script>

Replace ‘GA_MEASUREMENT_ID’ with your actual GA4 measurement ID.

#2 Use ‘window.postMessage’ API

The second solution is to use the ‘window.postMessage’ API to send data between the parent document and the iframe.

This method allows the iframe to communicate with the parent document without violating the same-origin policy.

For example,

The parent document can send the Google Analytics Client ID to the iframe, enabling the iframe to create the ‘_ga’ cookie and use the same Client ID for tracking.

First, in the parent document, you need to get the Client ID from Google Analytics and send it to the iframe using window.postMessage.

In the Parent Document:

// Function to get the Google Analytics Client ID
function getGAClientId() {
  return new Promise((resolve) => {
    gtag('get', 'GA_MEASUREMENT_ID', 'client_id', function(clientId) {
      resolve(clientId);
    });
  });
}

// Send the Client ID to the iframe
getGAClientId().then(clientId => {
  const iframe = document.getElementById('your-iframe-id'); // Replace with your iframe's ID or selector
  iframe.contentWindow.postMessage({
    event: 'ga_client_id',
    clientId: clientId
  }, '*');
});

Replace ‘GA_MEASUREMENT_ID’ with your GA4 measurement ID and update ‘your-iframe-id’ with the correct ID or selector for your iframe.

In the iframe, you need to listen for the message from the parent document, extract the Client ID, and then set the _ga cookie accordingly.

In the iframe:

// Listen for messages from the parent
window.addEventListener('message', function(event) {
  if (event.data && event.data.event === 'ga_client_id') {
    const clientId = event.data.clientId;

    // Set the _ga cookie with the received Client ID
    document.cookie = `_ga=GA1.2.${clientId}; path=/;`;

    // Optionally, initialize GA tracking with the received Client ID
    gtag('config', 'GA_MEASUREMENT_ID', {
      'client_id': clientId
    });
  }
});

Again, replace ‘GA_MEASUREMENT_ID’ with your actual GA4 measurement ID.

After setting the _ga cookie in the iframe, you can initialize GA4 with the same Client ID that the parent document is using.

Optional GA4 Initialization in the iframe:

<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());

  // GA4 configuration will be handled after receiving the Client ID from the parent
</script>

Following is the summary of the entire process:

Parent Document:

  1. Retrieves the GA4 Client ID.
  2. Sends the Client ID to the iframe using window.postMessage.

Iframe:

  1. Receives the Client ID.
  2. Sets the _ga cookie with the received Client ID.
  3. Optionally initializes GA4 with the same Client ID.

This ensures that both the parent and iframe use the same Client ID for tracking, enabling consistent tracking across both contexts.

#3 Handle all tracking in the parent document.

The iframe can send all dataLayer messages to the parent document, which processes them and sends them to GA4.

This method simplifies the implementation because you only need to set up GA4 tracking in one location (the parent document).

It avoids the complexity of setting up and maintaining separate tracking codes in both the parent and the iframe.

Since the tracking code runs in the parent document, you circumvent the same-origin policy restrictions that would otherwise prevent the iframe from accessing the parent document’s properties.

To handle all tracking in the parent document while allowing the iframe to send dataLayer messages, you can set up a system where the iframe sends its tracking data to the parent document via ‘window.postMessage’. 

The parent document then processes these messages and forwards them to GA4. 

Here’s how you can implement this:

In the iframe, you should send tracking events to the parent document using window.postMessage. Each event can include the same structure you’d use in a dataLayer push.

In the iframe:

function sendTrackingEventToParent(eventData) {
  window.parent.postMessage({
    event: 'tracking_event',
    data: eventData
  }, '*');
}

// Example: Sending a button click event
sendTrackingEventToParent({
  event: 'button_click',
  category: 'Button',
  action: 'Click',
  label: 'Subscribe Button'
});

This function sends an object with event data (event name, category, action, label, etc.) to the parent document.

In the parent document, listen for messages from the iframe. 

When a message is received, extract the event data and push it to the dataLayer. GA4 will pick up these events as if they occurred in the parent document.

In the Parent Document:

// Function to handle incoming messages from the iframe
function handleIframeMessage(event) {
  if (event.data && event.data.event === 'tracking_event') {
    const eventData = event.data.data;

    // Push the received event data to the dataLayer
    window.dataLayer = window.dataLayer || [];
    window.dataLayer.push(eventData);
  }
}

// Add an event listener to capture messages from the iframe
window.addEventListener('message', handleIframeMessage);

Ensure that the parent document has the GA4 configuration script set up, so it can process the events pushed to the dataLayer.

In the Parent Document:

<script async src="https://www.googletagmanager.com/gtag/js?id=GA_MEASUREMENT_ID"></script>
<script>
  window.dataLayer = window.dataLayer || [];
  function gtag(){dataLayer.push(arguments);}
  gtag('js', new Date());
  gtag('config', 'GA_MEASUREMENT_ID');
</script>

While all three solutions are valid and can be effective, handling all tracking in the parent document is often the best solution.

My best selling books on Digital Analytics and Conversion Optimization

Maths and Stats for Web Analytics and Conversion Optimization
This expert guide will teach you how to leverage the knowledge of maths and statistics in order to accurately interpret data and take actions, which can quickly improve the bottom-line of your online business.

Master the Essentials of Email Marketing Analytics
This book focuses solely on the ‘analytics’ that power your email marketing optimization program and will help you dramatically reduce your cost per acquisition and increase marketing ROI by tracking the performance of the various KPIs and metrics used for email marketing.

Attribution Modelling in Google Analytics and BeyondSECOND EDITION OUT NOW!
Attribution modelling is the process of determining the most effective marketing channels for investment. This book has been written to help you implement attribution modelling. It will teach you how to leverage the knowledge of attribution modelling in order to allocate marketing budget and understand buying behaviour.

Attribution Modelling in Google Ads and Facebook
This book has been written to help you implement attribution modelling in Google Ads (Google AdWords) and Facebook. It will teach you, how to leverage the knowledge of attribution modelling in order to understand the customer purchasing journey and determine the most effective marketing channels for investment.

About the Author

Himanshu Sharma

  • Founder, OptimizeSmart.com
  • Over 15 years of experience in digital analytics and marketing
  • Author of four best-selling books on digital analytics and conversion optimization
  • Nominated for Digital Analytics Association Awards for Excellence
  • Runs one of the most popular blogs in the world on digital analytics
  • Consultant to countless small and big businesses over the decade