SPA Support#

Single-page applications (SPAs) change routes without reloading the page. Pulsora detects these transitions automatically so you still get accurate pageview analytics.

Automatic History Tracking#

When autoPageviews is enabled (default), Pulsora:

  • Wraps history.pushState and history.replaceState
  • Listens to the popstate event for back/forward navigation
  • Emits a pageview whenever the URL changes

This covers vanilla SPAs, React Router, Vue Router, Next.js (client transitions), Remix, and more with zero additional code.

Forcing Manual Control#

If you prefer to manage pageviews yourself, disable auto tracking:

const pulsora = new Pulsora();
pulsora.init({
  apiToken: 'pub_123',
  autoPageviews: false,
});

Then trigger pageviews explicitly when your router changes routes:

import { useEffect } from 'react';
import { useLocation } from 'react-router-dom';

export function AnalyticsBridge({ pulsora }) {
  const location = useLocation();

  useEffect(() => {
    pulsora.pageview({
      url: window.location.href,
      title: document.title,
    });
  }, [location.pathname]);

  return null;
}

Using the React Hook#

If you install @pulsora/react, the usePageview hook handles this pattern for you:

import { usePageview } from '@pulsora/react';
import { useLocation } from 'react-router-dom';

function Analytics() {
  const location = useLocation();
  usePageview({ trigger: location.pathname });
  return null;
}

The hook defers to Pulsora’s automatic tracking when no trigger is provided, so you can use it selectively.

Custom Routers & Edge Cases#

For bespoke routing solutions:

  1. Disable auto pageviews.
  2. Emit a pageview whenever your app considers a route change complete.
  3. Include canonical URLs in the url property when hash-based routing is used.

Example for hash routers:

pulsora.pageview({
  url: `${location.origin}${location.pathname}#${location.hash}`,
});

Debugging SPA Tracking#

  • Enable debug: true to see [Pulsora] Pageview tracked logs.
  • Verify requests are hitting POST /api/ingest in the Network panel.
  • Ensure you call pulsora.pageview() after the DOM updates if you rely on the new page title.

Next, explore production-grade code snippets for different stacks: Core Examples →