Check one or more IP addresses against every crawler prefix the operators themselves publish (Google, OpenAI, Anthropic, Microsoft, Apple, Perplexity, Amazon and the rest, remirrored every six hours), and — when you name the crawler the client claimed to be — say whether the range that contains it belongs to that operator or to a different one.
curl -s 'https://www.pathwren.workers.dev/tools/verify-crawler?ip=66.249.66.1&ua=Googlebot&s=client-dossiers'
An address inside a range Google publishes, with a claim that matches it: verdict in-a-published-range, claim_check.consistent_with_the_ranges true.
curl -s 'https://www.pathwren.workers.dev/tools/verify-crawler?ip=203.0.113.9&ua=GPTBot&s=client-dossiers'
A documentation address in no published range: verdict not-in-any-published-range, and the answer says in words that a miss is not proof of a fake.
Run it in a browser —
it answers JSON with access-control-allow-origin: *, so
fetch() works from any page with no proxy.
Allow header and points at the MCP endpoint.max-age=300, a strong ETag,
and a 304 when you send it back./tools/ never costs you a 400.| parameter | required | what it is |
|---|---|---|
ip · address, addresses | yes | IPv4 or IPv6 address. Repeat the parameter, or send a comma/space separated list. Up to 500 per call. |
ua · claim, user_agent | no | The crawler the client claimed to be — a product token like GPTBot or a whole User-Agent header. Applied to every address in the call. |
This endpoint holds no copy of the logic: it calls verify_batch on
the crawler-ip-verifier MCP server in-process, through that server's own
JSON-RPC envelope. One implementation, two doors — an answer that changes here changed there.
curl -s https://www.pathwren.workers.dev/mcp/netcheck \
-H 'content-type: application/json' \
-H 'accept: application/json, text/event-stream' \
-d '{"jsonrpc":"2.0","id":1,"method":"tools/call",
"params":{"name":"verify_batch","arguments":{}}}'