# Next.js (Pages Router) quickstart

Add a Web Agent to a Next.js app that uses the Pages Router. At the end, the agent's launcher is on every page and the agent knows which user is signed in, from a token an API route of your app signs.

The adapter that lets the agent call Server Actions needs the App Router and is not part of this quickstart. In a Pages Router app the agent calls your API routes under `pages/api` and external APIs.

## Prerequisites

- Next.js 14 or later with the Pages Router, and React 18 or later.
- A Web Agent in your workspace, created with Next.js as its technology, whose analysis has finished, with a version deployed to Production.

## 1. Copy your agent ID

1. In the portal, go to [**Web Agents**](https://auth.faustine.ai/go?to=%2Fweb-assistants) and select your agent.
2. In the **Overview** tab, find the **Install the assistant** card and select **By hand**.
3. In the **Mount** step, select **Show snippet** and copy the `agentId` value. The rest of the snippet is for the App Router.

## 2. Install the packages

**npm**

```bash
npm install @faustine-ai/next @faustine-ai/web-agent
```

**pnpm**

```bash
pnpm add @faustine-ai/next @faustine-ai/web-agent
```

**yarn**

```bash
yarn add @faustine-ai/next @faustine-ai/web-agent
```

**bun**

```bash
bun add @faustine-ai/next @faustine-ai/web-agent
```

## 3. Mount the agent

Render `<FaustineAgent>` once in `pages/_app.tsx`, next to the page component.

```tsx filename="pages/_app.tsx"
import type { AppProps } from 'next/app';
import { FaustineAgent } from '@faustine-ai/next/client';

export default function App({ Component, pageProps }: AppProps) {
  return (
    <>
      <Component {...pageProps} />
      <FaustineAgent agentId="<AGENT_ID>" />
    </>
  );
}
```

The component loads the Production environment. To load another one, pass its name: `env="Staging"`.

## 4. Identify the signed-in user

The Pages Router has no root layout that runs only on the server, so the token is signed in an API route and fetched after the page mounts.

Copy the agent's secret from the **Settings** tab, under **Identity verification**, and add it to your server environment as `FAUSTINE_IDENTITY_SECRET`. Do not give the variable a `NEXT_PUBLIC_` prefix.

Add the API route. `getSession` stands for your own session helper.

```ts filename="pages/api/faustine-identity.ts"
import type { NextApiRequest, NextApiResponse } from 'next';
import { faustineIdentityToken } from '@faustine-ai/next';
import { getSession } from '../../lib/session';

export default async function handler(req: NextApiRequest, res: NextApiResponse) {
  const user = await getSession(req);
  const jwt = user
    ? faustineIdentityToken({ id: user.id, name: user.name, email: user.email })
    : null;
  res.setHeader('Cache-Control', 'no-store');
  res.status(200).json({ jwt });
}
```

Fetch the token in `_app.tsx` and pass it to the component.

```tsx filename="pages/_app.tsx"
import type { AppProps } from 'next/app';
import { useEffect, useState } from 'react';
import { FaustineAgent } from '@faustine-ai/next/client';

export default function App({ Component, pageProps }: AppProps) {
  const [identityJwt, setIdentityJwt] = useState<string | null>(null);
  useEffect(() => {
    fetch('/api/faustine-identity')
      .then((res) => res.json())
      .then((data) => setIdentityJwt(data.jwt))
      .catch(() => setIdentityJwt(null));
  }, []);
  return (
    <>
      <Component {...pageProps} />
      <FaustineAgent agentId="<AGENT_ID>" identityJwt={identityJwt} />
    </>
  );
}
```

The widget starts as anonymous and the component identifies the user when the token arrives. `faustineIdentityToken` signs an HS256 token that expires after 3600 seconds. Only `id` is required.

## 5. Run your app

```bash
npm run dev
```

> **Checkpoint:** The agent's launcher appears on the page and stays after you move to another page. Sign in, select the launcher and send a message. In the portal, the conversation appears under the agent's **Monitoring** tab, with your name and a **Verified** badge.

## Install with a coding agent

The `install-faustine` skill detects the Pages Router and does steps 2 to 4 in your repository.

```bash
npx skills add faustine-ai/skills
```

Then, in your coding agent:

```text
/install-faustine <AGENT_ID>
```

## Troubleshooting

| Symptom | Cause | Fix |
| --- | --- | --- |
| `/api/faustine-identity` answers `500`, and the server log has an error that starts `faustineIdentityToken: set FAUSTINE_IDENTITY_SECRET` | The server environment has no secret. | Add the variable to `.env.local` and restart the dev server. |
| No launcher, and the request to `webagent.faustine.ai/embed` returns `404` | No environment of the agent serves a version. | [Publish a version](https://docs.faustine.ai/web-agents/publish-a-version/). |
| No launcher, and the same request returns `403` | The page's domain is not in the environment's allowed domains. | See [Restrict the domains that can load the agent](https://docs.faustine.ai/web-agents/restrict-domains/). |
| The user stays anonymous after signing in | The app fetched the token before the session existed and did not fetch it again. | Fetch `/api/faustine-identity` again after sign-in and set the new token. |

## Next steps

- [Next.js on Faustine](https://docs.faustine.ai/technologies/nextjs/): what each router supports.
- [Identity verification](https://docs.faustine.ai/web-agents/identity-verification/): what a verified user gets.
- [Restrict the domains that can load the agent](https://docs.faustine.ai/web-agents/restrict-domains/): allow your own domains only.
- [Next.js (App Router) quickstart](https://docs.faustine.ai/technologies/nextjs-app-router/): the same install with the token signed in the root layout.
