Cloudflare challenges fail in very different ways depending on which protection type you're hitting. Using the wrong approach for the challenge type is the most common root cause. This guide covers diagnosis and fixes for each Cloudflare challenge type.
For background on Cloudflare's protection types, see the Cloudflare CAPTCHA Guide.
Step 1 — Identify the Challenge Type
Before debugging, confirm which challenge you're facing:
| Symptom | Challenge type |
|---|---|
| Form has an iframe with a spinning circle or checkbox | Turnstile (widget embedded in page) |
| Full page shows "Checking your browser…" with a spinner | Managed Challenge or JS Challenge |
| Full page shows "Just a moment…" with a 5-second countdown | JS Challenge |
| "Verify you are human" with a CAPTCHA challenge | Managed Challenge |
| Error code 1020 "Access Denied" | Firewall Rule block — solver won't help |
Solvers work for Turnstile and Managed Challenge only. A 1020 block means your IP is on Cloudflare's firewall deny list — no solver resolves that.
import requests
def detect_cloudflare_challenge(url: str) -> str:
headers = {"User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"}
r = requests.get(url, headers=headers, timeout=15, allow_redirects=True)
if r.status_code == 403 and "1020" in r.text:
return "firewall_block"
if "managed_challenge" in r.text or "cf-challenge" in r.text:
return "managed_challenge"
if "jschl-answer" in r.text or "checking your browser" in r.text.lower():
return "js_challenge"
if "cf-turnstile" in r.text or "challenges.cloudflare.com/turnstile" in r.text:
return "turnstile"
return "unknown"
Debugging Turnstile (Widget in Form)
The most common failure: token is solved but not accepted by the form.
Check 1 — Is the token being injected into the right field?
# Correct injection for Turnstile
page.evaluate(f"""
const field = document.querySelector('[name="cf-turnstile-response"]');
if (field) {{
field.value = '{token}';
console.log('Injected into cf-turnstile-response');
}} else {{
console.error('cf-turnstile-response field not found');
}}
""")
If the field isn't found, the site may use a custom name. Inspect the form fields before submission.
Check 2 — Is action or cdata required?
Some Turnstile deployments validate the action parameter server-side. If the solver generated a token with action=login but the form submits to an endpoint expecting action=checkout, the token is rejected.
Fix: Extract data-action and data-cdata from the widget div:
import re, requests
html = requests.get(page_url, headers={"User-Agent": "Mozilla/5.0"}, timeout=15).text
action_m = re.search(r'data-action=["\']([^"\']+)["\']', html)
cdata_m = re.search(r'data-cdata=["\']([^"\']+)["\']', html)
payload["action"] = action_m.group(1) if action_m else None
payload["data"] = cdata_m.group(1) if cdata_m else None
Check 3 — Has the token expired?
Turnstile tokens are valid for approximately 300 seconds (5 minutes). If your automation process takes longer than 5 minutes from solve to submit, the token is stale.
Fix: Solve immediately before form submission, not at the start of the session.
Check 4 — Using the correct solver method?
Turnstile requires method=turnstile. Using method=userrecaptcha or method=hcaptcha generates a different token type that Cloudflare rejects.
Debugging Managed Challenge (Full-Page Interstitial)
Managed Challenge is the hardest Cloudflare protection to bypass. It runs JS fingerprinting, TLS analysis, and behavioral signals. A standard CAPTCHA solver API won't clear it — you need a solver that explicitly runs a headless browser against Cloudflare's challenge.
Why standard solvers fail
When you submit pageurl to a standard solver, the worker visits your page URL and encounters the Managed Challenge itself — then loops. The solver needs to be designed to handle this specifically.
What works
-
CapSolver
CloudflareChallengetask: Runs a purpose-built headless browser that handles the Managed Challenge and returns acf_clearancecookie. -
Puppeteer/Playwright with stealth plugins:
puppeteer-extra-plugin-stealthorplaywright-stealthcan sometimes pass Managed Challenge by looking like a real browser. Reliability varies by IP reputation. -
Pre-cleared session cookies: If you manually clear a Managed Challenge in a browser, export the
cf_clearancecookie and use it in requests. Valid for hours to days depending on Cloudflare's settings.
Using cf_clearance cookies
def make_request_with_clearance(url: str, cf_clearance: str, user_agent: str) -> requests.Response:
"""
Use a pre-obtained cf_clearance cookie to bypass Managed Challenge.
IMPORTANT: The User-Agent must match the browser that generated the cookie.
"""
session = requests.Session()
session.cookies.set("cf_clearance", cf_clearance, domain=".example.com")
session.headers.update({"User-Agent": user_agent})
return session.get(url, timeout=30)
The User-Agent is critical — cf_clearance is bound to the browser session that solved it. Mismatched User-Agents cause the cookie to be rejected.
Debugging JS Challenge (5-Second Wait)
JS Challenges are handled the same way as Managed Challenges via cf_clearance. The 5-second countdown is Cloudflare executing and verifying a JavaScript fingerprint.
Key difference from Managed Challenge: JS Challenges are more predictable and easier to clear with stealth browsers than the ML-based Managed Challenge.
Common Failure Causes by Type
| Challenge | Common failure cause | Fix |
|---|---|---|
| Turnstile | Wrong field name | Inspect form, target [name="cf-turnstile-response"] |
| Turnstile | Token expired | Solve immediately before submit |
| Turnstile | Wrong action |
Extract data-action from widget |
| Turnstile | Wrong solver method | Use method=turnstile |
| Managed Challenge | Wrong solver type | Use CapSolver CloudflareChallenge or stealth browser |
| Managed Challenge | IP flagged | Rotate to residential IP |
| JS Challenge | Cookie mismatch | Keep User-Agent consistent |
| 1020 Block | IP denied | Rotate IP — no solver helps |
Related Guides
- CAPTCHA Solver Troubleshooting Guide — full overview
- Cloudflare CAPTCHA Guide — challenge types explained
- Best Cloudflare Challenge Solver — solver comparison for each type
- How to Solve Cloudflare Turnstile in Python — full code tutorial
Production Readiness Notes
Use Cloudflare Challenge Not Solving — Diagnosis and Fixes as a decision and implementation aid, not just as a one-time reference. The practical test for cloudflare challenge not solving is whether the same approach behaves reliably when traffic is messy: rotating sessions, expired tokens, changing widget parameters, intermittent solver delays, and target pages that refresh without warning. For Developer debugging Cloudflare automation, the safest rollout is to start with a narrow fixture, record every submitted task, and compare the solver response with the browser state that finally submits the form. That makes failures explainable instead of mysterious, especially when a target alternates between visible challenges, invisible checks, and server-side verification.
Evaluation Criteria
A troubleshooting guide should change one variable at a time and record the before-and-after result; otherwise proxy, token, and page-state bugs blur together. For troubleshooting work, the most useful scorecard combines technical acceptance with operational cost. A low nominal price is not enough if retries double the real cost per accepted token, and a fast median solve time is not enough if p95 latency stalls the queue. Track these criteria before you standardize the workflow:
- The challenge subtype, sitekey, action, rqdata, blob, captchaId, or page URL used for each task.
- Median and p95 solve time, separated by provider and target domain.
- Accepted-token rate on the target page, not just successful API responses.
- Retry count, timeout count, zero-balance incidents, and invalid-parameter errors.
- The exact browser, proxy region, and user-agent that submitted the solved token.
Rollout Checklist
Before this guidance moves into a production job, build a small acceptance suite around the pages that matter most. Run it with a fixed browser profile, then repeat with the proxy and concurrency settings you expect in production. Keep the first release conservative: bounded polling, clear timeout handling, and a fallback path when the solver cannot return a usable answer. For troubleshooting, preserve the original request payload, solver response, page URL, sitekey, proxy, and browser fingerprint before changing multiple variables. That checklist keeps the article useful after the first copy-paste, because the integration is judged by end-to-end completion rather than by whether a code sample returned a string.
Monitoring Signals
Healthy CAPTCHA automation is observable. Log the task id, provider, challenge type, target host, queue time, solve time, final submit status, and normalized error code for every attempt. Review those logs in daily batches at first, then move to alerts once the baseline is stable. Sudden drops usually come from target-side changes: a new sitekey, a changed action name, a stricter hostname check, an added managed challenge, or a proxy pool that no longer matches the expected geography. When you can see those shifts quickly, provider switching becomes a controlled decision instead of a late-night rewrite.
Maintenance Cadence
Revisit the setup whenever the target UI changes, when the solver provider changes task names or pricing, or when benchmark data shows a sustained latency or solve-rate shift. Keep one known-good fixture for each CAPTCHA subtype and rerun it after dependency upgrades, browser updates, and proxy changes. If the article is used for vendor selection, repeat the same fixture across at least two providers before renewing a balance or migrating the whole pipeline. That habit keeps cloudflare challenge not solving work aligned with the real target behavior rather than with stale assumptions.