Duplicate pageviews in SPAs
Single-page apps often send a pageview on initial load and another from a route-change listener, and on the very first view both can fire for the same URL. Strict-mode double renders, mounting effects that run twice, and duplicate listeners add more. The result is inflated pageviews concentrated on entry pages. This page explains duplicate SPA pageviews and how to fire exactly one per route.
Why the first view doubles
A common SPA setup sends a pageview from the analytics snippet on initial load and also subscribes to the router's navigation event to send a pageview on each route change. The framework frequently emits an initial route event for the landing URL, so both handlers fire for the same first page. Development double-invocation (React Strict Mode) and effects without guards can add yet another.
Because this concentrates on entry pages, landing-page metrics inflate the most.
- Initial-load pageview plus a route listener both fire
- Router emits an initial event for the landing URL
- Double renders/effects add further duplicates
Firing exactly once
Choose a single source of truth: either send only from the route listener (and suppress the snippet's automatic initial pageview) or send the initial one and skip the router's first event. Guard route-change handlers so they ignore the initial navigation, and make sure effects that fire pageviews are idempotent. Verify with one fresh session that an entry plus two clicks yields three pageviews, not five.
This overlaps with but is broader than the History-change trigger case, which is specific to GTM.
How it appears in analytics and logs
Two identical pageviews for an entry URL at session start usually mean the initial pageview and a route listener both fired, not two visits.
Diagnostic use case
Eliminate inflated single-page-app pageviews caused by initial-load and route-change handlers both firing for the same first view.
What WebmasterID can help detect
WebmasterID can derive route changes from one explicit signal, avoiding the overlapping triggers that inflate SPA entry pageviews.
Common mistakes
- Sending both an initial pageview and the router's first event.
- Firing pageviews from non-idempotent mount effects.
- Not verifying one-route-one-pageview in a clean session.
Privacy and accuracy notes
Deduplicating views uses URLs and timing, not identity. WebmasterID keeps privacy-safe language and stores no personal identifiers for this.
Related pages
- History-change double counting
Single-page apps signal navigation through the History API, and GTM's History Change trigger listens for it. Some routers call pushState and then emit their own navigation event, or fire popstate alongside a manual push, so the trigger fires more than once per route change. Each firing sends a virtual pageview, inflating counts. This page explains history-change double counting and how to make the trigger fire once.
- Single-page-app tracking gaps
In a single-page application, the browser loads once and the framework swaps views via the History API without a new document load. Analytics that depend on the load event therefore record only the first screen. This page explains the gaps — missing virtual pageviews, stale page paths, and broken referrer chains — and how SPA-aware tracking closes them.
- Double-counting pageviews
Double-counting happens when a single page load fires the analytics tag more than once. Two snippets on the page, a tag added in both the site and a tag manager, or an SPA that fires a virtual pageview on top of the full-load one all do it. The result inflates pageviews and drags engagement and bounce metrics. This page covers detection and the fixes.
- Events documentation
Send one explicit pageview per route change.
Sources and verification notes
Last reviewed 2026-06-24. Facts are checked against primary/official sources where available; uncertain specifics are marked “Data not yet verified” rather than guessed.