Troubleshooting

Cloudflare Turnstile 403 After Token Submission: Fix Guide

You solved the Turnstile CAPTCHA and got a valid token, but the target site still returns 403 Forbidden. This guide covers every cause.


Why 403 After Valid Token

Cause Likelihood
Missing cf_clearance cookie Very common
Token expired Common
Wrong submission endpoint Common
Missing request headers Moderate
IP mismatch between solve and submit Moderate
Cloudflare Challenge (not Turnstile) Sometimes confused

Turnstile sets cookies during validation. If you don't include these cookies in your subsequent request, Cloudflare blocks you.

import requests

session = requests.Session()

# Step 1: Load the page to get initial cookies
session.get("https://example.com")

# Step 2: Solve Turnstile
token = solve_turnstile(
    api_key="YOUR_API_KEY",
    sitekey="TURNSTILE_SITEKEY",
    pageurl="https://example.com",
)

# Step 3: Submit token to the validation endpoint
# This sets cf_clearance cookie
resp = session.post("https://example.com/api/verify", data={
    "cf-turnstile-response": token,
}, headers={
    "Content-Type": "application/x-www-form-urlencoded",
    "Origin": "https://example.com",
    "Referer": "https://example.com/",
})

# Step 4: Now make your actual request WITH the session cookies
resp = session.get("https://example.com/protected-page")
print(resp.status_code)  # Should be 200 now

Cause 2: Token Expired

Turnstile tokens last ~300 seconds, but use them immediately for best results.

import time

# Solve
start = time.time()
token = solve_turnstile(...)
solve_time = time.time() - start

# Check if token is still fresh
if solve_time > 240:  # > 4 minutes is risky
    print("Token may be too old, solving again...")
    token = solve_turnstile(...)

# Submit immediately
submit_token(token)

Cause 3: Wrong Submission Method

Find how the site submits the Turnstile token:

# Some sites use a hidden form field
data = {
    "cf-turnstile-response": token,
    "username": "user",
    "password": "pass",
}

# Some sites use a custom header
headers = {
    "X-Turnstile-Token": token,
}

# Some sites use JSON body
json_data = {
    "turnstileToken": token,
    "email": "user@example.com",
}

How to find the correct field name:

  1. Open browser DevTools → Network tab
  2. Complete the Turnstile challenge manually
  3. Find the form submission request
  4. Look at the request body for the token field name

Cause 4: Missing Headers

Cloudflare checks request headers for consistency:

headers = {
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36",
    "Accept": "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
    "Origin": "https://example.com",
    "Referer": "https://example.com/login",
    "Sec-Fetch-Dest": "document",
    "Sec-Fetch-Mode": "navigate",
    "Sec-Fetch-Site": "same-origin",
}

session.headers.update(headers)

Cause 5: Cloudflare Challenge vs Turnstile

Turnstile and Cloudflare Challenge are different systems:

Feature Turnstile Cloudflare Challenge
Widget Visible checkbox on page Full-page challenge screen
CaptchaAI method turnstile cloudflare_challenge
Token field cf-turnstile-response N/A (cookie-based)

If you see a full-page challenge, use method=cloudflare_challenge instead.


Complete Working Example

import requests
import time
import re


def solve_turnstile_and_access(target_url, api_key):
    """Complete flow: solve Turnstile and access protected page."""
    session = requests.Session()
    session.headers.update({
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36",
    })

    # Load page, get cookies and sitekey
    resp = session.get(target_url)
    match = re.search(r'data-sitekey="([^"]+)"', resp.text)
    if not match:
        raise RuntimeError("Turnstile sitekey not found")

    sitekey = match.group(1)

    # Solve via CaptchaAI
    submit_resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": api_key,
        "method": "turnstile",
        "sitekey": sitekey,
        "pageurl": target_url,
        "json": 1,
    }, timeout=30)
    task_id = submit_resp.json()["request"]

    # Poll
    for _ in range(12):
        time.sleep(5)
        poll = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key, "action": "get",
            "id": task_id, "json": 1,
        }, timeout=15)
        data = poll.json()
        if data.get("status") == 1:
            token = data["request"]
            break
    else:
        raise TimeoutError("Solve timeout")

    # Submit token using the same session
    form_resp = session.post(target_url, data={
        "cf-turnstile-response": token,
    }, headers={
        "Origin": f"https://{requests.utils.urlparse(target_url).netloc}",
        "Referer": target_url,
    })

    return session, form_resp


# Usage
session, resp = solve_turnstile_and_access(
    "https://example.com/login",
    "YOUR_API_KEY",
)
# session now has valid cookies for subsequent requests

Troubleshooting

Issue Cause Fix
403 despite valid token Missing session cookies Use same session for all requests
403 on subsequent pages cf_clearance not set Token validation must return cookie
Works once, then 403 Cookie expired Re-solve for fresh cookie
Always 403 Full-page challenge, not Turnstile Use cloudflare_challenge method

FAQ

How long does cf_clearance last?

Typically 30 minutes to 24 hours. If subsequent requests start failing, re-solve the Turnstile.

Do I need a proxy for Turnstile?

Often no — CaptchaAI's 100% success rate on Turnstile usually works without proxies. Add a proxy only if the site checks IP consistency.

Can I pass cf_clearance to another session?

Yes, but it's tied to the User-Agent and may be tied to the IP. Keep both consistent.



Fix 403 errors — solve Turnstile with CaptchaAI.

Discussions (0)

No comments yet.