SPA support
How @supapulse/core tracks route changes in single-page apps through the History API, and how to take manual control.
Automatic history tracking
With autoPageviews: true (the default), init():
- sends a pageview for the current page;
- wraps
history.pushStateandhistory.replaceState, sending a pageview after each call; - listens to
popstate, sending a pageview on back and forward.
Each pageview is sent on the next tick (setTimeout(…, 0)), so location.href and document.title reflect the new route by then, as long as your router updates the title synchronously.
React Router, Next.js, Remix, Vue Router, SvelteKit and Angular's router all navigate with pushState, so they work without extra code.
Things to know
replaceStatecounts as a pageview. Some routers call it to rewrite the URL on load or to sync query parameters. That shows up as an extra pageview.- Hash-only navigation isn't tracked. Changing
location.hashfireshashchange, notpopstateorpushState. Track it yourself (see below). - Titles set after a delay are missed. If your app sets
document.titleafter data loads, pass the title yourself with manual tracking.
Manual control
Turn off automatic pageviews and send them from your router:
supapulse.init({ apiToken: 'pub_your_token', autoPageviews: false });
router.afterEach((to) => {
supapulse.pageview({ url: location.origin + to.fullPath });
});Hash routing: Supapulse stores the URL's path, which is / for every #/route URL. Send the route as the path instead:
supapulse.init({ apiToken: 'pub_your_token', autoPageviews: false });
const trackRoute = () =>
supapulse.pageview({ url: location.origin + (location.hash.slice(1) || '/') });
trackRoute();
addEventListener('hashchange', trackRoute);Don't mix the two: calling pageview() with autoPageviews: true counts each route twice.
With @supapulse/react
<SupapulseProvider> uses the core tracker, so route changes are tracked the same way. Use the usePageview hook only when you've set autoPageviews: false.
Debugging
Set debug: true and navigate. Each route change should log one [Supapulse] Event sent line with type: 'pageview'. Two lines per navigation means the router calls both pushState and replaceState, or you're also calling pageview() yourself.