How to Track Analytics in a React or Vue Single Page App

How to Track Analytics in a React or Vue Single Page App

Single Page Applications (SPAs) built with React, Vue, Next.js, or Nuxt behave fundamentally differently from traditional multi-page websites. Instead of loading a new HTML page for each navigation, the app updates the DOM in place while the URL changes via the History API. This creates a problem for most analytics scripts: they only fire on the initial page load, so subsequent navigation within the app goes untracked.

Why Standard Analytics Scripts Fail in SPAs

A conventional analytics script works by executing when the HTML page loads, reading the current URL, and sending a pageview event. In a multi-page site, every click to a new page causes a full page load — triggering the script each time. In a SPA, the user can navigate through dozens of "pages" without ever triggering a full page load after the first one.

The result: if you install a standard analytics script in a React app, you'll see one pageview per session (the initial load) regardless of how many routes the user visits. Your analytics data will be nearly useless.

The History API Problem

SPAs use the browser's History API — specifically history.pushState() and history.replaceState() — to change the URL without triggering a page reload. Some also use hash-based routing (/#/route). An analytics tool that doesn't listen for these events will miss all in-app navigation entirely.

How SPA-Aware Analytics Tracking Works

Proper SPA analytics tracking works by intercepting History API calls. The script patches the native history.pushState and history.replaceState functions and adds an event listener for the popstate event (triggered by the back/forward buttons). Whenever any of these fire, the script reads the new URL and sends a pageview event.

Some analytics tools also listen for the hashchange event to support hash-based routing used by older frameworks like Vue Router in hash mode.

The Minimal Implementation

If you're building your own tracking solution or need to manually instrument a script that doesn't natively support SPAs, here's the core pattern in vanilla JavaScript:

// Patch pushState to detect SPA navigation const _origPush = history.pushState.bind(history); history.pushState = function(...args) { _origPush(...args); sendPageview(location.href); }; // Also listen for back/forward navigation window.addEventListener('popstate', () => { sendPageview(location.href); }); function sendPageview(url) { // Send the current URL to your analytics endpoint fetch('/collect?url=' + encodeURIComponent(url)); }

Framework-Specific Considerations

React and Next.js

In React Router, route changes fire pushState, so the History API interception approach works well. In Next.js, you can also use the router.events API to listen for routeChangeComplete events and manually trigger pageview calls if your analytics script doesn't auto-detect them.

Vue and Nuxt

Vue Router also uses pushState, so History API interception works. In Nuxt.js, similar router event hooks are available. If you're using a SPA-aware analytics tool, you typically won't need to configure anything — it handles this automatically.

Using an Analytics Tool That Handles SPAs Automatically

The simplest approach is to use an analytics tool that already intercepts History API events automatically. You paste the snippet once — usually in your root HTML template or in a global component — and it tracks every route change without any framework-specific configuration.

statpx's tracking script automatically patches history.pushState and listens for popstate events, giving you accurate per-route pageview tracking in React, Vue, Next.js, Nuxt, and any other SPA framework out of the box.

SPA analytics that just works — free

statpx automatically tracks navigation in React, Vue, Next.js, and any SPA. Paste the snippet once in your index.html and you're done. No configuration needed.

Try it free →

Verifying Your SPA Tracking Is Working

After installing your analytics script, open your site in a browser and navigate between several routes. Then check your analytics dashboard's real-time view. You should see a new pageview recorded for each route you visited, not just the initial page load. If you only see one pageview per session, your tracking script doesn't support SPA navigation and you'll need to switch to one that does or add the manual instrumentation above.

Also check that your top pages report shows multiple routes — not just your root URL dominating all traffic. If every visit appears to land on /, that's a clear sign SPA navigation isn't being tracked.

The Bottom Line

Single Page Applications break the most basic assumption analytics tools make — that every pageview begins with a full page load. Getting accurate SPA data requires a tracker that actively intercepts History API events rather than waiting for them to happen naturally. If you're building in React, Vue, or Next.js, the fastest path to reliable route-level analytics is dropping in a script that handles pushState and popstate automatically without any framework-specific wiring. statpx's tracking snippet does exactly this, so your Top Pages report reflects real user navigation from the moment you install it.

Continue reading

Technical
How to Identify and Block Referrer Spam in Website Analytics
Technical
How to Filter Your Own Visits Out of Website Analytics
Technical
Custom Dimensions in Analytics: Track Extra Context Beyond Pageviews
Analytics by statpx