Track Single Page Applications with GTM and GA4

Updated: Monday, June 3, 2024

What is a Single Page Application (SPA)?

A Single Page Application is a type of website that loads all the code required for navigation from the very first page. As the name suggests, it’s an application that consists of a single page.

SPAs are often created using the framework Javascript Angular, React and Vue.js.

Google Analytics 4 offers a default feature for tracking SPAs, but this may not work in your case. That’s why we’re going to look at 3 different methods in this article.

What is the History API in JavaScript?

Without going into the technical details, the idea here is to provide a clear understanding of how SPAs work.

The history object is a JavaScript global variable used by most SPAs to manipulate browsing history.

JavaScript global variable history
JavaScript global variable history

If you’re working on an older SPA, it may not be using the JavaScript History API, in this case you’ll need to install Google Analytics 4 via method 3.

3 methods to track SPAs with GTM and GA4

Method 1: Keep GA4 with default settings

Now let’s see what happens if I set the Google Tag for a new GA4 property on all pages.

Now, I receive History events (gtm.historyChange-v2) and History Change events (page_view).

The gtm.historyChange-v2 event is triggered as many times as the gtm.historyChange event because they listen to the same events (those from the History API).

However, gtm.historyChange-v2 is managed by GA4, whereas gtm.historyChange is managed by GTM.

This is why gtm.historyChange-v2 triggers a page_view event (named History Change in GTM).

This page_view event tracks all pages viewed using the history API.

This feature is enabled by default in GA4 enhanced measurement, and can be disabled when necessary. If you wish to transmit more information in the page_view event, you will need to use methods 2 or 3.

Default page_view event handling on a GA4 property
Default page_view event handling on a GA4 property

Method 2: Track page views with History Change trigger in GTM

To use this method, I disable page_view tracking when changing the browsing history in GA4 enhanced measurement settings.

Disabling page_view event from history changes
Disabling page_view event from history changes

Now, I only get the gtm.historyChange event, as the gtm.historyChange-v2 event is no longer in the Data Layer.

I’m now going to update all my GA4 events to override the page_location and page_referrer parameters using the variables sent by the history change trigger.

To do this, I’ll create a Google tag: Event settings variable and fill in these 2 parameters.

Use the Google tag: Event settings variable to fill in the page_location and page_referrer parameters.
Use the Google tag: Event settings variable to fill in the page_location and page_referrer parameters.

From now on, I have two options:

  1. use the Shared event settings of the Google tag. This applies the settings to all GA4 events on condition that for all GA4 events, the Google tag is triggered first.
Adding the parameters page_location and page_referrer to the shared events parameters of the Google tag.
Added the parameters page_location and page_referrer to the shared events parameters of the Google tag.
  1. add the parameters to all GA4 events (this ensures that all events will have the parameters)

In the page_view event


page_location and page_referrer parameters added to page_view event parameters
page_location and page_referrer parameters added to page_view event parameters

In all other GA4 events

Add page_location and page_referrer to GA4 event parameters
Add page_location and page_referrer to GA4 event parameters

Method 3: Track page views via Data Layer


To use this method, I disable page tracking when changing the browsing history in GA4’s enhanced metrics settings.

Deactivate page views linked to browsing history
Deactivate page views linked to browsing history

Method 3 consists in asking a developer to send a page_view event in the Data Layer when the user changes the view in the SPA.

Your developer probably doesn’t know anything about how Google Tag Manager and Google Analytics 4 work, so you will need to create a detailed data layer documentation explaning what you need to be implemented on the SPA.

dataLayer.push(
    {
        event: "page_view",
        virtual_page_title: "Tour of Heroes - Dashboard",
        virtual_page_location: "/dashboard",
        virtual_page_referrer: "/heroes"
    }
);

Once the Data Layer has been set up by the developer, I’ll update all my GA4 events to override the page_title, page_location and page_referrer parameters using the variables sent by the history change trigger.


To do this, I’ll create a Google tag event variable (Google tag: Event settings) and fill in these 3 parameters.

Use the Google tag: Event settings variable to fill in the page_title, page_location and page_referrer parameters.
Use the Google tag: Event settings variable to fill in the page_title, page_location and page_referrer parameters.

From now on, I have two options:

  1. use the Shared event settings of the Google tag. This applies the settings to all GA4 events on condition that for all GA4 events, the Google tag is triggered first.
Added page_title, page_location and page_referrer parameters to the Google tag shared events parameters.
Added page_title, page_location and page_referrer parameters to the Google tag shared events parameters.
  1. add the parameters to all GA4 events (this ensures that all events will have the parameters)

In the page_view event


page_title, page_location and page_referrer parameters added to page_view event parameters.
page_title, page_location and page_referrer parameters added to page_view event parameters.

In all other GA4 events

page_title, page_location and page_referrer parameters added to GA4 event parameters.
page_title, page_location and page_referrer parameters added to GA4 event parameters.