Rightshold™ Sign up

Answers · AI crawlers

How do I detect AI agents and scrapers that send an ordinary Chrome user agent instead of declaring themselves?

Last updated

TL;DR: You can't catch them from the user-agent string, because it is the part they copy. Score each request on signals that are harder to fake together: a TLS fingerprint (JA3/JA4) that doesn't match the browser the user-agent claims, missing or inconsistent fetch-metadata headers (Sec-Fetch-Mode, Sec-Fetch-Dest) on HTTPS page navigations, automation flags in the page (navigator.webdriver is true when Chrome runs with --enable-automation or --headless), and behaviour no person produces, such as HTML with no CSS or JS loads, many pages per second, or the same few URLs fetched from rotating cloud IPs. Combine them into a score and challenge on sensitive paths instead of blocking on one signal. Cloudflare reported on August 4, 2025 that Perplexity, when blocked under its declared names, also fetched with a generic Chrome-on-macOS user agent from IPs outside its published ranges, and that Cloudflare caught this with machine learning and network signals, not names. Give agents that want access a better lane: a verified Web Bot Auth signature. gate_check verifies those signatures for free; it can't classify unsigned traffic.

What should I check, step by step?

1. Stop treating the user-agent as identity. A Chrome string from a cloud network tells you only what the client chose to send. Matching a declared bot name to its published IP list is a separate job (see the spoofed ChatGPT-User page); this page is about traffic that declares nothing.

  1. Compare the TLS fingerprint with the claimed browser. Cloudflare's docs describe JA3/JA4 as identifying TLS clients by how they start connections, so a script library or headless stack can carry a Chrome user-agent but a non-Chrome fingerprint. On Cloudflare the field is cf.bot_management.ja4 (Enterprise Bot Management only); elsewhere, FoxIO's open-source JA4 suite can compute it at your proxy.
  2. Check fetch metadata on page loads. A browser navigating to an HTTPS page sends Sec-Fetch-Mode: navigate and Sec-Fetch-Dest: document (MDN). A request that claims a current Chrome and arrives with none of these on a top-level page is worth scoring as automated. It is a signal, not proof: a proxy can strip headers and a script can add them.
  3. Read automation flags in the page if you run JavaScript checks. MDN documents that navigator.webdriver is true in Chrome when --enable-automation or --headless is used, or --remote-debugging-port is 0. Stealth tooling can patch this, so a false value doesn't clear anyone.
  4. Score behaviour from your own logs: page HTML without the stylesheet, script and image requests a browser makes; many distinct pages from one IP inside a second; the same handful of URLs fetched by many datacenter IPs; robots.txt never fetched; no cookies carried between pages.
  5. Combine signals into one score and act by path. Challenge (not block) on login, checkout, search and API routes; leave cacheable public pages lighter. On Cloudflare, bot scores run 1 to 99, where 1 means quite certainly automated; granular scores need Enterprise Bot Management, and Pro and higher plans see bot groupings.
  6. Offer a verified lane. Agents and remote-browser platforms that sign requests with Web Bot Auth can be told apart from anonymous automation; on Cloudflare, cf.bot_management.signed_agent marks a known agent that self-identifies with Web Bot Auth. Let verified agents skip the challenge on the paths you choose.
  7. Review weekly what you challenged and who complained. A rule that blocks real people on a corporate proxy (for example one that strips the user-agent) costs more than the scraper it stopped.

Why don't published IP lists catch AI agents that pretend to be Chrome?

Published IP lists and reverse-DNS checks answer one question: is this request that claims to be GPTBot or Googlebot really from that operator? They say nothing about a request that claims to be Chrome on Windows. Undeclared automation is designed to fall into your human bucket.

Which signals reveal an AI agent or scraper sending a normal Chrome user agent?

TLS: Cloudflare's JA3/JA4 docs say each client type has distinct connection characteristics, so the fingerprint is a stable identifier across destinations; JA4 sorts ClientHello extensions to reduce noise from modern browsers. Cloudflare's JA4 Signals add last-hour aggregates per fingerprint across its network, such as browser_ratio_1h (share of requests from browser user agents) and uas_rank_1h (how many distinct user agents share the fingerprint). A fingerprint seen with many different user agents is a classic sign of a tool rotating strings.

Should I block or challenge suspected AI agents that pose as browsers?

Treat the score as a reason to ask for more, not a verdict. A managed challenge on sensitive paths stops most headless traffic while a person clicks through; hard blocks belong on clear abuse such as credential stuffing.

How do I ask Rightshold about this (free, no key)?

Add the MCP server https://www.rightshold.com/mcp to Claude, Cursor, ChatGPT, Grok or VS Code, then ask: “This request says it's Chrome but my bot score says automated. It carries Signature headers. Does it verify as a Web Bot Auth agent, so I can let it skip the challenge instead of treating it as a disguised scraper?”

One-click setup

{
  "tool": "gate_check",
  "arguments": {
    "policy": {
      "require_web_bot_auth": true
    },
    "request": {
      "method": "GET",
      "url": "<the requested URL>",
      "headers": {
        "user-agent": "<as received>",
        "signature-agent": "<as received>",
        "signature-input": "<as received>",
        "signature": "<as received>"
      }
    }
  }
}

Rightshold checks Web Bot Auth signatures and gate policies you send it. It doesn't sit in front of your site, compute JA3/JA4 fingerprints, run JavaScript challenges, score bots or block traffic, and it can't identify requests that carry no signature. Not legal advice.

What are the sources?

Related

Not legal advice. JSON · Markdown · All answers

Get a free API key in one call

No card and no email needed. 100 free credits; the license and policy checks stay free without a key.

curl -s -X POST https://www.rightshold.com/v1/accounts/signup -H "Content-Type: application/json" -d '{"accept_terms":true}'
export RIGHTSHOLD_API_KEY=rs_...   # the api_key from the reply (shown once)
curl -s https://www.rightshold.com/v1/licenses/check -H "Authorization: Bearer $RIGHTSHOLD_API_KEY" \
  -H "Content-Type: application/json" -d '{"license":"MIT","intended_use":{"commercial_use":true}}'