Proxy Configuration
How to pass a proxy for tasks that require IP matching.
Some tasks need to be solved from your IP. For those, include a proxy in the task field (string or object).
{
"clientKey": "YOUR_API_KEY",
"task": {
"type": "ReCaptchaV2Token",
"websiteURL": "https://example.com",
"websiteKey": "6LeIxAcTAAAAAJcZVRqyHh71UMIEGNQ_MXjiZKhI",
"proxy": "http://user:[email protected]:8080"
}
}Keep the same IP for the whole solve
A solve is never a single request: the provider loads the page, interacts with the challenge, and fetches the result, all through your proxy. Most CAPTCHA flows additionally check that the IP that solved the challenge is the IP that later submits the form. Both only work when the proxy keeps one IP for the entire solve, so a proxy that rotates its IP on every request will make the solve fail or produce a token the target site rejects.
What works best in practice:
- Use a sticky session (every major rotating-proxy provider offers one): the proxy holds a single IP for a time window. Pick a window of at least 5 minutes so the IP cannot change mid-solve.
- Use one sticky session per solve. Don't share a session across parallel solves, and start a fresh session (fresh IP) for the next one.
- Submit the form through the same session that solved the challenge, so the IPs match.
Per-request rotating proxies will fail
Never pass a proxy endpoint that hands out a new IP on every request. If your provider only sells rotating proxies, use their "sticky" or "session" mode instead.
String formats
Schemes: http, https, socks4, socks5. No scheme defaults to http. Most providers only support http.
| Format | Example |
|---|---|
scheme://user:pass@host:port | http://admin:[email protected]:8080 |
scheme://user:pass:host:port | http://admin:secret:1.2.3.4:8080 |
scheme://host:port | socks5://1.2.3.4:1080 |
user:pass@host:port | admin:[email protected]:8080 |
user:pass:host:port | admin:secret:1.2.3.4:8080 |
host:port | 1.2.3.4:8080 |
| IPv6 | http://user:pass@[2001:db8::1]:8080 |
Passwords containing `:` and IPv6
The colon-separated user:pass:host:port form can't disambiguate passwords with : and does not support IPv6
addresses (the :s in the address collide). For passwords with colons or IPv6 hosts, use the @-separated form or
a full URL.
Object format
| Field | Type | Required | Description |
|---|---|---|---|
type* | Yes | Proxy protocol: http, https, socks4, or socks5. Example: | |
host* | string | Yes | Proxy server hostname or IP address. Example: |
port* | unknown | Yes | Port the proxy listens on (1 - 65535). Example: |
username | string | No | Username for proxy authentication (if required). Example: proxy-user. Example: |
password | string | No | Password for proxy authentication (if required). Example: proxy-pass. Example: |
{ "type": "http", "host": "192.168.1.1", "port": 8080, "username": "proxy-user", "password": "proxy-pass"}socks4 auth behavior
socks4 itself does not support username / password auth like http or socks5. We still accept those fields
for consistency, but many providers ignore them. If you need authenticated SOCKS, use socks5.
Multiple proxies
task.proxy accepts either a single proxy or an array of proxies. Mix strings and objects freely:
{
"task": {
"proxy": [
"http://user:[email protected]:8080",
{ "type": "http", "host": "5.6.7.8", "port": 8080, "username": "user", "password": "pass" }
]
}
}Rotation across attempts
When auto retry or auto fallback is enabled on a proxy task, each attempt consumes the next proxy in the array. Attempt 0 uses index 0, attempt 1 uses index 1, and so on. This avoids re-trying a banned or dead IP into the same failure.
If there are more attempts than proxies, the rotation wraps around to the start of the list, so you never have to size the array for the worst case. Provide as many distinct proxies as you want fresh IPs (up to 100); beyond that, attempts reuse earlier ones.
Because a single proxy would be sent to every attempt, a one-proxy task with retry or fallback enabled is rejected unless you opt in with allowProxyReuse: true. Pass an array to rotate instead:
{
"task": { "proxy": ["http://user:[email protected]:8080", "http://user:[email protected]:8080"] },
"settings": { "retry": { "enabled": true, "maxRetries": 1 } }
}To deliberately reuse a single proxy across every attempt, set allowProxyReuse: true:
{
"task": { "proxy": "http://user:[email protected]:8080" },
"settings": {
"retry": { "enabled": true, "maxRetries": 2 },
"allowProxyReuse": true
}
}No retry or fallback? Rotation doesn't apply
Rotation only matters when retry or fallback is enabled. A single proxy is fine for ordinary one-attempt tasks.
Which proxy was used
When a completed task used a proxy, getTaskResult returns it as usedProxy, exactly as you submitted it. With rotation, this is the final attempt's proxy. With settings.statistics enabled, the retry history additionally carries a per-attempt proxyIndex.
{ "usedProxy": { "index": 1, "type": "http", "host": "5.6.7.8", "port": 8080, "username": "user", "password": "pass" } }Proxy types
| Type | What it is | When to use it |
|---|---|---|
| Datacenter | Cheap IPs from cloud providers. Easy to fingerprint as non-human. | Low-protection sites and smoke tests. |
| Residential | Real ISP-issued home IPs leased through proxy networks. | Most CAPTCHA-protected flows. |
| Mobile | Carrier-issued mobile IPs (4G/5G). Hardest to block. | Heavily protected flows where residential is also flagged. |
Recommended
For most CAPTCHA-protected flows, sticky residential proxies give the best success rate without paying for mobile. Switch to mobile only when residential is consistently flagged. Either way, follow the one-IP-per-solve rule above.