cloudscraper-turnstile
cloudscraper-turnstile is a drop-in replacement for cloudscraper that actually solves Cloudflare Turnstile and the 5s "Just a moment..." interstitial. It subclasses requests.Session exactly like cloudscraper does, so you change one import line and your existing scraper keeps working, except now the requests that used to return 403 come back with the real page.
import cloudscraper_turnstile as cloudscraper
scraper = cloudscraper.create_scraper(api_key="pk_your_api_key")
resp = scraper.get("https://protected.example.com/") # Turnstile solved, real page returned
Why cloudscraper can't do this anymore
cloudscraper is a good tool for the challenge it was built for, but that challenge is mostly gone:
- It only ever solved the legacy IUAM challenge. cloudscraper works by reading Cloudflare's old "I'm Under Attack Mode" page, extracting the JavaScript math problem, and evaluating it. That is the entire mechanism.
- It has no JS engine and no browser. Modern Cloudflare managed challenges and Turnstile run real, obfuscated browser JavaScript and collect behavioral and fingerprint signals. There is nothing in the page for a regex-and-eval tool to solve, so the request stays on the challenge page and you get a
403, a503, or an endless "Just a moment..." loop. - Its own "Turnstile support" is a hand-off. cloudscraper never solved Turnstile itself. It added hooks to pass the challenge to a third-party paid CAPTCHA API and inject the returned token. Without one of those API keys configured, Turnstile support does nothing.
- The project is effectively unmaintained. Its last real release was in 2023. Cloudflare has shipped many detection changes since.
So on any site that switched to Turnstile or the managed 5s challenge (most of them, by now), plain cloudscraper returns the challenge HTML instead of your data. This package fills exactly that gap: it keeps cloudscraper's create_scraper / requests.Session shape and does the one thing cloudscraper cannot, by sending the challenge to a solver that runs a real browser.
Powered by Peak
This package uses Peak to solve Turnstile and the 5s challenge.
- Solve Cloudflare Turnstile & the 5s challenge in about a second
- Pay only for successful solves, from $1 / 1,000
- 1,000 free solves to start, no card.
→ Get your free API key · Docs · Pricing
Install
pip install cloudscraper-turnstile
The only dependency is requests (you already have it if you used cloudscraper).
Migration guide
There is no rewrite. cloudscraper-turnstile mirrors cloudscraper's public API: create_scraper(...) returns a CloudScraper object that subclasses requests.Session, so .get, .post, .request, .cookies, and .headers all behave the same.
Before
import cloudscraper
scraper = cloudscraper.create_scraper()
resp = scraper.get("https://protected.example.com/") # 403 / "Just a moment..." on Turnstile sites
After
import cloudscraper_turnstile as cloudscraper # the only line that changes
scraper = cloudscraper.create_scraper() # reads PEAK_API_KEY from env
resp = scraper.get("https://protected.example.com/") # Turnstile solved, real page returned
If you were already using cloudscraper's captcha-provider style, that keeps working too, so migration is a no-op:
scraper = cloudscraper.create_scraper(
captcha={"provider": "peak", "api_key": "pk_your_api_key"},
)
Existing cloudscraper kwargs (browser, delay, interpreter, allow_brotli, sess, ...) are accepted and never raise, so you do not have to touch the rest of your create_scraper call.
Quickstart
pip install cloudscraper-turnstile requests
export PEAK_API_KEY=pk_your_api_key # Windows: setx PEAK_API_KEY pk_your_api_key
import os
import cloudscraper_turnstile as cloudscraper
scraper = cloudscraper.create_scraper(api_key=os.environ["PEAK_API_KEY"])
# Use it exactly like requests / cloudscraper. A Turnstile or 5s challenge is
# detected, solved through Peak, and the request is retried transparently.
resp = scraper.get("https://protected.example.com/")
print(resp.status_code) # 200
print(resp.text) # the real page, not the challenge
# Cookies obtained during the solve (including cf_clearance) persist on the
# session for every later request.
resp2 = scraper.post(
"https://protected.example.com/api/search",
json={"q": "widgets"},
)
Where the key comes from
The API key is resolved in this order:
- Explicit
create_scraper(api_key="pk_...") create_scraper(captcha={"provider": "peak", "api_key": "pk_..."})PEAK_API_KEYenvironment variable
Using a proxy
Pass a proxy and it is forwarded to Peak, so the solve happens from the same IP as your crawl (this matters, since Cloudflare ties clearance to the requesting IP):
scraper = cloudscraper.create_scraper(
api_key="pk_your_api_key",
proxy="http://user:pass@ip:port",
)
If you set scraper.proxies the requests way instead, that proxy is used for the solve automatically.
Compatibility
| cloudscraper API | Status in cloudscraper-turnstile |
|---|---|
create_scraper(**kwargs) |
Supported. Returns a requests.Session subclass. |
Returns a requests.Session |
Yes. CloudScraper(requests.Session). |
.get / .post / .put / .delete / .request |
Supported (inherited from requests.Session). |
.cookies, .headers, .proxies, .auth |
Supported (session state persists across the solve retry). |
sess= (adopt an existing Session) |
Supported (cookies, headers, proxies, auth carried over). |
captcha={"provider": ..., "api_key": ...} |
Supported. provider: "peak" is native; the api_key is read regardless. |
browser=, delay=, interpreter=, allow_brotli=, debug= |
Accepted, never raise. debug=True prints solve steps. |
| Legacy IUAM JS-math challenge | Handled by Cloudflare's own retry path; not the focus. |
| Cloudflare Turnstile | Solved via Peak (turnstiletask). |
| Cloudflare 5s "Just a moment" / managed | Solved via Peak (cloudflare5stask). |
cloudscraper vs cloudscraper-turnstile
| Challenge / trait | cloudscraper | cloudscraper-turnstile |
|---|---|---|
| Legacy IUAM JS-math | Yes | Yes |
| Cloudflare Turnstile | No (hands off to a paid API you must wire up) | Yes |
| 5s "Just a moment" interstitial | No (no JS engine) | Yes |
| Managed challenge | No | Yes |
requests.Session drop-in |
Yes | Yes |
| Actively maintained | No (last release 2023) | Yes |
FAQ
Why is cloudscraper not working in 2026?
Because the site moved to Cloudflare Turnstile or the managed 5s challenge. cloudscraper only solves the old IUAM JavaScript-math page and has no JS engine, so on a modern challenge it returns the challenge HTML (usually 403, 503, or a "Just a moment..." page) instead of your data. Its last release was in 2023. cloudscraper-turnstile detects those challenges and solves them through Peak.
What is a good cloudscraper alternative for Turnstile?
cloudscraper-turnstile is built to be that alternative: same create_scraper API, same requests.Session object, but it actually solves Turnstile. Change the import, add a Peak API key, and your existing code runs.
How do I fix cloudscraper 403 Forbidden?
A 403 from a Cloudflare-protected site usually means you received the challenge page, not a real block. Confirm the body contains cf-turnstile, Just a moment, or cf_chl_opt. If so, switch to import cloudscraper_turnstile as cloudscraper, set PEAK_API_KEY, and the challenge is solved and the request retried automatically. If the proxy/IP that gets challenged is not your default one, pass proxy= so the solve matches.
Does cloudscraper solve Cloudflare Turnstile?
Not on its own. cloudscraper never solved Turnstile itself; it only added hooks to pass the token from an external paid CAPTCHA service. cloudscraper-turnstile does the solve for you through Peak and injects the cf-turnstile-response token, so there is nothing else to wire up.
Do I need a real browser or Selenium?
No. This is a pure requests-based client. The browser work happens on Peak's side; you send the sitekey and URL and get a token (or a cf_clearance cookie for the 5s challenge) back.
Does it handle the 5s "Just a moment" page too?
Yes. When the response is the interstitial rather than a Turnstile widget, the package calls Peak's cloudflare5stask, sets the returned cf_clearance cookie (and user-agent) on the session, and re-requests the original URL.
Will it loop forever if a solve fails?
No. Solving is capped by max_solve_attempts (default 3). After that the last response is returned as-is so you can inspect it.
Legitimate use
Use this for automation, QA, monitoring, and scraping public data you are allowed to access. Respect each target's Terms of Service and robots.txt, rate-limit yourself, and do not use it for credential stuffing or to access data you have no right to. You are responsible for how you use it.
Links
License
MIT. See LICENSE.
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file cloudscraper_turnstile-0.1.0.tar.gz.
File metadata
- Download URL: cloudscraper_turnstile-0.1.0.tar.gz
- Upload date:
- Size: 454.7 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
986a3c6df134262886cb59132a1bee728be73824a9f25179299400e6ce3854e4
|
|
| MD5 |
5370db35fbdd82ebe0484f9bb8b6b5fd
|
|
| BLAKE2b-256 |
40b65b961fc55dd40b56db95a46ca99604dd2462b988b739f7588f50f32798ef
|
File details
Details for the file cloudscraper_turnstile-0.1.0-py3-none-any.whl.
File metadata
- Download URL: cloudscraper_turnstile-0.1.0-py3-none-any.whl
- Upload date:
- Size: 13.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via:
twine/7.0.0 CPython/3.12.0
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c5a1ef2a987c5cc789f3c888e76d4c3f9f60bdb64d24e8018e5f8ed986ce23e3
|
|
| MD5 |
0ea6ab055ce4b440fea6de6fc3e5b556
|
|
| BLAKE2b-256 |
a2776aba1344cd1e19c081d61a0266a2e1233a570b3b1bbc3be5b55d36ab2770
|