Launch Offer2 free audits with all 229 checks. No credit card required.Start free audit

GA4 SPA Tracking: React, Vue, Next.js, and Angular Without the Pageview Bugs (2026)

Intermediate

Why SPAs break standard GA4 tracking

In a traditional multi-page website, every page navigation triggers a full page load. GA4's enhanced measurement fires a page_view event on each load automatically. In a single-page application (React, Vue, Next.js, Angular), navigating between routes does NOT reload the page — JavaScript updates the DOM and the URL without triggering a full page load. Result: GA4 fires one `page_view` event on the initial load, then nothing. Users who navigate through 10 SPA routes appear in GA4 as a 1-page session.

Engagement rate is artificially low (many sessions appear as <10 seconds because only one page_view fires). All multi-page conversion funnels break.

Approach 1 — GA4 Enhanced Measurement History Change (easiest, least reliable)

GA4's enhanced measurement includes a History Changes option that fires page_view when the browser's History API changes (pushState/replaceState).

Enable: Admin → Data Streams → Web → Enhanced Measurement → History changes (enabled by default)

When this works: React Router, Vue Router, Angular Router — all use the History API for navigation. History Change enhanced measurement should fire page_view on each route change.

When this breaks:

  1. Hash-based routing — if your SPA uses #/path routing (hash fragments), the History API isn't used and the History Change trigger doesn't fire
  2. Modals that update the URL — if opening a modal changes the URL (e.g., /products#modal-123), GA4 fires a spurious page_view for the modal
  3. React Router with multiple history updates per navigation — some implementations trigger multiple History API calls per route change, causing double-firing of page_view

Check for double-firing: Open GA4 DebugView and navigate between pages. If each navigation produces 2 page_view events, double-firing is occurring.

Approach 2 — GTM History Change Trigger (reliable for most SPAs)

GTM has a built-in trigger type for SPA route changes: History Change.

GTM configuration:

  1. Triggers → + New → Trigger Type → History Change
  2. This trigger fires: when browser history changes (same as GA4 enhanced measurement History Change, but manageable in GTM)
  3. Create a GA4 Event tag triggered by History Change → Event Name: page_view → parameters: page_location = {{Page URL}}, page_title = {{Page Title}}
  4. Set firing priority higher than other page_view tags to prevent race conditions

Disable enhanced measurement History Changes if using GTM History Change trigger — having both active causes double page_view events.

Want to see which hidden implementation gaps are affecting your GA4 data quality?

React Router consideration: React Router v6+ uses the History API correctly and GTM's History Change trigger fires reliably. No additional configuration needed for standard React Router setups.

Known issue — Next.js App Router:

Next.js 13+ App Router uses React Server Components and a custom router that doesn't always fire standard History API events. The GTM History Change trigger may miss some navigations. See framework-specific section below.

Approach 3 — Manual virtual pageview push (most reliable)

For full control, push page_view events to the dataLayer manually from within your SPA's router/navigation logic.

React Router v6

In GTM: Create a Custom Event trigger for page_view. Create a GA4 Event tag: event name page_view, parameters from the dataLayer variables. Disable enhanced measurement page_view to prevent double-firing.

Next.js 13+ App Router

Note: The Suspense wrapper is required for useSearchParams() in Next.js 13+ — without it, the build fails.

Vue Router

Angular

The page title timing problem

All SPA tracking approaches face the same issue: when the route changes, the new page's <title> may not yet be set when the page_view event fires (especially in React/Next.js where title updates are asynchronous).

Fix — small setTimeout for title capture:

FAQ: GA4 SPA Tracking: React, Vue, Next.js, and Angular Without the Pageview Bugs

What should a team validate first when ga4 spa tracking: react, vue, next.js, and angular without the pageview bugs appears?

Reproduce the problem in the live implementation, isolate whether it is scoped to one report or flow, and compare it against at least one secondary source before changing the setup.

How do I know whether the fix actually worked?

You need before-and-after evidence in the browser and in the downstream report. A clean-looking dashboard without validation is not enough.

When should this become a full GA4 audit instead of a quick fix?

If the issue touches attribution, consent, revenue, campaign quality, or data trust for more than one workflow, it is usually safer to audit the surrounding implementation than patch only the visible symptom.

Run a GA4 audit before ga4 spa tracking: react, vue, next.js, and angular without the pageview bugs spreads into reporting decisions

Use GA4 Audits to surface implementation gaps, broken signals, and the next fixes to prioritize before the issue becomes harder to trust or explain.

These findings come from auditing thousands of GA4 properties. See how your property compares

GA4 Audits Team

GA4 Audits Team

Analytics Engineering

Specialising in GA4 architecture, consent mode implementation, and multi-layer audit frameworks.

Share