Solve Cloudflare Turnstile, reCAPTCHA v2, reCAPTCHA v3 & image OCR — pay only for successful solves.
3Captcha is a captcha-solving API. When a website you're automating shows a captcha (a "prove you're human" challenge), you send us the captcha's details and we return a token that proves the challenge was passed. You then submit that token to the website, exactly as if a real user had solved it.
You are charged only when a solve succeeds — there is no cost for failed attempts.
| Term | What it means |
|---|---|
sitekey | The public identifier of the captcha on the target site. You find it in the site's HTML, usually in a data-sitekey attribute or the render(...) call. |
siteurl | The full URL of the page where the captcha appears (e.g. https://example.com/checkout). |
token | The string our API returns. Submit it in the site's form (the g-recaptcha-response / cf-turnstile-response field, or via its JS callback) to prove the solve. |
action | reCAPTCHA v3 only — the action label registered for the key (e.g. submit, login). |
base64 | OCR only — the captcha image encoded as a base64 string. |
prv_… key from your dashboard.sitekey + siteurl, passing your key in the x-api-key header.token goes into the captcha field on the target site.curl -X POST http://3captcha.world/solve/turnstile \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"sitekey":"0x4AAAAAAActoBfh_En8yr3T","siteurl":"https://example.com/"}'
# Success
{"status":"success","token":"0.w0e4...","elapsed":5.2}
/solve/recaptcha-v2) and the fields you send — everything else is the same.The async flow is the recommended way to solve. It never blocks your connection and survives long solves. It's just two steps:
taskId back instantly.taskId every few seconds until you get success (with the token) or error.Works for every enabled type: turnstile, recaptcha-v2, recaptcha-v3 and ocr.
curl -X POST http://3captcha.world/createTask \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"type":"turnstile","sitekey":"0x4AAAAAAActoBfh_En8yr3T","siteurl":"https://example.com/"}'
# 200 OK — keep the taskId, you poll it in step 2
{"status":"success","taskId":"c60c71cdec26fae307cc73ceb8f40a92","type":"turnstile"}
| Field | Type | Description |
|---|---|---|
type | string | Required — turnstile, recaptcha-v2, recaptcha-v3 or ocr. |
sitekey | string | Required (except ocr) — the site's public key. |
siteurl | string | Required (except ocr) — the page URL hosting the captcha. |
base64 | string | Required for ocr — the captcha image as base64. |
action | string | Optional — reCAPTCHA v3 action label (default submit). |
timeout | int | Optional — solve timeout in seconds (default 45). |
curl "http://3captcha.world/getTaskResult?taskId=c60c71cdec26fae307cc73ceb8f40a92" \ -H "x-api-key: YOUR_API_KEY"
The result is always one of three states:
{"status":"processing","taskId":"c60c71..."} # still solving → poll again
{"status":"success","taskId":"c60c71...","token":"0.w0e4..."} # done → use "token"
{"status":"error","taskId":"c60c71...","detail":"..."} # failed
success or error. Tasks expire after 20 minutes.Once you get success, the token is the solved captcha. Submit it to the target site exactly like a human's answer:
cf-turnstile-response field (or its JS callback).g-recaptcha-response field.# Python
import requests, time
API = "http://3captcha.world"
HEAD = {"x-api-key": "YOUR_API_KEY"}
task = requests.post(API + "/createTask", headers=HEAD,
json={"type": "turnstile", "sitekey": "0x4AAAAAAActoBfh_En8yr3T", "siteurl": "https://example.com/"}).json()
task_id = task["taskId"]
while True:
r = requests.get(API + "/getTaskResult", params={"taskId": task_id}, headers=HEAD).json()
if r["status"] == "success":
print("TOKEN:", r["token"]); break
if r["status"] == "error":
print("FAILED:", r.get("detail")); break
time.sleep(4) # still processing — poll again
# Node.js
const API = "http://3captcha.world";
const HEAD = { "x-api-key": "YOUR_API_KEY" };
const task = await fetch(API + "/createTask", {
method: "POST",
headers: { ...HEAD, "Content-Type": "application/json" },
body: JSON.stringify({ type: "turnstile", sitekey: "0x4AAAAAAActoBfh_En8yr3T", siteurl: "https://example.com/" }),
}).then(r => r.json());
const taskId = task.taskId;
while (true) {
const r = await fetch(API + "/getTaskResult?taskId=" + taskId, { headers: HEAD }).then(r => r.json());
if (r.status === "success") { console.log("TOKEN:", r.token); break; }
if (r.status === "error") { console.log("FAILED:", r.detail); break; }
await new Promise(res => setTimeout(res, 4000)); // still processing
}
# PHP
$api = "http://3captcha.world";
$head = ["x-api-key: YOUR_API_KEY", "Content-Type: application/json"];
$ch = curl_init($api . "/createTask");
curl_setopt($ch, CURLOPT_HTTPHEADER, $head);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode(["type" => "turnstile", "sitekey" => "0x4AAAAAAActoBfh_En8yr3T", "siteurl" => "https://example.com/"]));
$task = json_decode(curl_exec($ch), true);
$taskId = $task["taskId"];
do {
sleep(4);
$r = json_decode(file_get_contents($api . "/getTaskResult?taskId=" . $taskId, false,
stream_context_create(["http" => ["header" => "x-api-key: YOUR_API_KEY"]])), true);
} while ($r["status"] === "processing");
echo ($r["status"] === "success") ? "TOKEN: " . $r["token"] : "FAILED: " . $r["detail"];Every solve request needs your API key. Send it in the x-api-key header (or api_key in the JSON body).
curl -X POST http://3captcha.world/solve/turnstile \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"sitekey":"0x4AAAAAAActoBfh_En8yr3T","siteurl":"https://example.com/"}'| Field | Type | Description |
|---|---|---|
sitekey | string | Required — the Turnstile site key. |
siteurl | string | Required — the page URL hosting the widget. |
timeout | int | Optional solve timeout in seconds (default 45). |
curl -X POST http://3captcha.world/solve/turnstile \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"sitekey":"0x4AAAAAAActoBfh_En8yr3T","siteurl":"https://example.com/"}'
# 200 OK — submit "token" as cf-turnstile-response
{"status":"success","token":"0.w0e4...","elapsed":5.2}
| Field | Type | Description |
|---|---|---|
sitekey | string | Required — the reCAPTCHA v2 site key. |
siteurl | string | Required — the page URL hosting the widget. |
curl -X POST http://3captcha.world/solve/recaptcha-v2 \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"sitekey":"6LfyCr4rAAAAAEEBPic8UihJxtI4IeOMuPXRLebm","siteurl":"https://example.com/"}'
# 200 OK — submit "token" as g-recaptcha-response
{"status":"success","token":"03AFcWeA...","elapsed":19.4}
v3 runs in the background (no image challenge) and returns a token whose score is decided by Google. Submit the token to your own verification endpoint to read the score.
| Field | Type | Description |
|---|---|---|
sitekey | string | Required — the reCAPTCHA v3 site key. |
siteurl | string | Required — the page URL hosting the widget. |
action | string | Optional action label (default submit). |
curl -X POST http://3captcha.world/solve/recaptcha-v3 \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"sitekey":"6Lcyqq8oAAAAAJE7eVJ3aZp_hnJcI6LgGdYD8lge","siteurl":"https://example.com/","action":"submit"}'
# 200 OK
{"status":"success","token":"03AGdBq26...","elapsed":33.2}
Our OCR engine extracts letters and numbers from any captcha image — built to handle noisy, distorted and overlapping characters with high accuracy.
| Field | Type | Description |
|---|---|---|
base64 | string | Required — the captcha image as a base64 string (with or without the data:image/…;base64, prefix). |
curl -X POST http://3captcha.world/solve/ocr \
-H "Content-Type: application/json" \
-H "x-api-key: YOUR_API_KEY" \
-d '{"base64":"/9j/4AAQSkZJRg..."}'
# 200 OK — "token" is the recognized text (letters/numbers only)
{"status":"success","token":"42ST","elapsed":22.7}
# Python
import requests
r = requests.post("http://3captcha.world/solve/turnstile",
headers={"x-api-key": "YOUR_API_KEY"},
json={"sitekey":"0x4AAAAAAActoBfh_En8yr3T","siteurl":"https://example.com/"})
print(r.json())
# Node.js
const res = await fetch("http://3captcha.world/solve/turnstile", {
method: "POST",
headers: { "Content-Type": "application/json", "x-api-key": "YOUR_API_KEY" },
body: JSON.stringify({ sitekey: "0x4AAAAAAActoBfh_En8yr3T", siteurl: "https://example.com/" }),
});
console.log(await res.json());
# PHP
$ch = curl_init("http://3captcha.world/solve/turnstile");
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => ["Content-Type: application/json", "x-api-key: YOUR_API_KEY"],
CURLOPT_POSTFIELDS => '{"sitekey":"0x4AAAAAAActoBfh_En8yr3T","siteurl":"https://example.com/"}',
]);
echo curl_exec($ch);