You name the sites your collector needs, one public URL per site (the root by default), and the User-Agent it sends. Within 48 hours of agreed scope you get a dated reading, readable and as JSON, with response metadata, headers, hashes and diagnostic evidence retained.
What is probed, exactly: requests sent by us, from our network, carrying by default your User-Agent string followed by our own reading token, which names us and the name you ask us to put on the reading, so the site sees both whose agent this is and who is asking. We send your string on its own only with your written authorisation, and our own bot's string if you give us none. For the signed condition, our own signing key and published directory; recognition by the destination is not assumed. Three attempts per condition, plus one control request per site from a generic, honestly labelled HTTP client (never a browser disguise), which helps tell a refusal of the User-Agent we sent from a refusal of any non-browser client at our address; one request is a clue, not a measurement. A User-Agent is not your egress, session or signing identity, so this is a reading of how the sites treat an identified request shaped like yours, not a reproduction of your bot. The instrument is published and needs only Python 3.7 or later, with no other packages; run from your side it makes the unsigned and control requests, since the signing key stays with us. If you run the same scope from the network your agent uses, we set the two readings side by side at no extra charge; refusals by address range are common and cannot be seen from our side alone.
A signed identity for one collector, to the current Cloudflare profile: RFC 9421 Ed25519 request signatures, a signed key directory on infrastructure that can set response headers (a free Worker on your own account), and the directory application prepared for you to submit.
Scope of the pilot: one Python collector, one directory deployment on your own Cloudflare account, integration done in your environment with the repository and account access we agree up front, and a handoff with the test evidence. You generate and keep the private key. Other languages are quoted separately. Retesting after Cloudflare's decision is included once; ongoing support is not.
In our 15 September 2026 reading of 24 sites, our parser found no root disallow for our unnamed identified bot at 20. Four of those sites returned HTTP 403 on every signed and unsigned attempt; a fifth returned 403 intermittently. A sixth produced transport failures, whose cause we did not identify. Signed and unsigned status sequences matched in this run. We did not establish that any site recognized our signing key. These are observations from our network, not a test of a customer's collector.
One row from that reading, as delivered under the method of that day. When we read this site again on 18 September 2026, robots.txt itself was refused (403 with a challenge header), and the instrument of that afternoon still requested the page, which was wrong. Since version 3, later the same day, a site that refuses us at robots.txt is not asked for the page, and the refusal at robots.txt is the recorded observation.
| Site | Declared policy | Observed, unsigned (3) | Observed, signed (3) | Next step |
|---|---|---|---|---|
| www.npmjs.com | robots.txt: no root disallow for our agent, for unnamed agents, or for GPTBot and ClaudeBot | 403, 403, 403 with cf-mitigated: challenge, server: cloudflare | 403, 403, 403, same headers | The npm registry publishes a documented API; the challenge is on the website, and the reading says which one your collector needs |
| Column | What it contains |
|---|---|
| Declared policy | robots.txt verdicts for the exact URL, for your agent, for our tokens, for unnamed agents, and for GPTBot and ClaudeBot; the file's fetch status and hash |
| Observed response | Status per attempt, challenge headers such as cf-mitigated, the reported server header as a clue and never as proof of cause, whether the final URL differed from the requested URL, and transport failures kept as their own class |
| Signed observation | The same requests carrying a Web Bot Auth signature, reported beside the unsigned ones, with what can and cannot be concluded from one key on one day |
| Next step | Per refused site: who acts, what they need and the test that shows it worked; a documented route where we found one, otherwise the site owner |
| Substitutes | Where BotWitness, StackScan or the site's own documentation already answers the question, stated plainly |
robots.txt governs: if it disallows your agent or ours, or is refused to us, or cannot be reached, we do not request the page and the row says so. Honest User-Agents only: the identified request and one labelled control, no evasion, no challenge solving, no proxies. A refusal is reported with the evidence that produced it, and no server header is presented as proof of cause. A null result is reported as null. We do not scrape sites whose terms we have read as barring automated access.