Third-Party Solvers: 2Captcha, CapSolver, Anti-Captcha
The main CAPTCHA-solving services in 2026. Pricing, API patterns, reliability differences.
What you’ll learn
- Compare 2Captcha, CapSolver, Anti-Captcha at a feature level.
- Understand the polling and callback API patterns.
- Pick a provider based on captcha type and volume.
When CAPTCHAs are unavoidable, you outsource the solve. Three services dominate. They differ in price, reliability per CAPTCHA type, and API ergonomics.
The major services
| Service | Founded | Notes |
|---|---|---|
| 2Captcha (also branded 2captcha.com) | 2014 | Largest; supports nearly every CAPTCHA type |
| CapSolver | 2021 | Newer; ML-driven; aggressive pricing |
| Anti-Captcha | 2007 | Oldest; reliable; sometimes higher prices |
| DeathByCaptcha | 2009 | Cheapest historically; smaller variety |
| CapMonster | (cloud variant) | Self-hosted ML solver + cloud option |
How solving works
All major services use a similar pattern:
- You submit the CAPTCHA (image, site key + URL, audio file).
- You receive a task ID.
- You poll the task ID until status = solved.
- You receive the solution (token or text).
import requests, time
API_KEY = "your-key"
def solve_recaptcha_v2(site_key, page_url):
# Submit
r = requests.post("https://2captcha.com/in.php", data={
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": site_key,
"pageurl": page_url,
"json": 1,
}).json()
if r["status"] != 1: raise RuntimeError(r["request"])
task_id = r["request"]
# Poll
for _ in range(60):
time.sleep(5)
r = requests.get("https://2captcha.com/res.php", params={
"key": API_KEY, "action": "get", "id": task_id, "json": 1
}).json()
if r["status"] == 1:
return r["request"] # the token to submit to the target
if r["request"] != "CAPCHA_NOT_READY":
raise RuntimeError(r["request"])
raise TimeoutError()
That's the pattern. The token returned is then submitted along with the form data on the target site.
Pricing (approximate, 2026)
| CAPTCHA | 2Captcha | CapSolver | Anti-Captcha |
|---|---|---|---|
| reCAPTCHA v2 | $1.00/1000 | $0.80/1000 | $1.50/1000 |
| reCAPTCHA v3 | $1.50/1000 | $1.20/1000 | $2.00/1000 |
| hCaptcha | $1.50/1000 | $1.00/1000 | $2.50/1000 |
| Image CAPTCHA | $0.80/1000 | $0.70/1000 | $1.00/1000 |
| FunCaptcha | $4.00/1000 | $3.50/1000 | $5.00/1000 |
| Turnstile | $1.50/1000 | $1.20/1000 | $2.00/1000 |
These are list prices. Volume discounts apply at $100+/mo commitments. Always verify current rates.
Reliability differences
For most CAPTCHA types, all three services hover at 90–95% solve success. Differences:
- 2Captcha has the broadest type support; if you need an obscure regional CAPTCHA, they're most likely to have it.
- CapSolver is ML-leaning; faster for image puzzles; less reliable for behavior-scored types.
- Anti-Captcha uses more human solvers; reliable but slower (often 30-60s per solve).
Speed matters: if your scraper times out waiting 60s for a solve, you've lost the session. Choose providers with average solve times under 20s for time-sensitive flows.
Integration patterns
Standalone Python
class CaptchaSolver:
def __init__(self, api_key, base="https://2captcha.com"):
self.key = api_key
self.base = base
def solve_recaptcha_v2(self, site_key, page_url, timeout=120):
# see code above
def solve_image(self, image_b64):
r = requests.post(f"{self.base}/in.php", data={
"key": self.key, "method": "base64", "body": image_b64, "json": 1
}).json()
# poll, return text
Wrap each service in a class. Switch providers via dependency injection.
Inside Playwright
async def with_captcha_handling(page):
if await page.locator("iframe[src*='recaptcha']").count() > 0:
# extract site key from page
site_key = await page.evaluate("() => document.querySelector('.g-recaptcha').dataset.sitekey")
token = solver.solve_recaptcha_v2(site_key, page.url)
# inject the token
await page.evaluate(f'document.getElementById("g-recaptcha-response").value="{token}"')
await page.evaluate("___grecaptcha_cfg.clients[0].O.O.callback('{token}')")
After solving, inject the token into the page's reCAPTCHA response field and call the callback. The page now considers itself "verified."
In Scrapy
A custom middleware that intercepts responses showing CAPTCHA, solves, retries:
class CaptchaMiddleware:
def process_response(self, request, response, spider):
if "data-sitekey" in response.text:
site_key = re.search(r'data-sitekey="([^"]+)"', response.text).group(1)
token = self.solver.solve_recaptcha_v2(site_key, response.url)
new_request = request.copy()
new_request.cookies["g-recaptcha-response"] = token
new_request.dont_filter = True
return new_request
return response
Per request, expensive, only enable when you know the route includes CAPTCHAs.
PHP integration
class CaptchaSolver
{
public function __construct(
private HttpClientInterface $http,
private string $apiKey,
) {}
public function solveRecaptchaV2(string $siteKey, string $pageUrl): string
{
$r = $this->http->request('POST', 'https://2captcha.com/in.php', [
'body' => [
'key' => $this->apiKey,
'method' => 'userrecaptcha',
'googlekey' => $siteKey,
'pageurl' => $pageUrl,
'json' => 1,
],
])->toArray();
if ($r['status'] !== 1) throw new \RuntimeException($r['request']);
$taskId = $r['request'];
for ($i = 0; $i < 24; $i++) {
sleep(5);
$r = $this->http->request('GET', 'https://2captcha.com/res.php', [
'query' => ['key' => $this->apiKey, 'action' => 'get', 'id' => $taskId, 'json' => 1],
])->toArray();
if ($r['status'] === 1) return $r['request'];
if ($r['request'] !== 'CAPCHA_NOT_READY') throw new \RuntimeException($r['request']);
}
throw new \RuntimeException('timeout');
}
}
Same pattern as Python. Register as a Symfony service, inject anywhere needed.
Optimization tips
-
Submit captcha solves asynchronously. Don't block the scraper waiting; queue the captcha task, work on something else, poll periodically.
-
Cache solves by site key + IP. If your IP holds a session, sometimes the same captcha token works for multiple requests. Verify per-site.
-
Use the cheapest service that meets your accuracy requirement. Higher accuracy isn't always needed. Test 2-3 services with your target's CAPTCHAs.
-
Pre-warm sessions. A logged-in user with a long session may not need to solve CAPTCHA again. Maintain long sessions where possible.
When solvers fail
- The site uses Enterprise tier (reCAPTCHA Enterprise, hCaptcha Enterprise). Solvers' success rate drops dramatically.
- The CAPTCHA is invisible and scoring you. No solve helps, you're scored, not gated.
- The site rotates challenges faster than the solver adapts (rare but happens with bespoke CAPTCHAs).
- Your IP is denylisted so any solve from your IP fails. Rotate proxies.
For these cases, commercial unblockers (§4.37) are usually a better fit.
Hands-on lab
Pick a site with reCAPTCHA v2 (many exist on signup pages):
- Sign up for a 2Captcha free trial (most services offer one).
- Write a Python script that solves the captcha and submits the form.
- Time the solve. Track success/failure rate over 10 attempts.
You'll feel both the cost and the latency. The exercise informs when solving is the right call vs avoidance.
Quiz, check your understanding
Pass mark is 70%. Pick the best answer; you’ll see the explanation right after.