# SDK — React Router (/docs/sdk/react-router)



{/* AGENT-4-OUTPUT-PENDING: confirm whether dedicated `@layers/react-router` wrappers ship; this guide assumes standard `@layers/client` + thin context wrapper. */}

React Router has two materially different shapes today — v6 (the classic `BrowserRouter` + `Routes` + `Route` JSX tree) and v7 (the data router with loaders + the optional **framework mode** that enables SSR). The SDK install is the same; the integration touchpoints differ.

## Install [#install]

```bash
npm i @layers/client
```

## v6 — BrowserRouter [#v6--browserrouter]

Wrap the router with a Layers provider. Use `useLocation` in a tracker component to fire `screen()` on every route change.

```tsx title="src/main.tsx"
import { LayersClient } from '@layers/client';
import { BrowserRouter, Routes, Route, useLocation } from 'react-router-dom';
import { createContext, useContext, useEffect, useState } from 'react';

const LayersContext = createContext<LayersClient | null>(null);
const useLayers = () => useContext(LayersContext);

function PageTracker() {
  const layers = useLayers();
  const { pathname } = useLocation();
  useEffect(() => {
    layers?.screen(pathname).catch(() => {});
  }, [layers, pathname]);
  return null;
}

function LayersProvider({ children }: { children: React.ReactNode }) {
  const [client, setClient] = useState<LayersClient | null>(null);
  useEffect(() => {
    const c = new LayersClient({
      apiKey: 'unused',
      appId: import.meta.env.VITE_LAYERS_APP_ID,
      environment: import.meta.env.MODE === 'production' ? 'production' : 'development',
    });
    c.init().then(() => setClient(c));
  }, []);
  return <LayersContext.Provider value={client}>{children}</LayersContext.Provider>;
}

createRoot(document.getElementById('root')!).render(
  <BrowserRouter>
    <LayersProvider>
      <PageTracker />
      <Routes>{/* … */}</Routes>
    </LayersProvider>
  </BrowserRouter>,
);
```

`PageTracker` must mount inside the router context (so `useLocation` resolves) and inside `LayersProvider` (so it can read the client). Render it once near the root.

## v7 — Data router (createBrowserRouter) [#v7--data-router-createbrowserrouter]

The hooks are the same; what changes is where you mount the provider. With `createBrowserRouter`, your route tree is configuration — wrap the `<RouterProvider>`:

```tsx
import { createBrowserRouter, RouterProvider } from 'react-router-dom';

const router = createBrowserRouter([
  // … your routes
]);

function App() {
  return (
    <LayersProvider>
      <RouterProvider router={router} />
    </LayersProvider>
  );
}
```

Page tracking still uses `useLocation` — render `<PageTracker />` from a route element (typically the root layout component).

## v7 — Framework mode (SSR) [#v7--framework-mode-ssr]

React Router v7 framework mode runs the route tree on the server. Same SSR rules as Next.js apply:

* **Never** initialize the SDK on the server. Use a `useEffect`-based provider, identical to the Next.js App Router pattern.
* For server-side event firing (post-purchase webhooks, etc.) call [`POST /v1/events`](/docs/api/reference/events/forward) — the partner-API forwarding surface — from your loader/action functions.

```tsx title="app/root.tsx"
import { useEffect, useState } from 'react';
import { Outlet, useLocation } from 'react-router';
import { LayersClient } from '@layers/client';

export default function Root() {
  const [client, setClient] = useState<LayersClient | null>(null);
  const { pathname } = useLocation();

  useEffect(() => {
    const c = new LayersClient({
      apiKey: 'unused',
      appId: import.meta.env.VITE_LAYERS_APP_ID,
      environment: import.meta.env.MODE === 'production' ? 'production' : 'development',
    });
    c.init().then(() => setClient(c));
  }, []);

  useEffect(() => {
    client?.screen(pathname).catch(() => {});
  }, [client, pathname]);

  return <Outlet />;
}
```

## Tracking events [#tracking-events]

Same `LayersClient` API as every other JS environment:

```tsx
const layers = useLayers();
layers?.track('purchase_success', { revenue: 19.99, currency: 'USD' });
```

See [Standard events](/docs/sdk/standard-events) for canonical event names; events outside that list are stored but not relayed to CAPI.

## Verifying the install [#verifying-the-install]

```bash
curl -X POST https://api.layers.com/v1/projects/$PROJECT_ID/sdk-apps/$APP_ID/verify-tracking \
  -H "Authorization: Bearer $LAYERS_API_KEY"
```

See [`verify-tracking`](/docs/api/reference/sdk-apps/verify-tracking).

## See also [#see-also]

* [Vite guide](/docs/sdk/vite) — most React Router apps build with Vite.
* [Next.js guide](/docs/sdk/nextjs) — for App Router apps that aren't using React Router.
* [Standard events](/docs/sdk/standard-events)
* [Server-side forwarding](/docs/api/reference/events/forward)
