For the worker that has to survive 3am

Most CAPTCHA Integrations Fail On The Retry Logic, Not The Solve.

A solver that works in a notebook and a solver that survives production differ in one place: what happens when the answer is not there yet. CaptchaAI documents distinct codes - CAPCHA_NOT_READY, ERROR_UNSOLVABLE, ERROR_ZERO_BALANCE - and branching on them properly is most of the reliability work.

Documented ERROR_* codes to branch on Poll cadence documented at ~5 seconds Not-ready is not a failure - treat it separately Balance errors need alerting, not backoff

Our Promise

Rated 5★ by customers on Google

Get API key
The three failure modes people ship

Hammering, hiding, and stalling

Treat every non-success identically and you get one of three bugs. Tight retries hammer the endpoint and burn threads on work already in progress. Swallowing codes hides a billing state until the queue is empty. Waiting forever on a task that will never resolve stalls a worker that looks healthy.

  • Retrying 'not ready' as if it failed wastes concurrency
  • A swallowed balance error looks like silence
  • No timeout means a stuck worker reports green
  • One generic handler causes all three
Hammering, hiding, and stalling
What We Do

A retry policy that holds up

Four rules, each mapped to a documented response.

CAPCHA_NOT_READY - keep polling, do not resubmit

This is the normal in-progress state, not an error. Poll res.php with action=get&id=<taskId> at the documented ~5s cadence. Resubmitting the task instead creates a second job and occupies a second thread for the same work.

ERROR_UNSOLVABLE - fail the item, keep the run

A genuine terminal state for that task. Retry once if your workload tolerates it, then move on and record it. Infinite retries on an unsolvable task convert one failed item into a stalled pipeline.

ERROR_ZERO_BALANCE - alert, do not back off

Backoff is exactly wrong here: nothing will improve with time. This needs a human or an automated top-up. Route it to alerting rather than folding it into the generic retry path where it will look like a slow day.

Time out against the published band

Each type has a published latency band - under 0.5s for image, up to 60s for reCAPTCHA v2. Set your ceiling from the band for the type you are solving, with headroom, rather than one arbitrary global timeout.

What to instrument

The four numbers that tell you whether this is healthy.

Time to solve, by type

Compare against the published band for that type. Drift upward is the earliest warning that something changed on the target side.

Unsolvable rate, by target

A rise concentrated on one site usually means that site changed its challenge, not that the solver degraded.

Thread saturation

If in-flight tasks sit at your thread ceiling, you are queueing. That shows up as end-to-end latency long before it shows up as an error.

Poll count per solve

Climbing polls per solve means tasks are taking longer. Cheap to record and it moves before anything else does.

Documented codes· Distinct meanings, not a generic error ~5s poll· Documented cadence for res.php Published bands· Per-type latency to time out against Proxy per task· For targets that fingerprint the solver IP
What to watch

Four numbers that tell you it is healthy

Reliability here is observable. Track these and you see a change on the target's side days before it becomes an incident.

  • Time to solve, compared to the published band per type
  • Unsolvable rate, grouped by target site
  • Thread saturation - are you queueing?
  • Polls per solve, which moves before anything else
Why Us

Why this way

The practical case, in four lines.

1

Retry logic that does not hammer

Polling an in-progress task instead of resubmitting keeps a second thread free for real work.

2

Billing states surface as themselves

A zero-balance response routed to alerting rather than backoff stops a silent queue drain.

3

Bounded failure

Treating unsolvable as terminal for that item keeps one bad task from stalling the pipeline.

4

Timeouts with a basis

Per-type published bands give a defensible ceiling instead of one global guess.

Good to Know

Retry questions

Should I use exponential backoff on the poll?

Generally no for the in-progress poll - the documented pattern is a steady ~5s cadence until the result is ready. Reserve backoff for transport-level failures like a network error or a 5xx, not for CAPCHA_NOT_READY.

How many times should I retry an unsolvable task?

Once, if at all, and only when a duplicate solve is harmless. It is a terminal state for that task; the useful response is to record it and watch the rate.

What if my worker dies mid-poll?

Persist the task id when you submit, not just in memory. On restart you can resume polling an existing task rather than paying for the same solve twice.

Does a proxy help with reliability?

It helps when the target fingerprints the IP the solve originates from. Tasks accept proxy and proxytype so the solve can share your session's network context.

How do I know whether to add threads or fix my code?

If individual solve times match the published bands but end-to-end latency is rising, you are queueing and need concurrency. If solve times themselves are drifting, the target or the type has changed.

Debugging a flaky solver integration?

Documented codes, predictable behaviour

Branch on what the API actually tells you, and the 3am pages stop.

Get API key