Tutorial
Switch Captcha Provider in 10 Minutes: 2Captcha and createTask
Move Cloudflare Turnstile solving from 2Captcha or a createTask-style service by changing two settings, then check six details before full traffic.
By ZeroCaptcha Engineering4 min readPublished Updated
Switching the service that solves your Cloudflare Turnstile tasks is mostly a configuration
change, because the common request formats are shared: 2Captcha’s in.php and res.php, and the
createTask and getTaskResult JSON calls that Anti-Captcha, CapSolver, 2Captcha and others
use. Point your client at the new host, give it the new key, run one task, and check six details
before moving all traffic. This is the checklist, with the exact changes for the most common
clients.
For a deep dive into one provider, see the migration guides for 2Captcha, CapSolver and Anti-Captcha.
Minute 0 to 2: find which format your code speaks
Search your code for the old provider’s host:
- URLs ending in
/in.phpand/res.php, withmethod=turnstile: the 2Captcha format. - Calls to
/createTaskand/getTaskResultwith a JSON body holdingclientKeyandtask: the createTask format. - An SDK (a 2Captcha, CapSolver or Anti-Captcha library): find which of the two formats it sends, usually in its README, and the option that sets its host.
ZeroCaptcha serves both formats on its API host, plus its own REST API. The task types other
services use for Turnstile are accepted as they are: TurnstileTaskProxyless, TurnstileTask,
and CapSolver’s AntiTurnstileTaskProxyLess (with AntiTurnstileTask for the proxy variant).
Minute 2 to 4: move the host and key into configuration
If the host and key are written in your code, move them to environment variables first. It turns this switch, and any later one, into a deploy with no code change:
import os
API = os.environ.get("CAPTCHA_API", "https://api.2captcha.com")KEY = os.environ["CAPTCHA_KEY"]Minute 4 to 6: change them
createTask format. Set the base URL to the ZeroCaptcha API host and the key to your
zc_live_… key. Nothing else changes:
# metadata holds the widget's data-action and data-cdata (or turnstile.render()'s action and# cData options); leave out any the widget does not set.curl -s "$ZEROCAPTCHA_API/createTask" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen)" \ -d '{"clientKey": "'"$ZEROCAPTCHA_KEY"'", "task": {"type": "TurnstileTaskProxyless", "websiteURL": "https://shop.example.com/login", "websiteKey": "0x4AAAAAAAB1cD2eF3gH4iJ5", "metadata": {"action": "login", "cdata": "session-7f3a9c2e"}}}'2Captcha format. Replace the host in front of in.php and res.php:
# action and data are the widget's data-action and data-cdata; leave out any it does not set.curl -s -H "Idempotency-Key: $(uuidgen)" \ "$ZEROCAPTCHA_API/in.php?key=$ZEROCAPTCHA_KEY&method=turnstile&sitekey=0x4AAAAAAAB1cD2eF3gH4iJ5&pageurl=https%3A%2F%2Fshop.example.com%2Flogin&action=login&data=session-7f3a9c2e&json=1"The 2Captcha Python library (2captcha-python) builds its URLs as https://<server>/in.php
and https://<server>/res.php from its server option, so it needs the API’s host name, without
the scheme:
import osfrom urllib.parse import urlsplit
from twocaptcha import TwoCaptcha
host = urlsplit(os.environ["ZEROCAPTCHA_API"]).netlocsolver = TwoCaptcha(os.environ["ZEROCAPTCHA_KEY"], server=host, pollingInterval=2)result = solver.turnstile(sitekey="0x4AAAAAAAB1cD2eF3gH4iJ5", url="https://shop.example.com/login")print(result["code"])This works when the API’s base URL has no path. The library polls every 10 seconds by default;
pollingInterval=2 gets the token to you sooner, which matters because a Turnstile token only
lives 300 seconds.
Minute 6 to 8: run one task and read the reply
Run your normal code path once, against a page you are allowed to automate. A ready
getTaskResult reply looks the same as before, with two additions you can use or ignore:
{ "errorId": 0, "taskId": "0192f3a4-7b1c-7d2e-9f10-3c4d5e6f7a8b", "status": "ready", "solution": { "token": "0.xT4…", "type": "turnstile" }, "cost": "0.000800", "createTime": 1790762400, "endTime": 1790762404, "solveCount": 1, "expiresAt": "2026-09-30T10:05:04Z"}expiresAt is when the token stops working, and cost what the task cost in US dollars; the
current prices are on the pricing page.
Minute 8 to 10: the six checks
- Task IDs. The 2Captcha format answers numbers, as 2Captcha does. The createTask format answers UUIDs: code that stores those as text is fine, and a database column or a parser that expects an integer needs changing.
- Only Cloudflare Turnstile is solved through the 2Captcha format, and only Cloudflare Turnstile and Cloudflare challenge pages through the createTask format.
A task type for reCAPTCHA or hCaptcha is refused with
ERROR_TASK_NOT_SUPPORTED(orERROR_BAD_PARAMETERSin the 2Captcha format), at no charge. Keep your old provider for those. - cData field names. The createTask format reads it as
cdata,cData,data,turnstileCDataormetadata.cdata, so each client’s own spelling works. See Cloudflare Turnstile action and cData. - Proxies are HTTP or HTTPS. A SOCKS proxy is refused before anything is held. See solve Cloudflare Turnstile with a proxy.
- Callbacks need no registration. Any public URL works as
pingbackorcallbackUrl, and each call is signed. See captcha solver callbacks. - Error codes. The common ones match (
ERROR_ZERO_BALANCE,ERROR_CAPTCHA_UNSOLVABLE,ERROR_KEY_DOES_NOT_EXIST), and any code your client does not know should be treated as a failure. The full list is in captcha API error codes.
After the ten minutes: roll out gradually
- Send one worker, or a small share of tasks, to the new host.
- Compare, on your own pages, the share of tokens your target site accepts and the time from
createTaskto the token. Those two numbers are what you pay for. - Watch the status page for the service-wide success rate and median solve time.
- Move the rest of the traffic, and keep the old key for a week in case you need to switch back.
A task on ZeroCaptcha is charged only when its token is ready; a task that fails or times out costs nothing, so a trial costs only the tokens you receive.
ZeroCaptcha is not affiliated with 2Captcha, CapSolver or Anti-Captcha; their names appear only to say which formats and clients this covers.
Sources
- 2captcha-python README and its
API client source,
for the
serverandpollingIntervaloptions and the URLs it builds (checked 1 October 2026). - 2Captcha: Cloudflare Turnstile API (checked 1 October 2026).
- ZeroCaptcha’s 2Captcha format and errors reference.
The team that builds and runs the ZeroCaptcha API. Articles are drafted with AI tools, then checked against the API's code and the primary sources each one cites.