You submitted a Turnstile CAPTCHA to CaptchaAI, got a token back, but the target site rejects it. The token is technically solved — the problem is how or when you use it. This guide covers every reason Turnstile tokens fail after solving.
Symptoms
| What you see | Likely cause |
|---|---|
| Site returns 403 after submitting token | Token expired before submission |
| Form submission fails silently | Wrong field name for token injection |
| Token accepted but action blocked | Sitekey mismatch — solved wrong widget |
| Works once, then fails | Token already used (single-use) |
| Works in browser, fails in script | Missing cookies or headers |
Cause 1: Token expired
Turnstile tokens expire quickly — typically within 300 seconds (5 minutes). If your code takes too long between receiving the token and submitting it, the token is dead.
Fix: Submit the token immediately after receiving it.
import requests
import time
API_KEY = "YOUR_API_KEY"
# Submit Turnstile task
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "turnstile",
"sitekey": "0x4AAAAAAADnPIDROz1234",
"pageurl": "https://example.com/login",
"json": 1
}).json()
task_id = submit["request"]
time.sleep(10)
# Poll for result
for _ in range(24):
result = requests.get("https://ocr.captchaai.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": 1
}).json()
if result.get("status") == 1:
token = result["request"]
# USE TOKEN IMMEDIATELY — do not delay
response = requests.post("https://example.com/login", data={
"username": "user",
"password": "pass",
"cf-turnstile-response": token
})
break
time.sleep(5)
Cause 2: Wrong sitekey
Each Turnstile widget has a unique sitekey. If the page has multiple widgets or you copied the wrong key, the token will be valid but rejected.
How to find the correct sitekey:
// In browser console on the target page
document.querySelectorAll('[data-sitekey]').forEach(el => {
console.log('Sitekey:', el.getAttribute('data-sitekey'));
console.log('Element:', el);
});
If there are multiple sitekeys, use the one attached to the form you are submitting.
Cause 3: Wrong field name
Turnstile expects the token in cf-turnstile-response, not g-recaptcha-response.
# WRONG — this is for reCAPTCHA
data = {"g-recaptcha-response": token}
# CORRECT — this is for Turnstile
data = {"cf-turnstile-response": token}
Some sites use a custom field name. Inspect the form to find the actual field:
// Check what field the Turnstile widget populates
document.querySelector('[name*="turnstile"], [name*="cf-"]')
Cause 4: Token already used
Turnstile tokens are single-use. If your code retries a request with the same token, the second attempt will fail.
Fix: Solve a new CAPTCHA for each submission attempt.
Cause 5: Missing cookies or session context
Cloudflare may validate the token against session cookies. If you solve the CAPTCHA in one session and submit in another, rejection is likely.
# Use the SAME session for page load and token submission
session = requests.Session()
# Load the page first to establish cookies
session.get("https://example.com/login")
# Then solve and submit using the same session
token = solve_turnstile(sitekey, pageurl)
session.post("https://example.com/login", data={
"cf-turnstile-response": token
})
Cause 6: Action or cData mismatch
Some Turnstile implementations include action or cData parameters bound to the token. If the site expects these, you must pass them when solving.
submit = requests.post("https://ocr.captchaai.com/in.php", data={
"key": API_KEY,
"method": "turnstile",
"sitekey": "0x4AAAAAAADnPIDROz1234",
"pageurl": "https://example.com/login",
"action": "login", # If required by the site
"data": "custom_cdata_value", # If required by the site
"json": 1
}).json()
Decision tree
Token solved but rejected
↓
Used within 5 minutes? → No → Solve again, submit immediately
↓ Yes
Correct sitekey? → No → Find the correct sitekey from the page
↓ Yes
Using cf-turnstile-response field? → No → Change field name
↓ Yes
Same session for page load + submit? → No → Use session persistence
↓ Yes
Token used only once? → No → Solve a new token per submission
↓ Yes
Site requires action/cData? → Check page source, add to API call
FAQ
How long do Turnstile tokens last?
Typically 300 seconds (5 minutes). Some implementations set shorter expiry. Submit the token within seconds of receiving it.
Is Turnstile the same as Cloudflare Challenge?
No. Turnstile is an embedded widget (like reCAPTCHA). Cloudflare Challenge is a full-page interstitial. They use different CaptchaAI methods: turnstile vs cloudflare_challenge.
Why does my token work in Postman but not in my script?
Postman may be sending different headers or cookies. Match your script's headers and session state to what the browser sends.
Solve Turnstile CAPTCHAs at CaptchaAI
Get reliable Turnstile solving at captchaai.com.
Discussions (0)
Join the conversation
Sign in to share your opinion.
Sign InNo comments yet.