Track AI crawlers on your server: GPTBot, ClaudeBot and the rest
To track GPTBot, ChatGPT-User, ClaudeBot and other AI crawlers on your own server, add our open-source package to your Next.js, Express or Fetch API app, or POST the hits from any language. It sends only AI bot visits, after the response, and never slows down or breaks a request.
npm install @picked-so/crawler-detectPicked is an AI visibility tool for SEO and marketing agencies, and B2B SaaS teams. Every day it asks ChatGPT, Claude, Gemini, Perplexity and Google's AI answers the prompts your buyers ask, records which brands and pages they name, and writes the article built to become the source they quote.
How it works
What does the package do?
@picked-so/crawler-detect matches each request's user agent against the AI bots Picked knows. When one matches, it sends the hit (host, path, user agent, IP, status and time) to your project's private ingest address. Every other request is ignored.
After the response
The send happens once your page is out, so a visitor never waits for it, and a failed send never touches the request.
Verified by IP
Anyone can claim to be
ChatGPT-User. Picked checks each hit's IP against the ranges OpenAI, Anthropic, Perplexity, Google and Apple publish, and by reverse DNS for Amazonbot, so a fake doesn't count when Verified only is on.Visits from AI answers (0.2 and later)
A page view whose referrer is an AI assistant, or whose
utm_sourcenames one (utm_source=chatgpt.com), is sent too: the page, the user agent and the referrer's origin (https://chatgpt.com, never the chat's address). No IP address, no cookie.referrals: falseturns it off.A secret address
The address carries your project's ingest key, so it belongs in server code and an environment variable, never in the browser. Disconnecting issues a new key and the old one stops working.
Set up
How do you add it?
Four steps. The AI crawlers guide in the docs has them next to the Cloudflare and Vercel connections.
- 1
Open Analytics
In your project, choose Your server. The dialog shows your address and the code for your stack.
- 2
Install the package
Add it from npm with the command at the top of this page, and set
PICKED_INGEST_URLto the address from the dialog. - 3
Add one line
The table below says where it goes for your framework.
- 4
Deploy
The first AI crawler visit shows up once a bot next opens a page.
Next.js
- In
proxy.ts(Next.js 16), ormiddleware.tson 13 to 15: calltrackAiCrawler(request, event)
- In
Express
- Before your routes:
app.use(aiCrawlers()). Behind a proxy, setapp.set("trust proxy", true)so the IP is the bot's
- Before your routes:
Workers, Hono, Bun, Deno, Remix, SvelteKit, Astro
- Anything that handles a Fetch API request: call
trackAiCrawlerwith the request, the response and the context
- Anything that handles a Fetch API request: call
Any other server
- POST up to 200 hits at once as JSON, from any language
| Your stack | Where the line goes |
|---|---|
| Next.js | In proxy.ts (Next.js 16), or middleware.ts on 13 to 15: call trackAiCrawler(request, event) |
| Express | Before your routes: app.use(aiCrawlers()). Behind a proxy, set app.set("trust proxy", true) so the IP is the bot's |
| Workers, Hono, Bun, Deno, Remix, SvelteKit, Astro | Anything that handles a Fetch API request: call trackAiCrawler with the request, the response and the context |
| Any other server | POST up to 200 hits at once as JSON, from any language |
Any language
What does the plain HTTP call look like?
Send a hit when the User-Agent matches one of the bots Picked knows (the dialog lists the pattern), as JSON to your address:
host- Your domain
path- The path requested
userAgent- The full user agent string
ip- The bot's address, not your proxy's
status- The response status you sent
at- When it happened, in milliseconds
country- Optional: a two-letter code, such as the one your CDN gives
| Field | What to send |
|---|---|
host | Your domain |
path | The path requested |
userAgent | The full user agent string |
ip | The bot's address, not your proxy's |
status | The response status you sent |
at | When it happened, in milliseconds |
country | Optional: a two-letter code, such as the one your CDN gives |
Limits
What should you know before adding it?
From the day you deploy
The package sends what happens after it runs. There is no history. Visits from AI answers need version 0.2 or later.
Your server sees the bot's IP only if the proxy passes it on
Behind a load balancer or a CDN, make sure the real client address reaches your code, or Picked can't verify it.
One source per project
A project reads its crawlers from your server, Cloudflare or Vercel, not two at once, or a visit counts twice.
A few bots stay unverified
Meta and some others publish no IP ranges, so their hits show, but not as verified.
The catalogue is ours
The package carries its own list of bots. When a new AI crawler appears, we add it and publish a new version, so update the package now and then.
When not to
When this won't work for you
Honest answer: sometimes this isn't worth your time.
A static site with no server code
A static host that runs nothing on the request can't send a hit. Use Cloudflare if it sits behind it, or Vercel if it runs there.
You don't want to touch the code
Cloudflare needs no code at all, only a sign-in.
You need history
Only Cloudflare reads the last 30 days back.
Sources
How we checked
- The package: @picked-so/crawler-detect on npm, version 0.1.0, and its open-source repository.
- What each bot is for: OpenAI, Anthropic and Perplexity, read September 29, 2026.
- What Picked does with a hit: the product as built on September 30, 2026. The dialog in Analytics has the current code for each stack.
- Setup steps: AI crawlers in the docs.
Questions
Frequently asked questions
Short answers, each one checked against the product as built or the docs we link to.
The AI crawlers Picked knows: `GPTBot`, `OAI-SearchBot` and `ChatGPT-User` from OpenAI, `ClaudeBot`, `Claude-SearchBot` and `Claude-User` from Anthropic, `PerplexityBot` and `Perplexity-User`, Google's AI crawlers, Applebot and others. The list is in the package.
No. The send happens after the response is out, and a failure never touches the request.
Yes, if you'd rather add the package to your `proxy.ts` than use a log drain. It only sends AI bot visits, so it doesn't carry the drain's volume.
Yes. The package and its code are public on GitHub under the Picked organisation.
Yes. It contains your project's ingest key. Keep it in an environment variable on the server, never in code the browser loads.
Behind a proxy or CDN, your app sees the proxy's address unless it is told to trust the forwarded header. Set the real client address, as in Express's `trust proxy` setting, or the hit can't be verified.
Find out what ChatGPT and Google AI say about you
Add your domain and the prompts your buyers ask. Unlimited seats for your whole team, and no promises we can't keep.