• Courses
    • Courses
    • Course bundles
  • Blog
  • Resources
    • Youtube channel
    • E-books and Guides
    • GTM Recipes
    • View All Resources
    • GTM Community
    • GA4 community
  • Services
  • About
    • About
    • Contact
  • Login
  • Courses
    • Courses
    • Course bundles
  • Blog
  • Resources
    • Youtube channel
    • E-books and Guides
    • GTM Recipes
    • View All Resources
    • GTM Community
    • GA4 community
  • Services
  • About
    • About
    • Contact
  • Login

September 20, 2020

How to Track Virtual Pageviews when Multiple History Events Occur at the Same Time

Updated: September 20th, 2020

Note: In July 2023, Universal Analytics stops working. It is no longer recommended to do new implementations with Universal Analytics (GA3). Use Google Analytics 4 instead.

This is yet another post about Single Page Application tracking with Google Tag Manager. In my main blog post, I explored two options on how to track such websites. It’s either with the History Change trigger or with the developer’s input.

A more robust solution is to cooperate with a developer but, unfortunately, that is not always possible due to various reasons (e.g. developer’s busy schedule or maybe you’re working on a small project where the developer is not present at all).

Then your next option is a History Change trigger. But this has also some nuances. And in today’s article, we’ll take a look at one of them.

Google Tag Manager Ebook Bundle

Table of contents

  • Before We Continue
  • The Problem
  • Possible Solutions?
  • Check the History Change Source
  • Update the History Change Trigger
  • Passing the correct Page URL
  • Final test
  • Final words

 

Before we continue

This blog post will not dive into the intricacies of the Single Page Application tracking with GTM. I have another in-depth article about it. So if you’re totally new to this topic, I suggest you read that one first.

In today’s blog post, I’ll just tackle one problem and possible solutions for it.

 

The Problem

As you should already know, when a visitor browses SPA, the page does not actually reload. It just dynamically loads the content. So if you implement Google Analytics tracking the standard way, only the first pageview will be tracked.

A solution for that is called Virtual Pageviews. Every time a state/view of the SPA changes, a “fake pageview” hit is sent to Google Analytics.

If you’re managing your Google Analytics tracking tags via Google Tag Manager, you need to somehow figure out what is the “trigger” that sends those fake pageviews.

In my main blog post about the SPA tracking with GTM, there are two options: with the developer’s input (recommended) or History Change trigger.

Let’s say that the developer is not available and we have to go with the History Change trigger.

Once you have created it, refresh the preview mode, then refresh the page you’re currently working on. Then start navigating the page. Every time a page URL dynamically changes, you should see the History event in the preview mode. If you have followed my main SPA tracking guide, you have configured your GA Pageview tag to fire every time that History event occurs. So it’s natural that you expect that event to appear only once when the URL changes.

And that’s where we reach today’s problem (sorry for quite a long introduction to it). In some Single Page Applications, multiple History events happen at the same time (even though the URL just changed once).

 

Possible solutions?

One of the solutions could be to ditch the History Change trigger and cooperate with the developer. Ask him/her to push a custom event to the Data Layer every time a URL actually changes. Together with that event, he/she should also send the actual URL and the page title. You can read more about that here.

But you’re probably looking for some other option, right? Well, there is one. I’m not sure whether it will work on all SPAs but it sure did on many I’ve worked with (that had this problem of multiple history events).

So the solution that I propose in today’s blog post is narrowing down the History Change Source.

Subscribe and Get the Ebook - Mastering GA4 event tracking

Check the History Change Source

When you see those multiple History events in the GTM preview and debug mode, click the first one and go the Data Layer tab. Keep looking for the gtm.historyChangeSource. What is this value? Memorize it. In my case, it’s pushState.

Then click the next History event that happened almost at the same time. What is the value this time? In my case, it’s replaceState.

I’ve seen some apps that use 3 or 4 History events one every pageview. If that’s your case, check them all.

Your goal here is to answer this question: Is there one History event (of a “fake pageview”) that has a unique gtm.historyChangeSource value (compared to other History events that happened at the same time)?

For example, if you have 3 History Events happening at the same time, maybe only one of them uses pushState and all others are using the replaceState? (P.S. you can learn more about what each of these states means here).

In my case, I see two History events. One with the pushState and one with the replaceState. I’m still not sure which one to choose. So I keep navigating the Single Page App to see what is happening. P.S. If I saw 3 events (one of them was pushState, two – replaceState), then most likely, I’d have to go with the pushState.

But once again, since my case had only two History events at the same time, I’m not sure which state to pick.

The page that I was checking also had a slider where a visitor can answer a question by using a slider (from 1 to 10). Every time a slider was moved by 1 point, a new History event was pushed to the Data Layer.

After I checked them, ALL of them used the replaceState. Now, I definitely do NOT want to send a virtual pageview to GA every time someone moves a little slider. I want to fire a tag only when the page changes (e.g. I move to the next page, etc.).

So I’d say that replaceState is not a good option for me (because it fired too often). pushState, on the other hand, is (because it fires only once per page view when I actually navigate the SPA).

Just to make sure, you should continue navigating the Single Page Application to make sure that every time you move from one “page” to another, only one History event occurs in the Preview & Debug mode that uses the pushState. 

Remember: carefully inspect how YOUR single page application works. In my example, tracking only pushState History events is the way to go. In your case, things might be different and you might end up using a different state. So always play around and verify which History Change Source should be chosen.

Update the History Trigger

So if things went well for you and you managed to find the proper gtm.historyChangeSource value (that is pushed once to the Data Layer only when a visitor/user actually navigates from one “page” of the SPA to another), it’s time to add it to the History Change trigger’s settings.

Go to your Google Tag Manager container > Triggers and open the History Change trigger you’ve already created. Add the following condition: History Source equals pushState

This is case-sensitive.

If you don’t see the History Source variable in the list, click Choose built-in variable and then pick the History Source.

If your GA pageview tag already uses this trigger, let’s test whether the tag actually fires when it’s supposed to (just on pushState History events).

Refresh the Preview and Debug mode (by clicking the Orange Banner in the GTM interface) and then refresh the browser window with your SPA. Start navigating it and see what happens.

IMPORTANT: you will continue seeing multiple History events in the Preview and Debug mode. However, if you click them, you should notice that your GA Pageview tag is firing only on those where the History Source variable equals to pushState.

There are two places in the preview mode where you check the value of the History Source:

  • Variables tab of the Preview mode
  • Or Data Layer tab

 

Passing the correct Page URL

If the URL of your SPA contains the # and all the important stuff that can help you distinguish one URL from another is available after the # in the URL (e.g. example.com/#/pages/contact-us), you need to do some additional configuration (because by default, Google Analytics does not display URL parts that come after the hashmark (#).

Read this part of my SPA tracking guide to learn more. There are several options so you should pick the one that fits your needs the best.

 

Final test

Here’s what the final result should look like (a quick test plan).

 

Verify how many times does your GA Pageview tag fire on a single transition between SPA pages

Every time a visitor navigates from one page of your SPA to another, multiple History events may appear in the preview console, BUT only one of them should fire your GA pageview. If you see, say, 3 History events after clicking all of them, you will see that only on one event your GA Pageview tag has fired.

 

Check the Real-time reports

Go to the real-time reports of Google Analytics and check whether you are actually getting only one pageview when you navigate from page A to page B of your SPA.

 

Is URL with # also changing in GA real-time reports?

If your SPA URL contains # and something afterward, you should still see those URL changes in the GA Real-time reports. You can read more about it here.

 

Tracking SPA with GTM when Multiple History Events Occur: Final Words

Single Page Application tracking is always tricky and this can be proven by a whole bunch of various blog posts on the web. In today’s article, I tried to tackle a not-so-rare situation when multiple History events are visible in the GTM preview and debug mode even though a visitor has navigated just between two pages.

So instead of one History event, there were two, three, or maybe even more. One of the possible solutions is, of course, cooperation with a developer. If that is not an option, you could try checking the following thing.

Is there one History event (among all those unwanted duplicates) that is using a different History Source? If yes, then you could update your History Change trigger to fire the GA Pageview tag only on that certain History Change.

This, of course, requires some time to play around with the SPA and make sure that you have chosen the correct History Change Source. If unfortunately, you were not able to do that, then you should go back to your developers and use custom events to track virtual pageviews of your SPA.

Julius Fedorovicius
In Google Tag Manager Tips
14 COMMENTS
Stella Arambel
  • Jan 20 2021
  • Reply

Hi Julius,
I really enjoy your blogs and have been able to set up GTM tags for tracking easily because you are so thorough. I currently have Cross domain tracking placed on a destination site that serves as an application portal for financial products. In trying to setup a goal conversion in GA, the application I believe employs a SPA framework because the url doesn't change even after the user submits an application. In this instance, could I use the history trigger method you've outlined in your blog? The developer supports placing GTM script but not GA scripts (due to security). Thanks for your time

    Julius Fedorovicius
    • Jan 20 2021
    • Reply

    If History trigger works, you can use it.
    P.S. If your developer is concerned about security, then GTM is a much larger threat than GA.

Pablo
  • Apr 10 2021
  • Reply

Hey Julius,

Thanks for the great article! (:

Quick qs: Is this applicable to dynamic landing pages?

Thank you!
Pablo

    Julius
    • Apr 10 2021
    • Reply

    What is dynamic landing page?

Emil Hasanov
  • May 20 2021
  • Reply

Dear Julius,

I have 2 History Sources which both are pushState. Can You please advise how can I trigger it one time only?

API Call is as below:

event: "gtm.historyChange",
gtm.historyChangeSource: "pushState"

event: "gtm.historyChange-v2",
gtm.historyChangeSource: "pushState"

Thank You in advance.
Emil Hasanov

    Brad
    • Aug 5 2021
    • Reply

    Emil, it looks like you have 2 different types of history changes one is "gtm.historyChange" which is the one you can key off of and it will not see the other one "gtm.historyChange-v2" The second one is because you have GA4 installed and it is pushing this to the dataLayer. You are fine to simply set the history change trigger and it should only fire once.

Vincent
  • May 20 2021
  • Reply

Hi Julius,

Thank you for your help by describing the issue and providing a solution.

According to your explanations here, that means that you will not track popState history change source that occurs when user click on "back" or "next" button History of the browser.

I will recomend to create a regex rule matching "replaceState|popState" so navigation into History browser will be finally triggered as pageViewed

What do you think ?

    Vincent
    • May 20 2021
    • Reply

    My recommandation does not work cause regex is not applied to the value but to the variable name.

    Another alternative would be to create to conditions for the event but GTM forces us to user RULE 1 AND RULE 2 not RULE 1 OR RULE 2

    Do you have another solution to trigger popState ?

Vincent
  • May 20 2021
  • Reply

Emil Hasanov this is because you added on GA page viewed settings as "History Fragment", so GA triggers an other one.

I did the same.

    Emil Hasanov
    • May 20 2021
    • Reply

    Vincent, thank You for your response. I am using GA4, so I don't have view settings as "History Fragment".

    Would appreciate any assistance by all readers as well.

    Regards!

Vincent
  • May 20 2021
  • Reply

Well me too GA4.

Go to
> FLux
> Improved measures
> Page view
> Advanced settings
> uncheck History change

Ben
  • Aug 3 2021
  • Reply

Hi Julius,

I was able to successfully set up the history change event and trigger to fire the secondary pageview tag for GA. However after the history change event populates, GTM stops picking up events on the secondary "page". Essentially, after navigating away from the first "page" GTM stops populating events entirely. Any thoughts on what might be going on here?

Thanks,
Ben

Anshu
  • May 31 2022
  • Reply

Hi Julius,

Thanks a lot for providing the best tutorials. I currently working on unique events triggering in each page of 5 steps flow in SPA , followed the above steps , still getting 3 history data not one .API Call is as below:

event: "gtm.historyChange",
gtm.historyChangeSource: "pushState"

event: "gtm.historyChange-v2",
gtm.historyChangeSource: "pushState"

event: "page_view"
gtm.historyChangeSource: "pushState"

By using page view in implementation I have been triggered unique in 5 steps . Please let me know is this correct way or need to go as custom event to generate unique event in each page

jeff
  • Jul 21 2023
  • Reply

hi Julius - great article - i am stumped as we have an SPA site but i am seeing 2 History elements for each page load ("history change' & 'history').

we implemented the virtualPageview solution for tracking so maybe that is the issue - in debug i am seeing the page fire multiple times

Leave a comment Cancel reply

Your email address will not be published. Required fields are marked *


 

Hi, I'm Julius Fedorovicius and I'm here to help you learn Google Tag Manager and Google Analytics. Join thousands of other digital marketers and digital analysts in this exciting journey. Read more
Analytics Mania
  • Google Tag Manager Courses
  • Google Tag Manager Recipes
  • Google Tag Manager Resources
  • Google Tag Manager Community
  • Login to courses
Follow Analytics Mania
  • Subscribe to newsletter
Recent Posts
  • Setting up cookie consent for Microsoft Clarity (V2)
  • Conversion rate in Google Analytics 4
  • Google Tag Manager Data Layer Explained
Analytics Mania - Google Tag Manager and Google Analytics Blog | Privacy Policy
Manage Cookie Settings