## TL;DR
When Cloudflare 403s your scraper even with perfect browser headers, the block is usually at the TLS layer: your HTTP client's handshake fingerprint (JA3) does not match any real browser. Switch to a client that impersonates a browser TLS fingerprint, such as curl-impersonate or a Playwright-driven browser, instead of tuning headers further.

## The error
```text
403 Forbidden
cf-mitigated: challenge
Request headers matched a real browser, but the TLS handshake did not.
JA3 fingerprint flagged as automated client.
```

## Fix it
1. Confirm the TLS hypothesis by fetching the same URL with curl-impersonate using a chrome profile. If it returns 200 while your Python client gets 403, the fingerprint is the block.
   Expected: Expected: curl-impersonate succeeds and your existing client fails on the identical URL and headers.
2. Replace the HTTP client in the scraper with one that mimics a browser TLS handshake. For Python, use a library built for fingerprint impersonation rather than plain httpx or requests.
   Expected: Expected: the new client returns 200 on URLs that 403d before, with no header changes.
3. For high-value intel targets, run the fetch inside a real headless browser (Playwright with the stealth plugin) so TLS, HTTP/2, and JS signals are all genuine.
   Expected: Expected: the browser fetch passes the same pages that blocked the raw HTTP client.
4. Keep a fallback path: when the TLS-impersonating client also gets challenged, degrade to the site's RSS or API instead of escalating.
   Expected: Expected: the pipeline logs the fallback and still delivers the intel without hammering the WAF.

## When to use
- Your scraper gets 403s from Cloudflare-protected sites despite realistic headers and cookies.
- You need to prove the block is TLS-fingerprint based before reworking the client.
- You run intel collection against hardened news or IR sites.

## When not to use
- The site presents a CAPTCHA or interactive challenge - that needs a different strategy than TLS impersonation.
- You are trying to defeat a block the site owner placed deliberately against scrapers - use their feed or API.
- The 403 happens on a plain HTTP site with no Cloudflare - then it is not a TLS fingerprint issue.

## Why it happens
Cloudflare inspects the TLS ClientHello (cipher suites, extensions, order) and computes a JA3 hash. Scripting HTTP clients have distinctive hashes that no real browser produces. When the hash is flagged, no header can save the request because the decision was made before headers were even read.

## Variant phrasings
### ja3 fingerprint blocked cloudflare scraping
Same failure and fix; some searchers phrase the query this way.
### cloudflare 403 tls fingerprint fix scraper
Same failure and fix; some searchers phrase the query this way.

## Edge cases
- JA3 hashes change with client library versions, so an upgrade can suddenly start or stop getting blocked.
- HTTP/3 (QUIC) fingerprints are a separate signal; some sites block on QUIC fingerprint while TLS looks fine.

## Provenance

Resolved from the public thread: https://vectle.com/posts/pst_7Y_74NRUS0afTnC1dIoPuw
