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

# TanStack Start Integration

> Install Userplane in a TanStack Start application using a client-side provider component

This guide covers how to install Userplane in a TanStack Start application.

## Adding the script

The fastest way to add Userplane is the CDN embed. Add these two tags to the `<head>` in your root route's `<Head>` component:

```tsx theme={null}
// app/routes/__root.tsx
import { createRootRoute, HeadContent, Outlet } from '@tanstack/react-router';

export const Route = createRootRoute({
  head: () => ({
    meta: [{ name: 'userplane:workspace', content: 'YOUR_WORKSPACE_ID' }],
    scripts: [{ type: 'module', src: 'https://cdn.userplane.io/embed/script.js' }],
  }),
  component: RootComponent,
});

function RootComponent() {
  return (
    <>
      <HeadContent />
      <Outlet />
    </>
  );
}
```

You can copy the snippet with your workspace ID pre-filled from **Workspace Settings > Domains** in the Userplane dashboard.

## npm SDK

Use the npm SDK when you need programmatic control — triggering recordings from a button, attaching user metadata, or reading recording state.

### Installation

<CodeGroup>
  ```bash npm theme={null}
  npm install @userplane/sdk
  ```

  ```bash yarn theme={null}
  yarn add @userplane/sdk
  ```

  ```bash pnpm theme={null}
  pnpm add @userplane/sdk
  ```

  ```bash bun theme={null}
  bun add @userplane/sdk
  ```
</CodeGroup>

### Initialization

Create a `UserplaneProvider` component and render it inside your root route component. Use `useEffect` with a dynamic `import()` to ensure initialization runs only in the browser.

```tsx theme={null}
// app/components/UserplaneProvider.tsx
'use client';

import { useEffect } from 'react';

export function UserplaneProvider({ children }: { children: React.ReactNode }) {
  useEffect(() => {
    import('@userplane/sdk').then(({ initialize }) => {
      initialize({
        workspaceId: import.meta.env.VITE_USERPLANE_WORKSPACE_ID,
      });
    });
  }, []);

  return <>{children}</>;
}
```

```tsx theme={null}
// app/routes/__root.tsx
import { UserplaneProvider } from '../components/UserplaneProvider';

function RootComponent() {
  return (
    <UserplaneProvider>
      <HeadContent />
      <Outlet />
    </UserplaneProvider>
  );
}
```

### URL parameters

<Warning>
  **Important:** TanStack Router validates search parameters against a Zod schema. If a route schema
  does not include `userplane-token`, `userplane-action`, and `userplane-workspace`, the router
  throws a `notFoundError` when Userplane appends those params to the URL.
</Warning>

Add the Userplane params to your root route's search param schema:

```typescript theme={null}
// app/routes/__root.tsx
import { createRootRoute } from '@tanstack/react-router';
import { z } from 'zod';

const searchSchema = z.object({
  'userplane-token': z.string().optional(),
  'userplane-action': z.string().optional(),
  'userplane-workspace': z.string().optional(),
});

export const Route = createRootRoute({
  validateSearch: searchSchema,
  component: RootComponent,
});
```

Defining this on the root route means all child routes inherit it automatically. You can also use `z.record(z.string())` for a more permissive catch-all if your app accepts arbitrary query parameters.

If your app redirects unauthenticated users to a login page, preserve the `userplane-` prefixed parameters through the redirect:

```typescript theme={null}
// Example: auth-protected route
import { redirect } from '@tanstack/react-router';

export const Route = createFileRoute('/dashboard')({
  beforeLoad: ({ context, search }) => {
    if (!context.auth.isAuthenticated) {
      throw redirect({
        to: '/login',
        search: {
          'userplane-token': search['userplane-token'],
          'userplane-action': search['userplane-action'],
          'userplane-workspace': search['userplane-workspace'],
        },
      });
    }
  },
});
```

See [Installation](/developer/installation) for the full list of parameters.

## Sensitive data

Add `data-userplane-blur` to any element you want blurred in recordings. See [Sensitive Data Redaction](/developer/sensitive-data-redaction) for the full reference.

## Metadata

Call `set()` inside the `useEffect` after `initialize()`:

```tsx theme={null}
useEffect(() => {
  import('@userplane/sdk').then(({ initialize, set }) => {
    initialize({ workspaceId: import.meta.env.VITE_USERPLANE_WORKSPACE_ID });
    set('environment', import.meta.env.MODE);
  });
}, []);
```

See [Metadata SDK](/developer/metadata-sdk) for the full API.

## SSR

TanStack Start renders on the server before hydrating in the browser. `@userplane/sdk` is SSR-safe to import — it does not reference `window` or `document` at module evaluation time. The `initialize()` call must run client-side, which `useEffect` guarantees.

| Concern                                           | Safe? | Notes                         |
| ------------------------------------------------- | ----- | ----------------------------- |
| Static `import` at top of file                    | Yes   | Module is SSR-safe            |
| Calling `initialize()` in `useEffect`             | Yes   | Runs browser-only             |
| Dynamic `import('@userplane/sdk')` in `useEffect` | Yes   | Bundle-size optimization only |
| Calling `initialize()` in a loader                | No    | Loaders run on the server     |
| Missing search params in route schema             | No    | Router throws `notFoundError` |

## Example app

A complete TanStack Start example is available at [github.com/userplanehq/userplane-sdk-examples/tree/main/examples/tanstack-start](https://github.com/userplanehq/userplane-sdk-examples/tree/main/examples/tanstack-start).

<Frame caption="Example app">
  <img src="https://mintcdn.com/userplane/iHJrxtyvOmNXmfMS/media/developer/framework/tanstack-example-app.png?fit=max&auto=format&n=iHJrxtyvOmNXmfMS&q=85&s=339a43d37391120405b6c56a9ceab2ca" width="1920" height="1440" data-path="media/developer/framework/tanstack-example-app.png" />
</Frame>

| Variable                      | Description                 |
| ----------------------------- | --------------------------- |
| `VITE_USERPLANE_WORKSPACE_ID` | Your Userplane workspace ID |

```bash theme={null}
cd examples/tanstack-start && npm install && npm run dev
```

## Related articles

* [Installation](/developer/installation) — CDN script placement, CSP, and redirect handling.
* [Web SDK](/developer/web-sdk) — full SDK API reference.
* [Metadata SDK](/developer/metadata-sdk) — attach user context to recordings.
* [Sensitive Data Redaction](/developer/sensitive-data-redaction) — blur sensitive content in recordings.
