Skip to content
Botscent

Next.js

Add both halves of Botscent to a Next.js app and check the install.

Add Botscent to a Next.js app. The page half runs in the browser from instrumentation-client.ts. The server half runs in proxy.ts.

Before you start

You need:

  • Next.js 15.3 or later. For Next.js 14 to 15.2, see Older versions.
  • Node.js 22.12 or later.

1. Install the package

Install botscent from npm.

Terminal
npm install botscent

With pnpm, yarn or bun, use their add command.

2. Add the page half

In instrumentation-client.ts in the project root, import botscent/auto. If the file exists, add the line to the existing file.

instrumentation-client.ts
import 'botscent/auto'

The page half now starts before hydration.

3. Add the server half

If the project has no proxy, create proxy.ts in the project root. Export the Botscent proxy from the file.

proxy.ts
export { proxy } from 'botscent/next'

On Vercel, the proxy now sends the request's own verdict to the page in a Server-Timing header.

If the project already has a proxy, wrap its function with withBotscent from botscent/next. Keep your own code as it is.

proxy.ts
import { NextResponse, type NextRequest } from 'next/server'
import { withBotscent } from 'botscent/next'

function existingProxy(request: NextRequest) {
  if (request.nextUrl.pathname === '/old') return NextResponse.redirect(new URL('/new', request.url))
  return NextResponse.next()
}

export const proxy = withBotscent(existingProxy)

The response of your proxy stays the same, except for Server-Timing and, for agents, Cache-Control.

Warning: Do not replace an existing proxy with export { proxy } from 'botscent/next'. The replacement removes your own proxy code, such as redirects and access checks. Wrap the existing function with withBotscent.

4. Read the verdict

You can read the verdict in a client component and in a route handler.

In a client component, call useBotscent from botscent/react. The component renders again when the page verdict changes.

app/verdict.tsx
'use client'
import { useBotscent } from 'botscent/react'

export function VerdictView() {
  const verdict = useBotscent()
  return <pre>{JSON.stringify(verdict)}</pre>
}

In a normal browser, the component shows {"type":"human","reasons":[]}.

In a route handler, call inspect from botscent/server with the request. inspect returns the request's own verdict.

app/api/checkout/route.ts
import { inspect } from 'botscent/server'

export async function POST(request: Request) {
  const verdict = await inspect(request)
  return Response.json(verdict)
}

The route handler now returns the request's own verdict as JSON.

Warning: Do not use agent_name or the page verdict to allow access. Anyone can send the headers that produce a name, and the browser computes the page verdict. Use isVerified on the request's own verdict, as The trust model describes.

5. Check the install

Start the app. Then run the check against its URL.

Terminal
npx botscent check http://localhost:3000/

The page-script check prints pass, and the command exits with code 0.

On your own server, the server-half check prints unknown, because the transport is off there. See From the server to the page. On Vercel, the server-half check prints pass.

If a check fails, see Verify your install.

Older versions

Before Next.js 15.3, Next.js has no instrumentation-client.ts. Render <Botscent /> from botscent/react once in the root layout.

app/layout.tsx
import { Botscent } from 'botscent/react'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <Botscent />
        {children}
      </body>
    </html>
  )
}

Before Next.js 16, the proxy file is middleware.ts. Export the Botscent proxy under the name middleware.

middleware.ts
export { proxy as middleware } from 'botscent/next'

If the project already has a middleware, wrap its function with withBotscent.

middleware.ts
import { NextResponse, type NextRequest } from 'next/server'
import { withBotscent } from 'botscent/next'

function existingMiddleware(request: NextRequest) {
  if (request.nextUrl.pathname === '/old') return NextResponse.redirect(new URL('/new', request.url))
  return NextResponse.next()
}

export const middleware = withBotscent(existingMiddleware)

Next steps