# 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.

- Source: https://zerocaptcha.io/blog/switch-captcha-provider
- Published: 2026-09-30
- Updated: 2026-10-01
- Author: ZeroCaptcha Engineering

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](https://zerocaptcha.io/guides/migrate-from-2captcha), [CapSolver](https://zerocaptcha.io/guides/migrate-from-capsolver) and
[Anti-Captcha](https://zerocaptcha.io/guides/migrate-from-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.php`** and **`/res.php`**, with `method=turnstile`: the 2Captcha format.
- Calls to **`/createTask`** and **`/getTaskResult`** with a JSON body holding `clientKey` and
  `task`: 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:

```python
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:

```sh
# 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`:

```sh
# 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:

```python
import os
from urllib.parse import urlsplit

from twocaptcha import TwoCaptcha

host = urlsplit(os.environ["ZEROCAPTCHA_API"]).netloc
solver = 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:

```json
{
  "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](https://zerocaptcha.io/pricing).

## Minute 8 to 10: the six checks

1. **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.
2. **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` (or `ERROR_BAD_PARAMETERS`
   in the 2Captcha format), at no charge. Keep your old provider for those.
3. **cData field names.** The createTask format reads it as `cdata`, `cData`, `data`,
   `turnstileCData` or `metadata.cdata`, so each client's own spelling works. See [Cloudflare Turnstile action and cData](https://zerocaptcha.io/guides/cloudflare-turnstile-action-and-cdata).
4. **Proxies are HTTP or HTTPS.** A SOCKS proxy is refused before anything is held. See
   [solve Cloudflare Turnstile with a proxy](https://zerocaptcha.io/guides/solve-cloudflare-turnstile-with-a-proxy).
5. **Callbacks need no registration.** Any public URL works as `pingback` or `callbackUrl`, and
   each call is signed. See [captcha solver callbacks](https://zerocaptcha.io/guides/captcha-solver-callbacks).
6. **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](https://zerocaptcha.io/guides/captcha-api-error-codes).

## After the ten minutes: roll out gradually

1. Send one worker, or a small share of tasks, to the new host.
2. Compare, on your own pages, the share of tokens your target site accepts and the time from
   `createTask` to the token. Those two numbers are what you pay for.
3. Watch the [status page](https://zerocaptcha.io/status) for the service-wide success rate and median solve time.
4. 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](https://github.com/2captcha/2captcha-python) and its
  [API client source](https://github.com/2captcha/2captcha-python/blob/master/twocaptcha/api.py),
  for the `server` and `pollingInterval` options and the URLs it builds (checked 1 October
  2026).
- [2Captcha: Cloudflare Turnstile API](https://2captcha.com/api-docs/cloudflare-turnstile)
  (checked 1 October 2026).
- ZeroCaptcha's [2Captcha format](https://zerocaptcha.io/docs/2captcha) and [errors reference](https://zerocaptcha.io/docs/reference/errors).

## Questions

### Do I need to rewrite my code to switch CAPTCHA providers?

Usually not for Cloudflare Turnstile. If your code speaks 2Captcha's in.php and res.php or the createTask format, changing the API host and the key is the whole code change; the checklist covers the details that can differ.

### Can the official 2Captcha Python library point at another service?

Yes. Its server option sets the host it builds https://<server>/in.php and /res.php from, so it works with any service that serves the 2Captcha format at the root of its host.

### How do I switch without risking an outage?

Make the host and key configuration, send a share of traffic to the new service, compare success and solve time on your own pages, then move the rest. Keep the old key until you are sure.
