Limits and Queueing
How long a result lives, how to poll, and what a refusal means
Nothing here is a per-key quota: a key is not rate limited, and a burst is not rejected for being a burst. The API is bounded by how many solves the platform runs at once, and everything above that waits in a queue. This page describes what that means in practice.
Results and Polling
- A finished result is kept for a short window (minutes), then it expires: a late
/getTaskResultanswersERROR_TASK_NOT_FOUND. Read the result when it is ready; do not archive thetaskIdand expect to come back to it later. - Poll
/getTaskResultevery few seconds, not in a tight loop. A solve takes from a couple of seconds to a minute depending on the product and on whether the site is busy. - Every call answers with HTTP 200, success or failure: read
errorId(anderrorCode) rather than the HTTP status. A client library that only checksresponse.okwill treat every error as a success.
The Queue
Tasks are solved as slots free up. A task you just created is behind everything that arrived before it, so a slow answer usually means a busy platform, not a stuck task.
When the queue is long enough that a new task would wait far longer than the solve itself, /createTask refuses it immediately with ERROR_TASK_QUEUE_FULL and refunds the reservation. The task never reaches a worker. That is deliberate: a task that waits longer than a result lives could never be delivered.
In that situation, back off and come back: retrying in a loop only lengthens the queue. Errors and Retries has the per-code rules.
Concurrency
There is no per-key limit on concurrent tasks today. Many customers run large batches through a single key, and the queue absorbs them.
Two things bound a batch in practice:
- The platform's slots. Everything past the running solves waits.
- The private-beta products. The payload API caps concurrent sessions per key and answers
concurrency_limitwith aretryAfterMs; its own page documents it.
Requests
proxyis required for every non-ProxyLess task type and ignored on a ProxyLess one. One clean token, no whitespace: see Proxy Format.websiteURLmust be the page that renders the challenge, without credentials, on a public host. A private or reserved address in the URL or in the proxy host is refused withERROR_BLOCKED_TARGET.- Fields are validated before anything is reserved: a malformed request is answered at once and never charged.
Per Product
| Product | What is specific to it |
|---|---|
| reCAPTCHA v3 / Enterprise | A standard sitekey sent to an Enterprise type (or the reverse) is refused with ERROR_WRONG_TASK_TYPE. See reCAPTCHA v3 |
| AWS WAF Captcha | The ProxyLess variant uses our pool; AntiAwsWafTask needs your proxy. See AWS WAF |
| GeeTest v3 + v4 | v3 and v4 are the same task type, selected by the fields you send. See GeeTest |
| CaptchaFox | The token format depends on the site. See CaptchaFox |
| Cloudflare Turnstile | Enabled per API key, and a managed widget can ask for a click. See Cloudflare Turnstile |