Integration guidesReact Router
React Router
Add Supapulse to a React Router single-page app, with automatic pageviews, events and checkout attribution.
Install
npm install @supapulse/core @supapulse/reactWrap the app
import { SupapulseProvider } from '@supapulse/react';
import { createRoot } from 'react-dom/client';
import { RouterProvider, createBrowserRouter } from 'react-router-dom';
import { routes } from './routes';
const router = createBrowserRouter(routes);
const config = { apiToken: import.meta.env.VITE_SUPAPULSE_TOKEN };
createRoot(document.getElementById('root')!).render(
<SupapulseProvider config={config}>
<RouterProvider router={router} />
</SupapulseProvider>,
);Keep the provider above the router so it isn't remounted.
Pageviews
React Router navigates with history.pushState, which the tracker follows. Every route change is a pageview without extra code.
To control pageviews yourself, for example to send a cleaned URL, turn them off and use the hook inside the router:
const config = { apiToken: import.meta.env.VITE_SUPAPULSE_TOKEN, autoPageviews: false };
function RouteTracker() {
const location = useLocation();
usePageview({ trigger: location.pathname });
return null;
}Render <RouteTracker /> in your root layout route.
Events
import { useEvent } from '@supapulse/react';
export function PricingPage() {
const trackEvent = useEvent();
return <button onClick={() => trackEvent('plan_selected', { plan: 'growth' })}>Choose Growth</button>;
}Checkout
import { useSupapulse } from '@supapulse/react';
export function BuyButton({ priceId }: { priceId: string }) {
const supapulse = useSupapulse();
async function buy() {
const response = await fetch('/api/checkout', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
priceId,
fingerprint: await supapulse.getVisitorFingerprint(),
sessionId: supapulse.getSessionId(),
}),
});
window.location.href = (await response.json()).url;
}
return <button onClick={buy}>Buy</button>;
}Your backend stores the fingerprint and session ID in the payment's metadata, next to your user ID. With Stripe, Supapulse reads them from its own webhook. See the Stripe guide; other processors are in Payment webhooks.
Troubleshooting
- Two pageviews per navigation. Some setups call
replaceStateright afterpushState(for example, scroll restoration or search-param syncing). UseautoPageviews: falsewith the hook above. - Hash routers. With
createHashRouterthe route lives after#, and Supapulse records the URL's path, so every page shows up as/. UseautoPageviews: falseand send the route as the URL yourself:supapulse.pageview({ url: location.origin + location.pathname })with React Router'slocation.