nodriver-turnstile
Solve Cloudflare Turnstile inside a nodriver browser. Read the sitekey off the page, get a token, drop it into the widget. Three lines, and it works with the real Chrome nodriver already drives.
nodriver gets you past most bot checks on its own. It's a genuine Chrome with no CDP fingerprints. What it can't do is answer a Turnstile challenge, because that's a token the widget mints server-side, not something a browser flag turns off. This library fills that one gap: it hands the (url, sitekey) to a solver and puts the returned token back where the page expects it. Everything else (cookies, TLS, the session) stays in your nodriver browser.
Install
pip install nodriver-turnstile
Use it
import asyncio, os
import nodriver as uc
from nodriver_turnstile import solve_turnstile
async def main():
browser = await uc.start()
tab = await browser.get("https://site-with-turnstile.example/login")
result = await solve_turnstile(tab, os.environ["PEAK_API_KEY"])
print(result.elapsed, result.cost) # token is already in the page
await (await tab.select("button[type=submit]")).click()
asyncio.run(main())
That's the whole thing. solve_turnstile finds the sitekey (explicit-render div, implicit div, or the managed iframe), requests a token, fills every cf-turnstile-response field, and fires the widget's callback if the page registered one.
Matching the exit IP
Turnstile scores the IP that submits the token. If your nodriver browser runs behind a proxy, give the solver the same one so the token and the request line up:
result = await solve_turnstile(tab, api_key, proxy="http://user:pass@host:port")
Leave proxy off and the token is minted from a clean pool instead. That's fine for a lot of sites; test it against yours.
Lower-level pieces
You don't have to hand it the tab. Pull the sitekey and token yourself when you want control over injection:
from nodriver_turnstile import read_sitekey, request_token
sitekey = await read_sitekey(tab)
res = await request_token(api_key, url="https://target.example/", sitekey=sitekey)
await tab.evaluate(f'document.querySelector("[name=cf-turnstile-response]").value = {res.token!r}')
Getting a key
solve_turnstile needs an API key for the solver it calls: Peak. Turnstile solves come back in about a second, you pay only for the ones that land, and the free tier is enough to wire this up and test it end to end. Peak also solves the Cloudflare 5-second challenge (task_type: "cloudflare5stask"); this package focuses on Turnstile.
$0.90 per 1,000 Turnstile solves, down to $0.35 at volume · pay only on success · 1,000 free solves · peak.fo
Related
Same pattern for other stacks: playwright-turnstile · selenium-turnstile · camoufox-turnstile · scrapling-turnstile · crawlee-turnstile · drissionpage-turnstile · puppeteer-extra-plugin-turnstile · scrapy-turnstile · turnstile-curl · cloudscraper-turnstile · crawl4ai-turnstile. Full list in awesome-turnstile-solvers.
Notes
Use this on sites and accounts you're allowed to automate. Respect each target's Terms of Service and robots.txt. This is tooling for legitimate automation, testing, and public-data scraping; nothing here helps with credential stuffing or abuse. Not affiliated with Cloudflare.
License
MIT
Metadata
Release files for nodriver-turnstile 0.1.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| nodriver_turnstile-0.1.0.tar.gz | 6.9 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| nodriver_turnstile-0.1.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 13.5 kB
Release files / nodriver_turnstile-0.1.0.tar.gz
| Download URL | nodriver_turnstile-0.1.0.tar.gz |
|---|---|
| Size | 6.9 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9961ced5c67be4fb6bc5206438748b9f5c8ccd5426fbf143d68890bc5577fcf7
|
|
BLAKE2b-256 checksum How to use checksums |
6f5fb249cede91dff4ddd1f51c7f2b6b206a5a8cbde2e95a5102de0d8f6d0b3d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.0
|
Release files / nodriver_turnstile-0.1.0-py3-none-any.whl
| Download URL | nodriver_turnstile-0.1.0-py3-none-any.whl |
|---|---|
| Size | 6.6 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
8aacc2b30f609400a96860f5e7683c56958cb30a24037150eba8b58a6b21768b
|
|
BLAKE2b-256 checksum How to use checksums |
96cba214fc90d9b0d8472a0a896067076b1cc02b2ba648ac90a3b47be3832dfc
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/7.0.0 CPython/3.12.0
|