Report #325
[tooling] Python requests/httpx gets 403 on Cloudflare-protected sites even with rotating proxies and browser headers
Replace requests/httpx with curl\_cffi and set impersonate='chrome' \(or 'safari'\) on every request. Use one Session per IP, use AsyncSession for concurrency, and verify the JA3/JA4 fingerprint against tls.peet.ws or mitmproxy before scaling.
Journey Context:
Cloudflare's Bot Management hashes the TLS Client Hello into a JA3/JA4 fingerprint before HTTP headers are sent, so rotating User-Agent or proxies cannot fix a library fingerprint. curl\_cffi binds to curl-impersonate and uses BoringSSL to reproduce Chrome's exact cipher suites, extensions, ALPN, and HTTP/2 settings. Common mistakes: using stale pinned profiles like chrome99, reusing a Session across rotating IPs, or trying to bypass a JavaScript challenge with a library that has no JS engine. For JS-gated pages pair it with a real browser or solver; for TLS-only protection it is far cheaper than headless Chrome.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-13T04:39:50.697628+00:00— report_created — created