
Your script requests a page and gets back a full-screen "Verifying you are human" wall instead of content. In a browser this costs about five seconds. In a requests session it costs forever: the interstitial runs JavaScript in a real browser environment before handing out the cookies that unlock the site, and a plain HTTP client never qualifies for them.
This article covers solving that page programmatically with Kaptra's captcha API and the AntiCloudflareTask type. If you are here for the inline Turnstile widget instead (the checkbox inside a form), that is a different mechanism with a different task type; the closing section links a companion guide for it.
Why the challenge page breaks plain HTTP clients
A Cloudflare challenge page is not a captcha rendered on your target page. It replaces your target page. The site's protection mode is set to challenge incoming visitors, and every visitor has to clear the interstitial before any real content loads.
Three properties make it a hard wall for scripts:
- The check runs JavaScript that expects a real browser environment.
- Clearing it issues cookies, and those cookies are bound to the IP address that earned them.
- There is no sitekey or form token to extract; the "proof of passage" is the cookie set itself.
So a solver cannot hand you a reusable string token the way it can for a widget. It has to pass the interstitial from your IP and give you back the cookies it earned. That is why this API task requires your own proxy as an input.
The task in one glance
- Type:
AntiCloudflareTask - Required inputs:
websiteURL(the protected page) andproxy(a public HTTP proxy; SOCKS is rejected) - Execution: async. Poll
/getTaskResultevery 1 to 2 seconds, up to 120 queries per task - Result:
solution.cookies, the clearance material to replay in your session - Cost and speed: $1.20 per 1,000 successful tasks, average under 10 seconds, billed per success only
Working Python implementation
import time
import requests
# ---
BASE_URL = "https://api.kaptra.ai"
API_KEY = "YOUR_KAPTRA_API_KEY"
# ---
def solve_cloudflare_challenge(website_url: str, proxy: str) -> dict:
# 1. create the task; proxy is required for this type (HTTP only)
resp = requests.post(
f"{BASE_URL}/createTask",
json={
"clientKey": API_KEY,
"task": {
"type": "AntiCloudflareTask",
"websiteURL": website_url,
"proxy": proxy,
},
},
).json()
if resp.get("errorId"):
raise RuntimeError(f"createTask failed: {resp.get('errorCode')}")
task_id = resp["taskId"]
# 2. poll every 1-2s, max 120 queries per task
for _ in range(120):
result = requests.post(
f"{BASE_URL}/getTaskResult",
json={"clientKey": API_KEY, "taskId": task_id},
).json()
status = result.get("status")
if status == "ready":
return result["solution"] # {"cookies": ...}
if status == "failure":
raise RuntimeError(f"task failed: {result.get('errorCode')}")
# processing (or CAPTCHA_NOT_READY): keep polling
time.sleep(1.5)
raise TimeoutError("gave up after 120 polls")
# ---
if __name__ == "__main__":
my_proxy = "http://USER:PASS@HOST:PORT"
solution = solve_cloudflare_challenge(
"https://www.example.com/protected", my_proxy
)
print(solution["cookies"])
# 3. attach these cookies to your session and keep
# sending requests through that same proxy
After the task returns, take solution["cookies"], attach it to your HTTP session, and route subsequent requests through the exact proxy you submitted with the task. Keeping that IP consistent is the point of the whole design: the clearance is only valid where it was earned.
Operational notes: proxy rules, retries, pricing
Proxy format. HTTP only. The docs reject SOCKS outright, so SOCKS-first infrastructure needs an HTTP front or a different provider for these tasks.
Retry posture. Failures come back as ERROR_CAPTCHA_UNSOLVABLE. One retry with identical parameters is the standard response; you pay nothing for failed or timed-out tasks, so the retry is free.
Envelope. Every API response is HTTP 200. Check errorId (0 means fine, 1 means error) and errorCode in the body, never the status code.
Budget. $1.20 per 1k successful solves, no monthly fee, no minimum, balance never expires. Fresh accounts get $10 of test credit, which is several thousand solves at this task's price if you want to prove the pipeline first.
Widget vs challenge page: a pocket reference
| Turnstile widget | Challenge page | |
|---|---|---|
| Where you see it | Embedded in a form | Replaces the whole page |
| You supply | websiteURL + websiteKey |
websiteURL + proxy (HTTP) |
| You receive | token + userAgent | cookies |
| You then | submit token with the form | replay cookies via same proxy |
The companion guide for the Turnstile widget side is on our Medium publication. Site and docs: kaptra.ai and the AntiCloudflareTask reference. Questions about a task type you need covered? The team answers tickets in Discord.
About the author
- Official account of Kaptra, a captcha recognition API for developers. We publish practical guides on Cloudflare Turnstile, Cloudflare Challenge, AWS WAF, and DataDome for test automation and authorised data collection workflows.
Comments
Join the discussionNo comments yet. Be the first to comment.

