Let a verified agent through
Skip a challenge, a sign-in wall or a rate limit for an agent whose signature verified.
Let an agent with a verified signature past a challenge, a sign-in wall or a rate limit. Agents that prove who runs them get through, and every other visitor meets the same checks as before.
Before you start
- Install the server half of Botscent. See Next.js or Express.
- Find which agents sign their requests. Agents lists them. In this release, ChatGPT, Grok Bot, Manus and Cloudflare Browser Run sign.
1. Choose what a verified agent can skip
A verified signature proves that the agent operator's infrastructure signed the request. It does not prove who the person is, or which model runs the session.
So let a verified agent past checks that protect your site. Examples are a challenge, a rate limit, and a sign-in wall in front of pages that hold no person's data. Keep the checks that protect a person's account.
Each signature has a time window, from 5 s before its created time to its expires time. Someone who captures a signed request can replay the signature to the same host within that window. See The trust model.
2. Check the signature on the server
In proxy.ts, call isVerified on the request's own verdict before the challenge:
import { NextResponse, type NextRequest } from 'next/server'
import { withBotscent } from 'botscent/next'
import { inspect, isVerified } from 'botscent/server'
async function challenge(request: NextRequest) {
if (!request.nextUrl.pathname.startsWith('/search')) return NextResponse.next()
if (request.cookies.has('challenge-passed')) return NextResponse.next()
if (isVerified(await inspect(request))) return NextResponse.next()
return NextResponse.redirect(new URL('/challenge', request.url))
}
export const proxy = withBotscent(challenge)A verified agent now reaches /search without the challenge. Other visitors without the cookie go to /challenge.
Without a name, isVerified is true for a Web Bot Auth signature that verified against a key in this release. It is also true for the platform's verified-bot field, such as Cloudflare's. That field says that some agent was verified, not which agent.
Warning: Do not let an agent through on a reason string, a bare
agent_nameor a page report. Anyone can send the headers that produce a name, and scripts on the page can forge a report. UseisVerifiedon the request's own verdict.
3. Let one agent through
Pass the agent name to isVerified. With a name, isVerified is true only when a verified signature names that agent. The platform's verified-bot field never passes a check with a name.
In Express, the request's own verdict is req.botscent. The Express adapter does not add botscent to Express's Request type, so this code reads it with a type assertion:
import express, { type NextFunction, type Request, type Response } from 'express'
import { botscent } from 'botscent/express'
import { isVerified, type Verdict } from 'botscent/server'
const app = express()
app.use(botscent())
// 60 requests a minute for each address. A verified ChatGPT has no limit.
const hits = new Map<string, number>()
setInterval(() => hits.clear(), 60_000)
function rateLimit(req: Request, res: Response, next: NextFunction) {
const verdict = (req as Request & { botscent?: Verdict }).botscent
if (isVerified(verdict, 'chatgpt')) return next()
const key = req.ip ?? ''
const count = (hits.get(key) ?? 0) + 1
hits.set(key, count)
if (count > 60) return res.status(429).send('Too many requests')
next()
}
app.use(rateLimit)
app.get('/search', (req, res) => {
res.json({ results: [] })
})
app.listen(3000)ChatGPT's verified requests now skip the limit. Every other request counts against it.
A hosted agent can sign its page loads and nothing else. Then its other requests carry no signature, and they count against the limit.
4. Keep the package current
Each release bundles the signers' keys, and the server half fetches no key. A key that a signer adds after the release gives signer.web-bot-auth.declared until you upgrade. A key that a signer removes, because it rotated or leaked, stays verified until you upgrade.
Upgrade to the latest release, and keep the exact version pinned:
npm install --save-exact botscent@latestThe release notes give the date of the key fetch, and the output-change report of the release. See Versions and stability.
Result
Agents with a verified signature skip the challenge, and a verified ChatGPT skips the rate limit. Every other visitor meets the same checks as before. To see why a signature did or did not verify, start the server with BOTSCENT_DEBUG=1.
Next steps
- The trust model: what a verified signature proves, and which verdicts are fit for access.
- Agents: which agents sign their requests, and the signer host of each.
- Server API (TypeScript): both forms of
isVerified.