# Next.js

> Mount the pipedog WebRTC offer endpoint in a Next.js route handler on the Node.js runtime.

Source: https://polvallverdu.github.io/pipedog/docs/frameworks/nextjs/



An App Router route handler handles `POST /api/offer` on the Node.js runtime. It passes the web
`Request` to `offer` unchanged.

## Install [#install]

```bash
bun add @pipedog/core @pipedog/asyncio @pipedog/transport-smallwebrtc @pipedog/transport-websocket @pipedog/serializer-protobuf @pipedog/openai @pipedog/audio-silero @pipedog/audio-smart-turn
```

`@pipedog/audio-smart-turn` isn't imported anywhere: the default turn strategies load it. To run
the snippet from a checkout instead, see [Installation](https://polvallverdu.github.io/pipedog/docs/installation/#from-source).

## Files [#files]

The endpoints come from the shared module on the [overview](https://polvallverdu.github.io/pipedog/docs/frameworks/#the-two-endpoints).
`@/lib/voice` re-exports it:

```ts title="lib/voice.ts"
export { offer, runSocketAgent, socket } from "../../shared/voice.ts";

```

```ts title="app/api/offer/route.ts"
import { offer } from "@/lib/voice";

// The Node.js runtime, not the edge: the media runs over UDP, and the server has
// to stay up for the call.
export const runtime = "nodejs";

export const POST = (request: Request) => offer(request);

```

## Run it [#run-it]

```bash
OPENAI_API_KEY=sk-... bunx next dev
```

The browser then POSTs its SDP offer to `/api/offer`.

## Deploy [#deploy]

The route sets `runtime = "nodejs"`, not the edge, because the offer's media runs over UDP and the
server has to stay up for the call. Run it with `next start` on a long-lived server. Vercel's
serverless functions don't carry the UDP media.

## WebSocket [#websocket]

A Next.js route handler can't upgrade a WebSocket. Mount `socket` on a server that can upgrade: a
[Bun](https://polvallverdu.github.io/pipedog/docs/frameworks/bun.md), Node or [Deno](https://polvallverdu.github.io/pipedog/docs/frameworks/deno.md) server next to the Next.js app, or
[Cloudflare Workers](https://polvallverdu.github.io/pipedog/docs/frameworks/cloudflare-workers.md).

## Authentication [#authentication]

The route has no auth. Wrap `offer` with a session check before it runs, as in
[Authentication](https://polvallverdu.github.io/pipedog/docs/frameworks/#authentication).
