Guide

Do You Need a Proxy to Solve reCAPTCHA?

For reCAPTCHA it depends on the task name, and the API is strict about it: a `*ProxyLess` task is rejected if you send a `proxy` field, and every other reCAPTCHA task is rejected if you don't. That part is mechanical. The real question is which variant you should pick, and that comes down to one thing — whether the IP the token is minted from needs to relate to the IP your traffic comes from.

The rule: ProxyLess reCAPTCHA tasks must not carry a proxy

The check is the suffix: isProxyless(task) is task.endsWith('ProxyLess'). Inside the reCAPTCHA branch of the request schema it splits two ways:

  • ProxyLess task with a proxy → rejected: ProxyLess tasks must not include a proxy
  • Non-ProxyLess reCAPTCHA task without a proxy → rejected: a proxy is required for non-ProxyLess tasks

Both are HTTP 400 with error: "validation_error" and the complaint in an issues array. Branch on issues[].path, not on the prose:

{
  "success": false,
  "error": "validation_error",
  "message": "Request failed validation.",
  "request_id": "...",
  "issues": [
    { "path": "proxy", "message": "ProxyLess tasks must not include a proxy" }
  ]
}

Three pairs: ReCaptchaV2Task, ReCaptchaV3Task and ReCaptchaV3EnterpriseTask, each with a *ProxyLess twin. Same solve, different egress.

That rule lives in the reCAPTCHA branch only. The other task families return before it with their own rules: EvaluateTask requires a proxy and has no ProxyLess variant; KasadaLogin requires one because its token is IP-bound; KasadaReload needs none and, unlike a ProxyLess task, is not rejected for carrying one; TicketmasterTmptTask treats it as optional, falling back to the solver's own pool. Don't generalize the suffix convention across families.

Why the IP the token is minted from matters

A reCAPTCHA v3 token resolves to a score when your backend verifies it, and that score reflects the context it was minted in — including the network. Your ProxyLess solve egresses from KagedCap's addresses; your proxied solve egresses from yours.

The mismatch shows up at verification, because Google's verification APIs accept a second IP: siteverify takes an optional remoteip, and reCAPTCHA Enterprise's createAssessment takes event.userIpAddress. If your backend passes the address of the request that replayed the token while the token was minted somewhere unrelated, you have given the assessment two unrelated addresses for what is supposed to be one client — and the score reflects that. Not a broken token; a weaker one, by an amount set by the sitekey's configuration and the site's own risk model, neither of which you can see from outside. A v3 token is valid for about two minutes, so there is no rerouting it after the fact.

Measure it rather than trusting anyone's claim, ours included. Send your reCAPTCHA secretKey on the solve request and the response carries a verified score; run the same sitekey and action both ways on a property you own and compare.

When to send your own proxy, and when ProxyLess is fine

Send your own proxy when:

  • The token gets replayed from a specific address — a session already established from that exit, or a workflow pinned to one residential IP. The mint and the replay are the same client; make the egress match.
  • Your backend passes remoteip or event.userIpAddress at verification.
  • The page's behaviour is geography-dependent and you need a particular region.

ProxyLess is fine when:

  • You are evaluating the API and don't want to wire up egress first.
  • The token is consumed by something that never sees or forwards a client IP.
  • It's v2 invisible, where there is no score to degrade.

Two caveats. The ProxyLess exit address is not yours to control, and it is shared. And ProxyLess is the only reCAPTCHA family whose egress KagedCap supplies, which makes it the one we can shed: under load or egress pressure it returns 503 proxyless_disabled while proxied traffic is untouched. If ProxyLess is your only path, that 503 is an outage for you — build the fallback first: the same request with a proxy field and the suffix dropped.

Proxy formats the KagedCap API accepts

Two shapes, and the difference matters:

scheme://user:pass@host:port      →  http://u:p@1.2.3.4:8888
host:port[:user:pass]             →  1.2.3.4:8888:u:p

URL form accepts http, https, socks5, socks5h and socks4; anything else is refused pre-flight as 400 proxy_invalid, reason disallowed scheme <x>.

The colon form is always parsed as http. It has no scheme slot, so a SOCKS proxy written as host:port:user:pass is dialled as HTTP and will not work. Write SOCKS in URL form.

  • Port is required in the colon form, 1–65535; in URL form it can be omitted for a known scheme (http 80, https 443, socks 1080). No whitespace anywhere in the string.
  • Up to 2048 characters — residential providers pack zone, country, city, sticky-session id and TTL into the username, so one credential can run several hundred characters. An earlier 512-character limit rejected real traffic.
  • Credentials never reach logs: the value is rewritten to scheme://***:***@host:port before anything is written, and only host:port is stored.

The host is then resolved and every resolved address checked: loopback, RFC1918, link-local (including 169.254.169.254), CGNAT 100.64/10, multicast and their IPv6 equivalents are refused, as is a host that resolves to one of them or does not resolve at all. Each is 400 proxy_invalid; nothing is dispatched and nothing is billed.

proxy_unreachable is your side, not ours

Dead, overloaded or rate-limited proxies are the most common cause of failed solves we see. They get dedicated codes rather than the generic solve_failed / solve_timeout they used to hide behind, because reporting a proxy fault as a solver fault taught callers to retry us instead of fixing the proxy.

  • proxy_invalid, 400 — pre-flight: malformed, bad scheme, unresolvable, or a private/reserved target. No solve attempted.
  • proxy_unreachable, 502 — runtime: the solve ran and your proxy did not answer. 502, not 4xx, because the request was valid; the host it named was not.
  • solve_failed, 502 — a real attempt that failed.
  • key_frozen, 429 — the key tripped a per-key breaker after a burst of failed solves. The cool-off is in the message.
  • proxyless_disabled, 503 — ProxyLess temporarily off. Resend with your own proxy.

A frozen key is refused before dispatch, so retries during the cool-off cost you nothing and do not extend it — but they achieve nothing either. Wait it out and fix the pool.

Retry 429, 503 and 504 with backoff; never retry a 502 without changing something first. Only a 200 carrying a token is billed, so a bad proxy costs throughput, not balance.

When a solver is the wrong answer

You control the site. Allowlist your own automation and skip all of this. A shared-secret header your middleware checks before the captcha gate, a separate staging sitekey, or a test identity that skips the challenge in staging only — faster, deterministic, free, and it keeps CI off a risk-scoring path where a score change becomes a flaky test. Paying to solve your own challenge works around a config you can change.

You are not authorized to automate the target. Then stop. No proxy configuration makes that acceptable, and nothing here is advice for getting around a control put there to keep you out. This API is for sanctioned work — QA against properties you own, authorized monitoring and accessibility checks, internal workflows — where an agent doing legitimate work hits a gate built for abusive bots. If you cannot name who authorized the access, you do not have a proxy problem.

Your IP reputation is the actual problem. A solver does not repair a burnt pool. If scores are low across sitekeys and the pattern follows your egress rather than the target, change the proxies, not the solve type.

You need v2 checkbox with an image challenge. Not supported. v2 coverage is invisible only.

Common questions

Do you need a proxy to solve reCAPTCHA with the KagedCap API?

Only for non-ProxyLess reCAPTCHA tasks. The API decides by task-name suffix: ReCaptchaV2Task, ReCaptchaV3Task and ReCaptchaV3EnterpriseTask require a proxy field, while their ProxyLess counterparts must omit it. Sending the wrong combination returns HTTP 400 validation_error with the reason in the issues array. That rule applies to reCAPTCHA tasks only. The other task families have their own: EvaluateTask and KasadaLogin always require a proxy, KasadaReload needs none, and TicketmasterTmptTask treats it as optional.

What happens if I send a proxy with a ProxyLess task?

The request is rejected before any solve is attempted. You get HTTP 400 with the error validation_error and an issue whose path is proxy and whose message reads: ProxyLess tasks must not include a proxy. Nothing is dispatched and nothing is billed. Either drop the proxy field or drop the ProxyLess suffix from the task name. Those are the two valid requests.

What proxy formats does the KagedCap API accept?

Two. A full URL in the form scheme://user:pass@host:port, or the colon form host:port optionally followed by :user:pass. URL form accepts the schemes http, https, socks5, socks5h and socks4. The colon form has no scheme slot and is always parsed as http, so a SOCKS proxy must be written in URL form. The string may be up to 2048 characters, which accommodates residential providers that pack session state into the username, and it must contain no whitespace.

Does the proxy affect the reCAPTCHA v3 score?

Yes. A v3 token resolves to a score when your backend verifies it, and that score reflects the context the token was minted in, including the network it was minted from. The mismatch shows up at verification: siteverify accepts an optional remoteip and reCAPTCHA Enterprise's createAssessment accepts event.userIpAddress. If you pass the IP of the request replaying the token but the token was minted from an unrelated address, you have given the assessment two unrelated addresses for what is supposed to be one client. A token minted from an address related to your traffic is a stronger token. You can measure the difference on a property you own by sending your reCAPTCHA secret key with the solve and reading the verified score back.

What does the proxy_unreachable error mean?

HTTP 502 proxy_unreachable means the solve ran and your proxy did not answer. It is distinct from the HTTP 400 proxy_invalid pre-flight rejection, which fires when a proxy is malformed, uses a disallowed scheme, does not resolve, or points at a private or reserved address. proxy_unreachable is a caller-side fault: dead, overloaded or rate-limited proxies are the most common cause of failed solves we see. Do not retry it blindly, because repeated failures can trip a per-key breaker and return HTTP 429 key_frozen with a cool-off period.

Does retrying a frozen API key make the freeze last longer?

No. A frozen key is refused before dispatch, so a retry during the cool-off is neither billed nor counted as a failure, and it does not extend the freeze. It also accomplishes nothing. The freeze runs for a fixed cool-off that is stated in the error message. Wait it out and fix the proxies that caused the failure burst.

Should I use a solver on a site I own?

Usually not. If you control the site, allowlist your own automation instead: a shared-secret header checked before the captcha gate, a separate staging sitekey, or a test identity that skips the challenge in staging only. That is faster, deterministic, free, and it keeps your test suite off a risk-scoring path where a score change turns into a flaky test.

SupportDo You Need a Proxy to Solve reCAPTCHA? — KagedCap