Track Single Page Applications with GTM and GA4
Updated: Friday, July 26, 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.

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.

page_view
event handling on a GA4 propertyMethod 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.

page_view
event from history changesNow, 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.

page_location
and page_referrer
parameters.From now on, I have two options:
- 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.

page_location
and page_referrer
to the shared events parameters of the Google tag.- 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 parametersIn all other GA4 events

page_location
and page_referrer
to GA4 event parametersMethod 3: Track page views via Data Layer
page_view
event whenever you like and with the parameters of your choice.To use this method, I disable page tracking when changing the browsing history in GA4’s enhanced metrics settings.

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: document.title,
virtual_page_location: document.location.protocol + '//' +
document.location.hostname +
document.location.pathname +
document.location.search,
virtual_page_referrer: document.referrer
}
);
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.
page_title
parameter, as we have more flexibility when using method 3. This will allow us to have different page titles in GA4.To do this, I’ll create a Google tag event variable (Google tag: Event settings) and fill in these 3 parameters.

page_title
, page_location
and page_referrer
parameters.From now on, I have two options:
- 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.

page_title
, page_location
and page_referrer
parameters to the Google tag shared events parameters.- 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.In all other GA4 events

page_title
, page_location
and page_referrer
parameters added to GA4 event parameters.page_view
events so that Data Layer variables are up to date at the time of the event.