Get Started with BotID
The set up involves adding:
- a client side component to run challenges,
- a server side function to classify the session, and
- a configuration change to ensure requests are routed through BotID.
BotID works best with Vercel in front. If your app is serving traffic through a reverse proxy, BotID can work in a degraded mode. Please reach out to our support team for assistance in getting BotID to work with a reverse proxy in front.
Before setting up BotID, ensure you have a JavaScript project deployed on Vercel.
Add BotID to your project:
pnpm i botid
Use the appropriate configuration method for your framework to set up proxy rewrites. This ensures that ad-blockers, third party scripts, and more won't make BotID any less effective.
next.config.jsimport { withBotId } from 'botid/next/config'; const nextConfig = { // Your existing Next.js config }; export default withBotId(nextConfig);
nuxt.config.tsexport default defineNuxtConfig({ modules: ['botid/nuxt'], });
For other frameworks, add the following configuration values to your
vercel.json
:When using
vercel.json
configuration, these rewrites only apply in production. For local development behavior, see the Local Development Behavior section.vercel.json{ "rewrites": [ { "source": "/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/a-4-a/c.js", "destination": "https://api.vercel.com/bot-protection/v1/challenge" }, { "source": "/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/:path*", "destination": "https://api.vercel.com/bot-protection/v1/proxy/:path*" } ], "headers": [ { "source": "/149e9513-01fa-4fb0-aad4-566afd725d1b/2d206a39-8ed7-437e-a3be-862e0f06eea3/:path*", "headers": [ { "key": "X-Frame-Options", "value": "SAMEORIGIN" } ] } ] }
Choose the appropriate method for your framework:
- Next.js 15.3+: Use
initBotId()
ininstrumentation.client.ts
for optimal performance - Other Next.js: Mount the
<BotIdClient/>
component in your layouthead
- Other frameworks: Call
initBotId()
during application initialization
Next.js 15.3+ (Recommended)
We recommend using
initBotId()
ininstrumentation-client.ts
for better performance in Next.js 15.3+. For earlier versions, use the React component approach.instrumentation-client.tsimport { initBotId } from 'botid/client/core'; // Define the paths that need bot protection. // These are paths that are routed to by your app. // These can be: // - API endpoints (e.g., '/api/checkout') // - Server actions invoked from a page (e.g., '/dashboard') // - Dynamic routes (e.g., '/api/create/*') initBotId({ protect: [ { path: '/api/checkout', method: 'POST', }, { // Wildcards can be used to expand multiple segments // /team/*/activate will match // /team/a/activate // /team/a/b/activate // /team/a/b/c/activate // ... path: '/team/*/activate', method: 'POST', }, { // Wildcards can also be used at the end for dynamic routes path: '/api/user/*', method: 'POST', }, ], });
Next.js < 15.3
app/layout.tsximport { BotIdClient } from 'botid/client'; import { ReactNode } from 'react'; const protectedRoutes = [ { path: '/api/checkout', method: 'POST', }, ]; type RootLayoutProps = { children: ReactNode; }; export default function RootLayout({ children }: RootLayoutProps) { return ( <html lang="en"> <head> <BotIdClient protect={protectedRoutes} /> </head> <body>{children}</body> </html> ); }
plugins/botid.client.tsimport { initBotId } from 'botid/client/core'; export default defineNuxtPlugin({ enforce: 'pre', setup() { initBotId({ protect: [{ path: '/api/post-data', method: 'POST' }], }); }, });
src/hooks.client.tsimport { initBotId } from 'botid/client/core'; export function init() { initBotId({ protect: [ { path: '/api/post-data', method: 'POST', }, ], }); }
- Next.js 15.3+: Use
Use
checkBotId()
on the routes configured in the<BotIdClient/>
component.Important configuration requirements: - Not adding the protected route to
<BotIdClient />
will result incheckBotId()
failing. The client side component dictates which requests to attach special headers to for classification purposes. - Local development always returnsisBot: false
unless you configure thedevelopmentOptions
option oncheckBotId()
. Learn more about local development behavior.Using API routes
app/api/sensitive/route.tsimport { 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 }); } const data = await processUserRequest(request); return NextResponse.json({ data }); } async function processUserRequest(request: NextRequest) { // Your business logic here const body = await request.json(); // Process the request... return { success: true }; }
Using Server Actions
app/actions/create-user.ts'use server'; import { checkBotId } from 'botid/server'; export async function createUser(formData: FormData) { const verification = await checkBotId(); if (verification.isBot) { throw new Error('Access denied'); } const userData = { name: formData.get('name') as string, email: formData.get('email') as string, }; const user = await saveUser(userData); return { success: true, user }; } async function saveUser(userData: { name: string; email: string }) { // Your database logic here console.log('Saving user:', userData); return { id: '123', ...userData }; }
BotID actively runs JavaScript on page sessions and sends headers to the server. If you test with
curl
or visit a protected route directly, BotID will block you in production. To effectively test, make afetch
request from a page in your application to the protected route.- Only available on Pro or Enterprise plans
From the Vercel dashboard
- Select your Project
- Click the Firewall tab
- Click Configure
- Enable Vercel BotID Deep Analysis
Client-side code for the BotID Next.js implementation:
'use client';
import { useState } from 'react';
export default function CheckoutPage() {
const [loading, setLoading] = useState(false);
const [message, setMessage] = useState('');
async function handleCheckout(e: React.FormEvent<HTMLFormElement>) {
e.preventDefault();
setLoading(true);
try {
const formData = new FormData(e.currentTarget);
const response = await fetch('/api/checkout', {
method: 'POST',
body: JSON.stringify({
product: formData.get('product'),
quantity: formData.get('quantity'),
}),
headers: {
'Content-Type': 'application/json',
},
});
if (!response.ok) {
throw new Error('Checkout failed');
}
const data = await response.json();
setMessage('Checkout successful!');
} catch (error) {
setMessage('Checkout failed. Please try again.');
} finally {
setLoading(false);
}
}
return (
<form onSubmit={handleCheckout}>
<input name="product" placeholder="Product ID" required />
<input name="quantity" type="number" placeholder="Quantity" required />
<button type="submit" disabled={loading}>
{loading ? 'Processing...' : 'Checkout'}
</button>
{message && <p>{message}</p>}
</form>
);
}
Server-side code for the BotID Next.js implementation:
import { checkBotId } from 'botid/server';
import { NextRequest, NextResponse } from 'next/server';
export async function POST(request: NextRequest) {
// Check if the request is from a bot
const verification = await checkBotId();
if (verification.isBot) {
return NextResponse.json(
{ error: 'Bot detected. Access denied.' },
{ status: 403 },
);
}
// Process the legitimate checkout request
const body = await request.json();
// Your checkout logic here
const order = await processCheckout(body);
return NextResponse.json({
success: true,
orderId: order.id,
});
}
async function processCheckout(data: any) {
// Implement your checkout logic
return { id: 'order-123' };
}
Was this helpful?