Skip to content

About

Solve Cloudflare Turnstile in Rust: a tested example crate that gets a Cloudflare Turnstile token from the ZeroCaptcha REST API with ureq and serde_json, with typed errors, retries, idempotency keys and a deadline.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

 

History

1 Commit

Folders and files

Repository files navigation

Cloudflare Turnstile solver in Rust

CI

Solve Cloudflare Turnstile in Rust: a tested example crate that gets a Cloudflare Turnstile token from the ZeroCaptcha REST API with ureq and serde_json, with typed errors, retries, idempotency keys and a deadline.

Website · Docs · Quickstart · API reference · Pricing

What it does

The cloudflare_turnstile_solver crate gets a valid Cloudflare Turnstile token for a page you are allowed to automate, and its binary prints one. You give it the page's URL and the widget's sitekey; it creates a task on the ZeroCaptcha API, waits for it, and returns the token to submit as the browser would.

  • Three small dependencies: ureq (blocking HTTP with rustls), serde_json and uuid.
  • Safe to retry: every task is created with its own Idempotency-Key, so a retry after a lost reply returns the same task instead of paying for a second one. 429, 502, 503 and 504 are retried after the wait the API asks for.
  • Bounded: polls every 2 seconds, gives each request only the time left, and never runs past the timeout you pass.
  • Typed errors: a refusal or a failed task is an Error with the API's code, such as insufficient_funds or ERROR_CAPTCHA_UNSOLVABLE, and the request_id to quote to support.

Quickstart

  1. Create an account on the ZeroCaptcha website, create an API key on the dashboard and add funds (crypto, from $10). A task is charged only when it succeeds.

  2. Put the API's address and your key in your environment, never in your code:

    export ZEROCAPTCHA_API=https://api.zerocaptcha.io
    export ZEROCAPTCHA_KEY=zc_live_...
  3. Read the widget's data-sitekey, and its data-action and data-cdata if it sets them (the sitekey guide shows where else they hide, such as the options of turnstile.render()), then run:

    cargo run -- https://shop.example.com/login 0x4AAAAAAAB1cD2eF3gH4iJ5 login session-7f3a9c2e

    Many sites check the action and cData when they verify the token, so pass both whenever the widget sets them.

    It prints the token. Set PROXY_URL=http://user:[email protected]:8080 to solve through your own proxy.

Use it in your code

Add it from git, or copy src/lib.rs into your crate:

[dependencies]
cloudflare-turnstile-solver = { git = "https://github.com/ZeroCaptcha/cloudflare-turnstile-solver-rust" }
use std::time::Duration;
use cloudflare_turnstile_solver::{Client, Task};

let client = Client::new(std::env::var("ZEROCAPTCHA_API")?, std::env::var("ZEROCAPTCHA_KEY")?);
let task = Task {
    // The widget's data-action and data-cdata, or turnstile.render()'s action and cData options;
    // None for any the widget does not set.
    action: Some("login"),
    cdata: Some("session-7f3a9c2e"),
    // proxy: Some("http://user:[email protected]:8080"), // to solve through your own proxy
    ..Task::new("https://shop.example.com/login", "0x4AAAAAAAB1cD2eF3gH4iJ5")
};
match client.solve(&task, Duration::from_secs(180)) {
    Ok(token) => println!("{token}"),
    Err(error) => eprintln!("{} (request {:?})", error.code, error.request_id),
}

solve blocks its thread while it waits. In async code, run it with tokio::task::spawn_blocking, or port request to reqwest: the calls are plain HTTP.

Submit the token

The widget sends its token in the cf-turnstile-response form field, and the site checks it with Cloudflare's siteverify when the form arrives. Send yours the same way, straight after you get it:

let response = ureq::post("https://shop.example.com/login")
    .send_form(&[("email", "[email protected]"), ("cf-turnstile-response", &token)])?;

How it works

  1. POST /v1/tasks with the page, the sitekey, and the action and cData if the widget sets them. The task's price is held on your balance.
  2. GET /v1/tasks/{id} every 2 seconds while the task is queued or running.
  3. succeeded carries solution.token, and the held price is charged. failed or expired carries an errorCode, and the hold is released: nothing is charged.

The quickstart, the task lifecycle and the errors and retries guide have every detail.

Honest limits

  • A token works once, for 300 seconds. Get it just before you submit, and a new one for the next submission.
  • The action and cData must match the widget's. A token made without them can be refused by the site's siteverify check.
  • Proxies are http or https, with the port in the URL. SOCKS is not supported.
  • Only for sites you own or are allowed to automate. The Acceptable Use Policy applies to every task.

FAQ

Is there a crate on crates.io? Not yet: the official clients are for JavaScript, Python and Go. This crate is small enough to vendor, or use it from git.

What does a solve cost? The pricing page lists the price per 1,000 solved tasks. Only a task that succeeds is charged.

Why is my token refused by the site? Most often it was used twice, used after 300 seconds, or made without the widget's action or cData. The siteverify errors article explains each code.

How do I drive a browser from Rust? Read the sitekey from the page, solve it here, then set cf-turnstile-response in the page before you submit; the Playwright example shows the script to run, which works the same through any WebDriver or CDP crate.

Run the tests

cargo clippy --all-targets -- -D warnings
cargo test

The tests run the solver against a stand-in API on your machine (std::net): no key, no real task, nothing spent.

More from ZeroCaptcha

Licence

MIT: see LICENSE.

Disclaimer

ZeroCaptcha is an independent service, not affiliated with or endorsed by Cloudflare. Cloudflare and Turnstile are trademarks of Cloudflare, Inc. Use ZeroCaptcha only on sites you own or are allowed to automate, as the Acceptable Use Policy says; any site owner can opt out.

About

Solve Cloudflare Turnstile in Rust: a tested example crate that gets a Cloudflare Turnstile token from the ZeroCaptcha REST API with ureq and serde_json, with typed errors, retries, idempotency keys and a deadline.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages