Understanding GTM Pageview vs History State Triggers

Websites handle navigation with one of two technologies: server transitions or client transitions. This article will explain the two types, how to configure GTM to account for them, and how to determine which type a given website uses.

Server transitions

In a server transitioned website, every time a user wants to navigate within the site, their browser requests an entirely new page from the server and renders it. Let’s suppose that each page on your site weighs 400kb. That means that the JS, CSS, HTML, and images used on each page sum up to a 400kb network payload. Each time the user clicks on a link within your site, they must load 400kb.

Some portion of that 400kb is the same on each page. For a very simplified example, you can imagine the duplicate code as the header and footer of your site — it’s the same header and footer on each page, but each page has to have a copy of those elements. Let’s suppose that half (200kb) is duplicate code. (Browsers also implement caching, but we’ll ignore that for simplicity.)

In the above example, every time the user loads a new page, it takes twice as long to fetch it because we have to load a bunch of redundant code.

What if we didn’t have to load all that duplicate code? What if we could load only the stuff we cared about?

Client transitions

Enter client-side transitions. With client-side transitions, the first page navigation loads the entire 400kb. Afterwards, subsequent navigations ask the server for just the necessary parts of the new page. Instead of “loading” an entirely new page, the existing page swaps in the new parts.

Configuring GTM for client transitions

The default All Pages trigger in GTM listens to the load event. Since client transitions don’t fire load, All Pages will only trigger on the first navigation when a user lands on the site. (Remember, the first load in a client transitioned site is a traditional full load, since the browser doesn’t already have parts of the page.) Depending on how many pages your users tend to visit, an All Pages trigger could result in only 10% of your traffic showing up in your analytics.

To solve this problem, simply add a History Change trigger alongside your All Pages triggers, such that the tag fires on both triggers. History Change monitors for client-side transitions that cause a URL change.

Detecting client transitions

If you know your tech stack, you can get a good idea of whether your site uses client transitions. Client transitions are a modern web technology and sites built with older server-rendered stacks such as WordPress, PHP, or .NET generally won’t have client transitions.

Sites built with newer tech might make use of client transitions. If your site is made with React, NextJS, Vue, Sveltekit, or Angular, it almost certainly uses client transitions. If your site is a “progressive web app” or a “single page app”, it probably uses client transitions. Statically generated sites may or may not use client transitions depending on the specific implementation.

The above is only a guideline; any site can use client or server transitions regardless of the stack. However, if you notice that your analytics look weird and you’re using a modern tech stack, there’s a good chance that client transitions are the culprit.

How to analyze a website

Generally speaking, your engineering team should know whether your site uses client-side transitions. However, if you don’t have access to the site engineers, here’s some methods to find out what method a site uses. Later methods require more engineering knowledge, but are also more reliable.

  1. The flicker trick
  2. Payload inspection
  3. Window modification

Method 1: The flicker trick

If you just want a quick rule-of-thumb, the flicker trick has you covered.

Go to your website and scroll all the way to the top. Rapidly click different buttons in the nav menu and watch to see if the nav menu has a brief flicker as it rerenders. Make sure that the buttons you’re clicking link to different pages. For example, https://example.com and https://example.com#test are the same page. Try to find two nav buttons that go to urls such as https://example.com and https://example.com/another.

If you see a flicker, your site is probably built with client-side transitions.

If you don’t see the flicker, it is not safe to assume that your site uses server transitions. Your site may simply load fast enough to avoid the flash.

Method 2: Payload inspection

This method requires us to use the devtools panel in Chrome. Devtools is a debugging app built into Chrome that lets you analyze and modify the website running in your browser. (It’s local-only, so if you modify the site, your changes won’t show up for other users.)

In a nutshell, we’re going to check whether a page loads extra data on its first load compared to navigating to it from another page.

Step 1: Preparation

Open your website’s homepage in Chrome and press CTRL+SHIFT+I to open the devtools. You should see a side panel appear. Click the double arrow at the top and choose Network to open the network debugger.

Step 2: Getting a baseline

Click the slashed-circle cancel icon to erase the network log. Make sure Preserve log and Disable cache are checked. Then, press CTRL+SHIFT+R to hard reload the site. Wait for the site to finish loading.

At the bottom of the Network tab, you should see a label such as XX.X MB transferred. This is the total weight of your page. Make a note of it.


Step 3: Checking in-site navigation

Go to another page in your site. In the Network tab, click the cancel icon to reset the log, and then navigate to the homepage. You must navigate to the homepage with a single click. Do not type the url into your browser and do not navigate to any other pages first. If you don’t follow these instructions exactly, the analysis will be thrown off.

Once the homepage finishes loading, check the page weight. Compare it to the baseline. If they’re very different, chances are you’re on a client transitioned website. If they’re very similar or identical, you’re probably on a server transitioned site.

Method 3: Window modification

This method works by modifying a global object (the “window”) with injected JS, navigating, and then checking to see if our modification still exists. In a server transition, there will be a new window object generated and the modification will be erased.

Step 1: Preparation

Go to your website’s homepage in Chrome and open devtools (CTRL+SHIFT+I). Devtools is a debugging app built into Chrome that lets you analyze and modify the website running in your browser. (It’s local-only, so if you modify the site, your changes won’t show up for other users.)

Click the double-arrow icon near the top of the devtools panel and select Console. You may notice various errors, or perhaps a warning that you’re being scammed or hacked. Ignore these. (You’ll see in the next section that the code we’re pasting in is very simple and not a security risk.)



Step 2: Injecting JS

In the Console tab, scroll down to the bottom. Click the empty space next to the > symbole and type in the following, without quotes: “window.clientSideTransitionTest = true”. Press ENTER to inject the code.

Step 3: Navigating away

Navigate to another page by clicking on a link. You must navigate with a single click. Do not navigate by typing a url into your browser. Do not navigate to multiple pages. Do not navigate to a page not on your site. If you don’t follow these directions exactly, the experiment will be invalidated.

Step 4: Checking for our modification

In the Console tab, type in the following, without quotes: “console.log(window.clientSideTransitionTest)”. Press ENTER to inject the code. You should get two lines of output back. If either line is “true”, then your website uses client transitions. If neither line is “true”, then your website uses server transitions.