> ## Documentation Index
> Fetch the complete documentation index at: https://doc.trackrev.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Track a single-page app

> Record pageviews on client-side route changes in React, Vue, or any SPA.

The pixel fires one pageview when the document loads. In a single-page app, navigations don't
reload the document — so you fire a pageview yourself on each route change. Everything else (the
`vid`, `identify`, revenue attribution) works unchanged.

## 1. Load the pixel once

Add the script to your app shell so it loads on first paint:

```html theme={null}
<script async src="https://www.trackrev.io/p.js" data-id="YOUR_WORKSPACE_ID"></script>
```

## 2. Fire a pageview on each route change

<CodeGroup>
  ```jsx React Router theme={null}
  import { useEffect } from "react";
  import { useLocation } from "react-router-dom";

  export function usePageviews() {
    const location = useLocation();
    useEffect(() => {
      window.trk?.pageview();
    }, [location.pathname]);
  }
  ```

  ```jsx Next.js (App Router) theme={null}
  "use client";
  import { useEffect } from "react";
  import { usePathname } from "next/navigation";

  export function usePageviews() {
    const pathname = usePathname();
    useEffect(() => {
      window.trk?.pageview();
    }, [pathname]);
  }
  ```

  ```js Vue Router theme={null}
  router.afterEach(() => {
    window.trk?.pageview();
  });
  ```
</CodeGroup>

<Note>
  Use optional chaining (`window.trk?.pageview()`) so a route change never throws if the script
  hasn't finished loading yet.
</Note>

## 3. Identify and track as usual

These don't depend on route changes — call them whenever the event happens:

```js theme={null}
// on login / signup
window.trk?.identify("customer@example.com");

// a custom conversion event
window.trk?.track("trial_started", { plan: "pro" });
```

## 4. Pass the vid at checkout

If checkout runs client-side, read `window.trk.vid` when you create the session; if it runs
server-side, read the `vid` cookie. See
[Pass the visitor id to checkout](/revenue-attribution/pass-vid-to-checkout).

<Check>
  Your SPA now records a pageview per navigation, and the visitor journey shows the full in-app
  path — not just the landing page.
</Check>
