How to Track Pageviews on a Single Page App (SPA)
A 2026 guide to tracking pageviews on React, Vue, Astro, and other single-page applications. Why SPAs break analytics by default and how to fix it.
TL;DR
- 1.Single-page apps don't reload on internal navigation — your analytics tool only sees the initial load by default.
- 2.Result: typical SPA setup misses 80%+ of pageviews. Most teams don't notice until traffic looks suspiciously low.
- 3.Fix: hook into your router's navigation event and fire a pageview on each route change.
- 4.Sleek's tracker handles this automatically — listens for History API changes and fires pageviews on `pushState`/`replaceState`.
- 5.Verify in browser devtools Network tab — you should see one analytics request per route change.
Why SPAs break default analytics
Traditional websites reload a new HTML document on every navigation. The analytics tool fires once per page load — easy.
Single-page apps (React, Vue, Angular, Svelte, Astro with view transitions) don't reload. The browser stays on the same HTML document and JavaScript swaps the visible content. From the analytics tool's perspective, no new page loaded — so no new pageview gets tracked.
On a SPA, the user might navigate through 10 different "pages" but your analytics shows only 1 pageview.
How Sleek handles SPAs automatically
Sleek's tracker listens for History API events (pushState, replaceState, popstate) and fires a pageview on each. Most modern frameworks use the History API for client-side routing — React Router, Next.js, Vue Router, SvelteKit — so Sleek automatically tracks route changes without integration.
<script async src="https://getsleek.io/v1.js" data-site="YOUR_SITE_KEY"></script>Manual SPA tracking with other tools
'use client'
import { usePathname } from 'next/navigation'
import { useEffect } from 'react'
export function PageviewTracker() {
const pathname = usePathname()
useEffect(() => {
if (typeof window.sleek === 'function') {
window.sleek('pageview')
}
}, [pathname])
return null
}React Router pattern
import { useLocation } from 'react-router-dom'
import { useEffect } from 'react'
export function PageviewTracker() {
const location = useLocation()
useEffect(() => {
if (typeof window.sleek === 'function') {
window.sleek('pageview')
}
}, [location.pathname])
return null
}Vue Router pattern
import { createRouter } from 'vue-router'
const router = createRouter({ /* ... */ })
router.afterEach(() => {
if (typeof window.sleek === 'function') {
window.sleek('pageview')
}
})Generic History API hook
This is essentially what Sleek's tracker does internally. If you're using Sleek, you don't need this.
;(function() {
const fire = () => {
if (typeof window.sleek === 'function') {
window.sleek('pageview')
}
}
const origPushState = history.pushState
history.pushState = function(...args) {
origPushState.apply(this, args)
fire()
}
const origReplaceState = history.replaceState
history.replaceState = function(...args) {
origReplaceState.apply(this, args)
fire()
}
window.addEventListener('popstate', fire)
})()Verifying it works
- Open your site in a browser, open developer tools, and switch to the Network tab.
- Filter the requests to just analytics calls (filter by "collect" for Sleek).
- Click through 3–4 internal routes.
- You should see ONE analytics request fire per route change. If you only see one request total (initial load), your SPA tracking isn't working.
Common SPA tracking mistakes
- Forgetting it entirely. Default GA4 / Plausible installs don't track SPA routes.
- Hooking into the wrong event. `useEffect` without a dependency array fires on every render, not just route changes.
- Tracking before the route renders. The URL might still be the old one.
- Not handling popstate. Browser back/forward buttons trigger popstate, not pushState.
- Double-counting. If your tool already detects SPAs, manually firing adds duplicates.
Frequently asked questions
Why doesn't my analytics track SPA route changes by default?
Single-page apps don't reload on internal navigation — they swap content via JavaScript. Most analytics tools fire on page load, not on JavaScript-driven navigation. You need a tool that auto-detects SPAs (like Sleek) or manually fire pageviews on route change.
Does Sleek work with Next.js out of the box?
Yes. Sleek's tracker listens for History API events, which Next.js uses for client-side routing. Just install the snippet in your root layout.
How do I verify SPA pageview tracking is working?
Open browser devtools Network tab, filter for your analytics endpoint, and click through 3–4 routes. You should see one analytics request per route change.
Should I track SPA route changes with GA4?
Yes — GA4's Enhanced Measurement includes "page changes from browser history events" which catches some SPAs. But it doesn't cover all routing approaches. Verify it's working, fall back to manual firing if not.
Does Astro need special pageview tracking?
Default Astro (multi-page mode) reloads on navigation, so pageview tracking works without configuration. Astro with View Transitions (since 4.0) is SPA-like and needs the same SPA pageview pattern as React.
Can I track SPA pageviews server-side?
For SPAs, no — the server doesn't see internal navigation. Each route change happens client-side only. You must fire pageviews from the browser.
Track your own growth loop
Sleek Analytics gives you visitors, sources, pages, devices, and real-time behavior with one lightweight script. No cookies, no GDPR banners.
Related reading
Next.js Analytics: Tracking Pageviews, Events, Web Vitals
Install analytics on a Next.js App Router app in 2026: next/script in app/layout.tsx, client component event tracking, web vitals via reportWebVitals, and the SPA pageview pitfall.
GuidesHow to Verify Your Analytics Is Actually Working (Step-by-Step)
A practical guide to verifying your web analytics is collecting data correctly. Browser devtools, real-time view, test events, cross-browser checks, and common gotchas.
How-toHow to Track Custom Events with a Privacy-First Tool
A 2026 guide to tracking custom events in privacy-friendly analytics tools. When to use them, naming conventions, and what to track for SaaS, ecommerce, and content sites.
ComparisonsSleek vs Google Analytics (2026): Which Is Better for Modern Teams?
Sleek Analytics vs Google Analytics in 2026: side-by-side on setup speed, dashboard clarity, privacy, pricing, and migration. Honest take on when each tool wins.