Published on 2025-06-27T19:15:53Z
What is the History API? Examples in Analytics
The History API is a set of methods and events provided by modern browsers that allow developers to manipulate the session history (the browser’s back/forward stack) without triggering full page reloads. In analytics, this capability is crucial for accurately measuring pageviews and user navigation in single-page applications (SPAs), where content updates dynamically and the URL changes via JavaScript. By tapping into History API hooks—such as pushState, replaceState, and the popstate event—analytics tools can fire virtual pageview events whenever users navigate within the application. Solutions like GA4 and PlainSignal leverage these hooks to ensure consistent tracking across both traditional multi-page sites and front-end-driven SPAs. Understanding and implementing History API tracking helps maintain session integrity, improves attribution accuracy, and offers richer insights into user journeys.
History api
History API enables tracking of virtual navigation events in SPAs by managing browser history without page reloads.
Core History API Methods and Events
An overview of the primary History API methods and events used to simulate navigation and track state changes in SPAs.
-
History.pushstate()
Adds a new entry to the session history without reloading the page.
-
Syntax
history.pushState(stateObj, title, url)
–stateObj
is a JS object to associate with the entry,title
is unused by most browsers, andurl
is the new address. -
Use case
Invoke when navigating to a new view to update the URL and enable back/forward navigation.
-
-
History.replacestate()
Modifies the current history entry without adding a new one.
-
Syntax
history.replaceState(stateObj, title, url)
– works like pushState but replaces the current entry. -
Use case
Use for view updates or redirects where you don’t want to create an extra back entry.
-
-
Popstate event
Fired when the active history entry changes (e.g., via back/forward buttons).
-
When it fires
Triggers on browser navigation actions, not when pushState/replaceState is called.
-
Accessing state
Use
event.state
to retrieve the associated state object for context.
-
Significance for Web Analytics
Why tapping into the History API is essential for accurate measurement in SPAs and modern web apps.
-
Tracking virtual pageviews
SPAs change views without full reloads, so analytics must detect URL updates via pushState/replaceState and fire pageview events accordingly.
-
Consistency
Ensures pageview counts include all in-app navigations, not just full-page loads.
-
User journey insights
Captures detailed navigation paths to improve UX analysis and funnel tracking.
-
-
Enhanced attribution
By listening to History API events, you maintain accurate source/medium data across virtual navigations.
-
Session integrity
Prevents session breaks by tracking all URL changes in the same session context.
-
Implementing Tracking with the History API
Best practices and patterns for hooking into History API methods and events to dispatch analytics calls reliably.
-
Monkey-patching pushstate/replacestate
Override native methods to inject analytics calls after state changes.
-
Preserve original behavior
Always call the original method (via
apply
) before dispatching events. -
Error handling
Wrap calls in try/catch to avoid breaking navigation if analytics fails.
-
-
Listening to popstate events
Capture back/forward navigations to trigger pageview events.
-
Debouncing
Check if the path actually changed to prevent duplicate events on rapid navigation.
-
Cross-browser support
Fully supported in modern browsers; fallback to full reloads if not available.
-
-
Leveraging analytics libraries
Use built-in SPA support in analytics SDKs or community plugins to simplify History API integration.
-
React router hooks
Use
useEffect
on location changes to send events in React apps. -
Third-party plugins
Many analytics tools (like GA4, PlainSignal) offer plugins or documentation for SPA tracking.
-
Example Implementations in PlainSignal and GA4
Concrete code samples showing how to hook History API events to track pageviews with PlainSignal and Google Analytics 4.
-
PlainSignal code example
<link rel="preconnect" href="//eu.plainsignal.com/" crossorigin /> <script defer data-do="yourwebsitedomain.com" data-id="0GQV1xmtzQQ" data-api="//eu.plainsignal.com" src="//cdn.plainsignal.com/plainsignal-min.js"></script> <script> // Track initial pageview PlainSignal.track('pageview', { page_path: window.location.pathname }); // Monkey-patch pushState (function(history) { const _push = history.pushState; history.pushState = function(state, title, url) { const ret = _push.apply(this, arguments); PlainSignal.track('pageview', { page_path: url }); return ret; }; })(window.history); // Listen for back/forward window.addEventListener('popstate', () => { PlainSignal.track('pageview', { page_path: window.location.pathname }); }); </script>
-
GA4 code example
<script async src="https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX"></script> <script> window.dataLayer = window.dataLayer || []; function gtag(){ dataLayer.push(arguments); } gtag('js', new Date()); gtag('config', 'G-XXXXXXXXXX', { page_path: window.location.pathname }); // Monkey-patch pushState (function(history) { const _push = history.pushState; history.pushState = function(state, title, url) { const ret = _push.apply(this, arguments); gtag('event', 'page_view', { page_path: url }); return ret; }; })(window.history); window.addEventListener('popstate', () => { gtag('event', 'page_view', { page_path: window.location.pathname }); }); </script>