A local Cloudflare solver. Clear a protected URL in one call — on your own proxy — and keep scraping pure-request. No paid solver service; the browser only runs when a real challenge is actually served.
from solver import Solver
res = Solver().get("https://target.com", proxy="http://user:pass@host:port")
print(res.status, res.solved_by) # 200 direct | 200 browser
print(res.cf_clearance, res.user_agent)
html = res.textThree layers, so the expensive one (a browser) only runs when it has to:
- Fingerprint — a request with a browser-exact TLS + HTTP/2 fingerprint
(
curl_cffi). The passive JA3/HTTP2 block that accounts for most "Cloudflare 403" clears here in ~50 ms, with no browser. - Detect — classify the response: clean, Cloudflare JS/managed challenge, Turnstile, reCaptcha v2/v3, or hCaptcha.
- Harvest — only for a genuine challenge: a stealth Chromium (
patchright) runs locally, on the same proxy, executes Cloudflare's own JS, passes the interstitial, and returns thecf_clearancecookie + page. The browser lives in a subprocess (isolated event loop, hard timeout) and presents a consistent Windows fingerprint (UA + client-hints +navigator.platform).
The harvested cf_clearance + User-Agent are then handed back to curl_cffi, so
further requests on the same (host, proxy) are fast and pure-request.
cf_clearance is bound to the exit IP + User-Agent. The browser and the
request client must therefore share the same proxy, or the cookie is rejected.
You pass the proxy per call; the clearance is cached per (host, proxy).
pip install -r requirements.txt
patchright install chromiumfrom solver import Solver
solver = Solver() # clearance cached across calls
res = solver.get(url, proxy=proxy) # or solver.post(url, proxy=proxy, data=...)
res.status # HTTP status
res.solved_by # "direct" (fingerprint) | "browser" | "failed"
res.challenge # detected challenge kind, if any
res.cf_clearance # cookie value, when Cloudflare issues one
res.cookies # full cookie dict for reuse
res.user_agent # UA the clearance is bound to
res.text # response bodyRun the solver as a service — the caller passes a URL and their own proxy:
python server.py # http://localhost:8000
API_KEY=secret python server.py # require X-API-Key / Bearercurl localhost:8000/solve -H 'Content-Type: application/json' -d '{
"url": "https://target.com",
"proxy": "http://user:pass@host:port"
}'
# -> {"status":200,"solved_by":"browser","cf_clearance":"...","cookies":{...},
# "user_agent":"...","body":"<!doctype html>...","ok":true}| Guard | Handling |
|---|---|
| Passive JA3 / HTTP2 403 | Fingerprint layer — no browser |
| Cloudflare JS / managed challenge | Local browser harvest → cf_clearance reuse |
| Cloudflare Turnstile | Local browser harvest |
| reCaptcha v2 / v3, hCaptcha | Detected + reported (attach your own token source) |
- Everything runs on your machine — no third-party solver API.
- The fingerprint layer clears passive blocks outright; the browser layer clears the interactive Cloudflare challenge and hands off a reusable cookie.
- reCaptcha / hCaptcha are detected (site-key + type) but not solved here — pair the detection with your own token source.
Provided as is, for lawful automation, testing, and research. You are solely responsible for complying with the terms and laws of the sites you access.
MIT — see LICENSE.