# How to protect your AI endpoints with Vercel BotID

**Author:** Ben Sabic

---

[Vercel BotID](https://vercel.com/botid) lets you verify that each request to your AI endpoints comes from a real browser before any inference runs. Working as an invisible CAPTCHA, it attaches a client-side challenge to requests on the routes you protect, and a server-side `checkBotId()` call classifies each one, so automated clients are turned away before they reach your model. Running it on every request, rather than once per session, means an attacker can't bypass it once and reuse that access across thousands of stolen calls. That difference is what kept Nous Research’s chat app online when a coordinated attack [spiked its traffic by 3,000%](https://vercel.com/blog/how-nous-research-used-botid-to-block-automated-abuse-at-scale) while inference stayed flat.

This guide walks you through installing BotID, declaring an AI route on the client, and gating that route with `checkBotId()` on the server so inference runs only for verified requests. You'll also set detection levels per route, enabling Deep Analysis on your highest-value endpoints and basic checks elsewhere, and learn how to let legitimate automation through with a [Vercel WAF](https://vercel.com/security/web-application-firewall) bypass rule.

## Prerequisites

Before you begin, make sure you have:

- A JavaScript project [deployed on Vercel](https://vercel.com/docs/projects/managing-projects#creating-a-project)
  
- An AI endpoint that accepts frontend requests, such as a route built with [AI SDK](https://ai-sdk.dev)
  
- A Pro or Enterprise plan to use [Deep Analysis](https://vercel.com/docs/botid#deep-analysis) (Basic is available on all plans)
  

## Steps

### 1\. Install the BotID package

Add BotID to your project:

`npm i botid`

### 2\. Configure proxy rewrites

Wrap your Next.js config with `withBotId`. This sets up proxy rewrites so that ad-blockers and third-party scripts can't weaken BotID's protection:

`import { withBotId } from 'botid/next/config'; const nextConfig = { // Your existing Next.js config }; export default withBotId(nextConfig);`

For Nuxt, SvelteKit, and other frameworks, the setup follows a similar pattern. See the [BotID getting started guide](https://vercel.com/docs/botid/get-started) for the per-framework versions.

### 3\. Declare your AI route on the client

Call `initBotId()` during client initialization and list the AI routes you want to protect. BotID uses this list to attach challenge headers to matching requests. If a route isn't declared here, its requests arrive without those headers, so `checkBotId()` has nothing to verify and treats them as bots.

For Next.js 15.3 and later, use `instrumentation-client.ts`:

`import { initBotId } from 'botid/client/core'; initBotId({ protect: [{ path: '/api/chat', method: 'POST', }, ], });` On earlier versions of Next.js, mount the `<BotIdClient />` component in your root layout `head` instead, passing the same `protect` array. ### 4\. Verify every request on the server Call `checkBotId()` inside the route handler, before the AI call runs. This is the load-bearing step: it returns a classification for the request currently being served, so a blocked request never reaches your model. `import { checkBotId } from 'botid/server'; import { NextRequest, NextResponse } from 'next/server'; export async function POST(request: NextRequest) { const verification = await checkBotId(); if (verification.isBot) { return NextResponse.json({ error: 'Access denied' }, { status: 403 }); } // Inference runs only after verification passes const body = await request.json(); const result = await runInference(body); return NextResponse.json({ result }); } async function runInference(body: unknown) { // Your AI SDK or model call here return { output: 'response' }; }` Placing the check before `runInference` means you incur the inference cost only for verified requests. ### 5\. Enable Deep Analysis Basic validation catches many less sophisticated bots and runs free on all plans. For high-value AI routes, enable Deep Analysis, which uses a [Kasada-powered](https://www.kasada.io/) machine learning model to analyze thousands of client-side signals.

Because Deep Analysis learns and adapts in real time, it can detect coordinated attacks that initially appear as legitimate traffic. In one incident, it traced a 500% traffic spike to a new bot network by correlating identical browser fingerprints cycling across proxy nodes. It then reclassified and blocked those sessions within roughly 10 minutes, without any manual intervention. For the full breakdown, see how [BotID Deep Analysis caught a sophisticated bot network in real time](https://vercel.com/blog/botid-deep-analysis-catches-a-sophisticated-bot-network-in-real-time).

Visit the [Bot Management](https://vercel.com/d?to=%2F%5Bteam%5D%2F%5Bproject%5D%2Ffirewall%2Fbot-management) page in your project settings, then click the **Configure** button to open the configuration settings and enable Deep Analysis.

This feature is available for all customers on [Pro and Enterprise plans](https://vercel.com/docs/botid#pricing). Only requests that invoke `checkBotId()` are charged, passive page views are not.

## Best practices

- **Run the check before inference**: Keep `checkBotId()` ahead of the model call in your handler, so a blocked request never costs you a token.
  
- **Set detection levels per route**: Use `advancedOptions.checkLevel` to apply `deepAnalysis` to your most sensitive routes and `basic` elsewhere. The `checkLevel` must be identical in your client and server configurations for each route, or verification will fail. This is available in `botid@1.4.5` and later.
  

### Allow trusted agents with Verified Bots

Blocking based on `isBot` alone also blocks legitimate automated agents, such as crawlers (e.g., Googlebot) and AI assistants (e.g., ChatGPT). To let specific agents through, use the verified-bot fields that `checkBotId()` returns along with `isBot`.

Vercel identifies these agents from its [verified bot directory](https://bots.fyi/) and returns `isVerifiedBot`, `verifiedBotName`, and `verifiedBotCategory`, so you can allow an agent like ChatGPT Operator while still blocking everything else.

`import { checkBotId } from 'botid/server'; import { NextResponse } from 'next/server'; export async function POST(request: Request) { const { isBot, isVerifiedBot, verifiedBotName } = await checkBotId(); // Allow ChatGPT Operator through; block all other bots const isOperator = isVerifiedBot && verifiedBotName === 'chatgpt-operator'; if (isBot && !isOperator) { return NextResponse.json({ error: 'Access denied' }, { status: 403 }); } // Inference runs for verified humans and allowed agents const body = await request.json(); const result = await runInference(body); return NextResponse.json({ result }); } async function runInference(body: unknown) { // Your AI SDK or model call here return { output: 'response' }; }`

For a trusted service that isn't in the verified bot directory, add a [bypass rule in the Vercel WAF](https://vercel.com/docs/vercel-firewall/firewall-concepts#bypass) rather than removing protection from the route. See [Handling Verified Bots](https://vercel.com/docs/botid/verified-bots) for the full list of agents and categories.

## Troubleshooting

### `checkBotId()` always reports a bot

Confirm the route is declared in your client `protect` array with a matching `path` and `method`. BotID only attaches challenge headers to declared routes, so an undeclared route has nothing for the server to verify.

### Testing with curl returns a 403

BotID runs JavaScript in the browser session and sends headers to the server, so a direct request from curl or a browser address bar is treated as a bot in production. To test a protected route, make a `fetch` request from a page in your own application.

### Local development always passes

Local development returns `isBot: false` unless you set the `developmentOptions` option on `checkBotId()`. See [Local Development Behavior](https://vercel.com/docs/botid/local-development-behavior) in the BotID docs for instructions on simulating bot traffic.

## Related resources

- [BotID overview](https://vercel.com/docs/botid)
  
- [Get Started with BotID](https://vercel.com/docs/botid/get-started)
  
- [Advanced BotID Configuration](https://vercel.com/docs/botid/advanced-configuration)
  
- [Handling Verified Bots](https://vercel.com/docs/botid/verified-bots)
  
- [How Nous Research used BotID to block automated abuse at scale](https://vercel.com/blog/how-nous-research-used-botid-to-block-automated-abuse-at-scale)
  
- [BotID Deep Analysis catches a sophisticated bot network in real-time](https://vercel.com/blog/botid-deep-analysis-catches-a-sophisticated-bot-network-in-real-time)

---

[View full KB sitemap](/kb/sitemap.md)
