How to Solve Cloudflare Turnstile: Complete Developer Guide
Step-by-step guide to solving Cloudflare Turnstile CAPTCHAs programmatically. Covers TurnstileTaskProxyless, finding site keys, handling tokens, and integration code examples.
Solving Cloudflare Turnstile programmatically is one of the most common requirements for developers building web scrapers, automation tools, and data pipelines. Unlike traditional CAPTCHAs that present image grids or distorted text, Turnstile operates almost entirely in the background, making it friendlier to real users but still a barrier for automated systems. This guide walks through every step of the process, from understanding how Turnstile works to extracting site keys, submitting tasks to a solver API, and integrating tokens into your application.
What Is Cloudflare Turnstile?
Cloudflare Turnstile is a free, privacy-focused CAPTCHA replacement launched in 2022. It aims to verify that a visitor is human without forcing them to solve visual puzzles. When a user loads a page with Turnstile embedded, the widget runs a series of lightweight browser challenges in the background — checking browser APIs, execution timing, and environment signals. If the checks pass, the widget issues a cf-turnstile-response token that the server validates through Cloudflare’s siteverify endpoint.
Turnstile ships in three modes:
- Managed — Cloudflare decides whether to show an interactive challenge or pass silently.
- Non-interactive — The widget always runs in the background with no user interaction.
- Invisible — Same as non-interactive, but the widget is completely hidden on the page.
From a solving perspective, all three modes produce the same output: a token string that the server expects in the form submission or API call.
For a broader look at how Turnstile compares to Google’s offering, see our Turnstile vs reCAPTCHA comparison.
How Turnstile Differs from Traditional CAPTCHAs
Traditional CAPTCHAs like reCAPTCHA v2 rely on explicit user interaction: clicking checkboxes, selecting images of traffic lights, or typing distorted text. Turnstile takes a different approach entirely. It evaluates the browser environment and behavioral signals without requiring the user to do anything visible. This means:
- No image puzzles — There are no grids to click, so traditional OCR or image classification techniques do not apply.
- Token-based verification — The output is always a string token, not a solved image response.
- Faster for real users — Turnstile typically resolves in under a second for legitimate browsers.
- Harder to fingerprint — Because there is no visual component, the challenge logic is obfuscated inside Cloudflare’s JavaScript bundle.
The implication for developers is clear: you cannot “solve” Turnstile by analyzing images. Instead, you need a service that can execute the browser challenges and return a valid token.
Finding the Turnstile Site Key
Before you can submit a solving task, you need the site key (also called the sitekey). This is a public identifier that tells Cloudflare which site the widget belongs to. There are several ways to find it.
Method 1: Search the Page Source
The most direct approach is to view the page source and search for the Turnstile container. Look for a div with the cf-turnstile class:
<div class="cf-turnstile" data-sitekey="0x4AAAAAAABS7vwvV6VFfMcD"></div>
The data-sitekey attribute contains the value you need.
Method 2: Search for the Render Call
If the widget is rendered programmatically, search the page source or loaded scripts for turnstile.render:
turnstile.render('#myWidget', {
sitekey: '0x4AAAAAAABS7vwvV6VFfMcD',
callback: function(token) {
document.getElementById('cf-turnstile-response').value = token;
}
});
Method 3: Inspect Network Requests
Open your browser’s developer tools, navigate to the Network tab, and filter for requests to challenges.cloudflare.com. The request URL or parameters will contain the site key.
Method 4: Check the Rendered iframe
After the widget loads, inspect the iframe element. The src URL contains the site key as a query parameter:
https://challenges.cloudflare.com/cdn-cgi/challenge-platform/h/b/turnstile/if/ov2/av0/rcv0/0x4AAAAAAABS7vwvV6VFfMcD/...
Optional: Action and cData Parameters
Some Turnstile implementations use additional parameters:
- action — A string that categorizes the type of challenge (e.g.,
login,signup). The server may validate that the token was generated with the expected action. - cData — Custom data attached to the challenge. Like action, it is bound to the token and verified server-side.
Check the data-action and data-cdata attributes on the widget element, or the corresponding properties in the turnstile.render() call. If present, you must include them in your solver request.
The TurnstileTaskProxyless Task Type
CAPTCHA solver APIs use task types to distinguish between different challenge formats. For Cloudflare Turnstile, the standard task type is TurnstileTaskProxyless. This tells the solver to handle the Turnstile challenge without requiring you to supply a proxy — the solver manages the browser environment internally.
Here is what a typical request body looks like:
{
"clientKey": "YOUR_UCAPTCHA_API_KEY",
"task": {
"type": "TurnstileTaskProxyless",
"websiteURL": "https://example.com/login",
"websiteKey": "0x4AAAAAAABS7vwvV6VFfMcD",
"metadata": {
"action": "login",
"cdata": "session_abc123"
}
}
}
The metadata object is optional. Only include action and cdata if the target site sets them.
If you need to route the request through your own proxy (for example, to match the IP address of your session), use TurnstileTask instead and supply the proxy configuration. For most use cases, TurnstileTaskProxyless is sufficient and faster.
Step-by-Step Solving Workflow
The solving process follows two API calls:
- Create the task — Send the site key and page URL. Receive a task ID.
- Poll for the result — Check the task status until the token is ready.
Here is the full workflow:
Step 1: Create the Task
POST https://api.ucaptcha.net/createTask
Send the site URL, site key, and task type. The API returns a taskId you will use to check the result.
Step 2: Poll for the Result
POST https://api.ucaptcha.net/getTaskResult
Send the taskId. The response will have a status field that is either processing or ready. When the status is ready, the solution object contains your token.
Step 3: Use the Token
Submit the cf-turnstile-response token to the target server. This is typically done by including it as a form field or request body parameter.
The token has a limited lifespan — usually around 300 seconds. Use it promptly after receiving it.
Python Implementation
Here is a complete Python example using the requests library:
import time
import requests
API_KEY = "YOUR_UCAPTCHA_API_KEY"
BASE_URL = "https://api.ucaptcha.net"
SITE_URL = "https://example.com/login"
SITE_KEY = "0x4AAAAAAABS7vwvV6VFfMcD"
def create_turnstile_task():
"""Submit a Turnstile solving task and return the task ID."""
response = requests.post(f"{BASE_URL}/createTask", json={
"clientKey": API_KEY,
"task": {
"type": "TurnstileTaskProxyless",
"websiteURL": SITE_URL,
"websiteKey": SITE_KEY,
# Include metadata only if the site uses action/cdata:
# "metadata": {"action": "login", "cdata": "value"}
}
})
result = response.json()
if result.get("errorId", 0) != 0:
raise Exception(f"Task creation failed: {result.get('errorDescription')}")
return result["taskId"]
def get_task_result(task_id: str, timeout: int = 120) -> str:
"""Poll for the task result and return the Turnstile token."""
start = time.time()
while time.time() - start < timeout:
response = requests.post(f"{BASE_URL}/getTaskResult", json={
"clientKey": API_KEY,
"taskId": task_id,
})
result = response.json()
if result.get("errorId", 0) != 0:
raise Exception(f"Result fetch failed: {result.get('errorDescription')}")
if result["status"] == "ready":
return result["solution"]["token"]
time.sleep(3)
raise TimeoutError("Turnstile solving timed out")
def solve_turnstile() -> str:
"""Full workflow: create task, poll result, return token."""
task_id = create_turnstile_task()
print(f"Task created: {task_id}")
token = get_task_result(task_id)
print(f"Token received: {token[:50]}...")
return token
# Usage: submit the token with your form data
token = solve_turnstile()
login_response = requests.post(f"{SITE_URL}", data={
"username": "user@example.com",
"password": "password",
"cf-turnstile-response": token,
})
print(f"Login status: {login_response.status_code}")
JavaScript / Node.js Implementation
Here is the equivalent implementation in Node.js:
const API_KEY = "YOUR_UCAPTCHA_API_KEY";
const BASE_URL = "https://api.ucaptcha.net";
const SITE_URL = "https://example.com/login";
const SITE_KEY = "0x4AAAAAAABS7vwvV6VFfMcD";
async function createTurnstileTask() {
const response = await fetch(`${BASE_URL}/createTask`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
clientKey: API_KEY,
task: {
type: "TurnstileTaskProxyless",
websiteURL: SITE_URL,
websiteKey: SITE_KEY,
// Include metadata only if required:
// metadata: { action: "login", cdata: "value" }
},
}),
});
const result = await response.json();
if (result.errorId !== 0) {
throw new Error(`Task creation failed: ${result.errorDescription}`);
}
return result.taskId;
}
async function getTaskResult(taskId, timeout = 120000) {
const start = Date.now();
while (Date.now() - start < timeout) {
const response = await fetch(`${BASE_URL}/getTaskResult`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
clientKey: API_KEY,
taskId,
}),
});
const result = await response.json();
if (result.errorId !== 0) {
throw new Error(`Result fetch failed: ${result.errorDescription}`);
}
if (result.status === "ready") {
return result.solution.token;
}
await new Promise((resolve) => setTimeout(resolve, 3000));
}
throw new Error("Turnstile solving timed out");
}
async function solveTurnstile() {
const taskId = await createTurnstileTask();
console.log(`Task created: ${taskId}`);
const token = await getTaskResult(taskId);
console.log(`Token received: ${token.substring(0, 50)}...`);
return token;
}
// Usage
(async () => {
const token = await solveTurnstile();
const loginResponse = await fetch(SITE_URL, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
username: "user@example.com",
password: "password",
"cf-turnstile-response": token,
}),
});
console.log(`Login status: ${loginResponse.status}`);
})();
Handling the cf-turnstile-response Token
Once you have the token, you need to submit it exactly as the target site expects. The most common patterns are:
Form Submission
Most sites embed Turnstile inside an HTML form. The token is placed in a hidden input named cf-turnstile-response. When you submit the form data, include this field:
data = {
"email": "user@example.com",
"password": "secret",
"cf-turnstile-response": token,
}
requests.post("https://example.com/login", data=data)
JSON API Body
Some modern sites send the token in a JSON request body. The field name varies — check the site’s network requests:
payload = {
"email": "user@example.com",
"password": "secret",
"turnstileToken": token, # field name varies by site
}
requests.post("https://example.com/api/login", json=payload)
Custom Header
Occasionally the token is sent as a custom HTTP header. Inspect the site’s XHR requests in DevTools to confirm:
headers = {
"X-Turnstile-Token": token,
"Content-Type": "application/json",
}
requests.post("https://example.com/api/login", headers=headers, json=payload)
Token Validation and Expiry
The token returned by the solver has a limited lifetime. Cloudflare typically enforces a 300-second (5-minute) window, though some sites configure shorter expiry. Best practices:
- Use the token immediately after receiving it. Do not cache tokens for later use.
- Solve just-in-time rather than pre-solving a batch. Create the task only when you are ready to submit the form.
- Handle failures gracefully. If the server rejects the token, create a new task and retry. Token rejection can happen if the token expired, the IP changed, or the action/cdata mismatch.
Using a Proxy with TurnstileTask
For scenarios where IP consistency matters — such as maintaining a logged-in session across requests — use the TurnstileTask type (without the Proxyless suffix) and supply your proxy:
{
"clientKey": "YOUR_UCAPTCHA_API_KEY",
"task": {
"type": "TurnstileTask",
"websiteURL": "https://example.com/login",
"websiteKey": "0x4AAAAAAABS7vwvV6VFfMcD",
"proxyType": "http",
"proxyAddress": "proxy.example.com",
"proxyPort": 8080,
"proxyLogin": "user",
"proxyPassword": "pass"
}
}
This ensures the token is generated from the same IP address your scraper uses, reducing the chance of server-side validation failures.
Common Issues and Troubleshooting
Token rejected by the server Double-check that you are using the correct site key, page URL, and (if applicable) action and cData values. Also verify the token has not expired.
Task stuck in processing Turnstile tasks typically resolve in 10-30 seconds. If a task takes longer than 60 seconds, the challenge page may have changed or the site key may be incorrect. Cancel and retry.
Wrong field name for submission
Not all sites use cf-turnstile-response as the field name. Inspect the actual form or API request in DevTools to find the correct parameter name.
IP mismatch errors
If the target server checks that the token’s IP matches the request IP, switch from TurnstileTaskProxyless to TurnstileTask with your own proxy.
Scaling Turnstile Solving
When processing thousands of pages, consider these strategies:
- Concurrent tasks — Submit multiple tasks in parallel rather than solving sequentially. uCaptcha handles concurrency automatically across its provider network.
- Smart routing — uCaptcha’s routing engine selects the fastest or cheapest provider for each task. If speed matters, choose the Fastest preset. If cost matters, choose the Cheapest preset.
- Error handling — Implement exponential backoff for transient errors. If a provider is down, uCaptcha automatically routes to an alternative.
For more strategies on working with Cloudflare-protected sites at scale, see our guide on automating Cloudflare-protected websites.
Beyond Turnstile: Cloudflare Challenge Pages
Turnstile is a standalone widget that site owners embed voluntarily. Cloudflare also deploys its own challenge pages — JavaScript challenges, managed challenges, and interactive challenges — on sites using Cloudflare’s proxy. These are different from Turnstile and require different handling. See our deep dive on Cloudflare challenge pages for a full breakdown of each challenge type and how to deal with them.
Conclusion
Cloudflare Turnstile is one of the easier modern CAPTCHA systems to integrate with programmatically, thanks to its token-based model and the TurnstileTaskProxyless task type supported by solver APIs. The workflow is straightforward: extract the site key, submit a task, poll for the token, and include it in your request. The key details to get right are the site key extraction, optional action/cData parameters, and timely token usage.
uCaptcha simplifies this further by routing your Turnstile tasks across multiple providers — CapSolver, 2Captcha, AntiCaptcha, CapMonster, and others — to find the fastest or cheapest option for each request. One API key, one integration, and the routing is handled for you.
Frequently Asked Questions
What is Cloudflare Turnstile?
Cloudflare Turnstile is a free CAPTCHA alternative that verifies users without presenting visual puzzles. It runs a series of browser challenges in the background and issues a cf-turnstile-response token upon success.
How do I solve Turnstile programmatically?
Submit the page URL and Turnstile site key to a CAPTCHA solver API using the TurnstileTaskProxyless task type. The API returns a cf-turnstile-response token you include in your request to the target server.
How much does solving Turnstile cost?
Turnstile solving typically costs $0.50–$2.00 per 1,000 tasks depending on the provider. uCaptcha's smart routing finds the cheapest option automatically.
Related Articles
Automating Cloudflare-Protected Websites: Strategies and Tools
Practical strategies for automating interactions with Cloudflare-protected websites — from Turnstile solving to challenge handling, cookie management, and request fingerprinting.
Cloudflare Challenge Pages: What They Are and How to Handle Them
Understanding Cloudflare's challenge pages — JavaScript challenges, managed challenges, and interactive challenges. Learn how to handle them in automated workflows.
Turnstile vs reCAPTCHA: A Developer's Comparison
Comparing Cloudflare Turnstile and Google reCAPTCHA — privacy, user experience, difficulty to solve, pricing, and which CAPTCHA is better for different use cases.