turnstile-curl
turnstile-curl is a curl_cffi companion that solves Cloudflare Turnstile without a browser, so a curl_cffi request that hits a Turnstile wall comes back with a real token instead of a 403.
Why
curl_cffi forges a browser's TLS/JA3 handshake perfectly, which is exactly why people reach for it. But it has no JavaScript engine. Cloudflare Turnstile is a JS widget, so a managed or interactive challenge hands curl_cffi an interstitial HTML page or a 403, and there is nothing in-process that can run the challenge. This is the "curl_cffi cloudflare blocked" wall: the handshake is right, the request still fails.
turnstile-curl reads the Turnstile sitekey straight out of the returned markup, sends it to Peak, and gives you back the cf-turnstile-response token. curl_cffi still does the fetching, so you keep its speed and fingerprint. When your setup gets blocked, drop in a Peak API key and it just works.
Powered by Peak
This package uses Peak to solve Turnstile.
- Solve Cloudflare Turnstile & the 5s challenge in about a second
- $0.90 per 1,000 successful Turnstile solves, down to $0.35 at volume
- 1,000 free solves to start, no card.
→ Get your free API key · Docs · Pricing
Install
pip install turnstile-curl curl_cffi
curl_cffi is the transport you fetch pages with. It is an optional dependency here so the library imports cleanly without it; install it to actually fetch.
Quickstart
import os
from turnstile_curl import solve
# Free key at https://peak.fo.?utm_source=github&utm_medium=readme&utm_campaign=packages&utm_content=turnstile-curl Reads PEAK_API_KEY by default.
os.environ.setdefault("PEAK_API_KEY", "pk_your_api_key")
# Fetch the protected page with curl_cffi, read the sitekey, solve via Peak.
token = solve("https://your-target.example/login")
print(token) # -> "0.AgAAA..." (the cf-turnstile-response value)
Send token as the cf-turnstile-response form field (or into the widget callback) on your next request.
Session: solve and resubmit in one shot
TurnstileSession wraps a curl_cffi session and keeps the same browser fingerprint through the whole flow.
from turnstile_curl import TurnstileSession
with TurnstileSession(api_key="pk_your_api_key", impersonate="chrome") as s:
# Just the token:
token = s.solve("https://your-target.example/login")
# Or solve + resubmit the form with the token injected, and keep the
# authenticated response and cookies on the session:
resp = s.solve_and_submit(
"https://your-target.example/login",
submit_url="https://your-target.example/verify",
data={"username": "demo", "password": "demo"},
)
print(resp.status_code)
Already have the sitekey
Skip the fetch and call Peak directly.
from turnstile_curl import PeakClient
peak = PeakClient(api_key="pk_your_api_key")
token = peak.solve_turnstile(
sitekey="0x4AAAAAAADnPIDROrmt1Wwj",
url="https://your-target.example/login",
# proxy="http://user:pass@ip:port", # optional
)
Proxies
Pass proxy="http://user:pass@ip:port" to TurnstileSession, solve(), or PeakClient.solve_turnstile(). The same proxy is used for the page fetch and forwarded to Peak so the token is minted from the IP you will use it on.
Earn with your app ID
Pass your Peak app id and you earn 5% of every solve this tool makes, paid as solve credit. It is optional and does not affect solve success or speed; it only tells Peak which app to credit. Create an app id at peak.fo/dashboard/developer, details at peak.fo/earn.
from turnstile_curl import solve
# Pass app_id=, or set the PEAK_APP_ID env var instead.
token = solve("https://your-target.example/login", app_id="app_your_app_id")
app_id works the same on TurnstileSession(...) and PeakClient(...), and falls back to PEAK_APP_ID when omitted.
How it works
- curl_cffi fetches the page with a forged browser TLS/JA3 fingerprint.
- turnstile-curl parses the sitekey (and
cData/action/pagedatawhen present) from thedata-sitekeycontainer or aturnstile.render(...)call. - It calls
POST https://api.peak.fo/solvewithtask_type: "turnstiletask", the sitekey, and the URL. - Peak returns the token; you resubmit the form with it as
cf-turnstile-response.
Peak also solves the Cloudflare 5s challenge (task_type: "cloudflare5stask"); this package focuses on Turnstile.
API
solve(url, *, api_key=None, impersonate="chrome", proxy=None, app_id=None) -> str— one-shot fetch + solve, returns the token.TurnstileSession(api_key=None, *, impersonate="chrome", proxy=None, app_id=None)—.get(),.solve(url),.detect_challenge(url),.solve_and_submit(url, ...).PeakClient(api_key=None, *, app_id=None)—.solve(challenge),.solve_turnstile(sitekey, url, ...).parse_challenge(html, url)/find_sitekey(html)— the extractor, if you fetch pages yourself.
The API key is read from PEAK_API_KEY unless you pass api_key=. The optional revenue-share app id is read from PEAK_APP_ID unless you pass app_id=.
Legitimate use
For automation, QA, and scraping public data you are allowed to access. Respect each target's Terms of Service and robots.txt, and rate-limit yourself. Do not use this for credential stuffing or to access data you have no right to.
License
MIT — see LICENSE.
Metadata
Release files for turnstile-curl 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| turnstile_curl-0.2.1.tar.gz | 13.0 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| turnstile_curl-0.2.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 25.4 kB
Release files / turnstile_curl-0.2.1.tar.gz
| Download URL | turnstile_curl-0.2.1.tar.gz |
|---|---|
| Size | 13.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7123720e602f1ec6396585f424a79e07878d5dbfbc677fa6d1526986ce45cf40
|
|
BLAKE2b-256 checksum How to use checksums |
72ef5011b71ac9e8c1becaaf922b7086d47cbdf04ef3103ffa3dcd41527a011f
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.0
|
Release files / turnstile_curl-0.2.1-py3-none-any.whl
| Download URL | turnstile_curl-0.2.1-py3-none-any.whl |
|---|---|
| Size | 12.4 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
12ea1e7bff5f9daa15ae906dd8258f14316f922eda8643ae435495f4fd262d8b
|
|
BLAKE2b-256 checksum How to use checksums |
254a10168f28a8e39bd1da3866b0054df2f5bd8f77d0370ecfdd8a68c08ebf71
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.0
|