Local captcha-solving HTTP sidecar — zero per-solve cost
The solver runs as an HTTP API on port 8877. Send a POST /solve with the captcha type, sitekey, and URL — get back a solved token.
curl -X POST http://127.0.0.1:8877/solve \
-H "Content-Type: application/json" \
-d '{
"type": "turnstile",
"sitekey": "0x4AAAAAAA...",
"url": "https://target.com"
}'
Response:
{
"type": "turnstile",
"solved": true,
"token": "0.eyJhbGciOiJFUzI1...",
"method": "route",
"elapsed": 8.1,
"expires_in": 300
}
solved field — it's the uniform success signal across ALL captcha types. Don't branch per-type.
Requests from 127.0.0.1 (localhost) require no auth. Remote requests need a Bearer token on protected endpoints.
| Endpoint | Auth |
|---|---|
GET / (Dashboard) | Public |
GET /health | Public |
GET /docs (Swagger) | Public |
GET /guide | Public |
POST /solve | Bearer Token |
GET /status | Bearer Token |
GET /logs | Bearer Token |
# Remote usage — add Authorization header
curl -X POST https://ircaptcha.isrealllairdrop.net/solve \
-H "Authorization: Bearer YOUR_TOKEN_HERE" \
-H "Content-Type: application/json" \
-d '{"type":"turnstile","sitekey":"0x4AAA...","url":"https://target.com"}'
| Method | Path | Description |
|---|---|---|
| GET | / | Dashboard UI |
| GET | /health | Liveness + supported types |
| GET | /guide | This documentation |
| GET | /docs | Swagger UI (interactive API docs) |
| POST | /solve | Solve a captcha → returns token |
| GET | /status | Service status + running tasks |
| GET | /logs | Recent solve events (last 100) |
Engine: CloakBrowser only (no AI). Route-intercept serves a fake page, widget solves itself, token extracted. ~8s avg.
| Field | Required | Note |
|---|---|---|
type | ✅ | "turnstile" |
sitekey | ✅ | From target page HTML |
url | ✅ | Page the captcha is on |
action | ❌ | Turnstile action string |
cdata | ❌ | Customer data bound to token |
real_page | ❌ | Navigate real site instead of stub |
Engine: CloakBrowser (v3/invisible = no AI, pure execute). v2 checkbox with image grid = Mistral Vision fallback. ~6s avg.
| Field | Required | Note |
|---|---|---|
type | ✅ | "recaptcha" |
sitekey | ✅ | Site key |
url | ✅ | Page URL |
version | ❌ | v2 (default) | v3 | invisible |
action | ❌ | v3/invisible action (default: submit) |
enterprise | ❌ | true for Enterprise keys |
secret | ❌ | v3 only: site's secret key to get score |
Engine: CloakBrowser + Mistral Vision (numbered-grid, 1 API call per challenge). ~20s avg.
| Field | Required | Note |
|---|---|---|
type | ✅ | "hcaptcha" |
sitekey | ✅ | Site key |
url | ✅ | Page URL |
action | ❌ | "invisible" for execute path |
Engine: CloakBrowser only. Passes full-page interstitial → returns cf_clearance cookie. No sitekey needed.
cf_clearance is bound to IP + JA3/TLS + User-Agent. Replay from the same proxy IP with the exact returned user_agent.
Engine: CloakBrowser only. Silent JS challenge → aws-waf-token cookie. No sitekey needed.
import httpx
SOLVER = "http://127.0.0.1:8877"
r = httpx.post(f"{SOLVER}/solve", json={
"type": "turnstile",
"sitekey": "0x4AAAAAAA...",
"url": "https://target.com/register"
}, timeout=90)
data = r.json()
if data["solved"]:
print(f"Token: {data['token'][:50]}...")
else:
print(f"Failed: {data.get('error')}")
import httpx
SOLVER = "http://127.0.0.1:8877"
# Step 1: Solve the captcha
solve = httpx.post(f"{SOLVER}/solve", json={
"type": "turnstile",
"sitekey": "0x4AAAAAAA...",
"url": "https://target.com/signup"
}, timeout=90).json()
if not solve["solved"]:
raise Exception(f"Captcha failed: {solve.get('error')}")
# Step 2: Register with the token
r = httpx.post("https://target.com/api/register", json={
"email": "user@mail.com",
"password": "securepass123",
"cf-turnstile-response": solve["token"]
})
print(f"Register: {r.status_code}")
r = httpx.post(f"{SOLVER}/solve", json={
"type": "recaptcha",
"version": "v3",
"enterprise": True,
"sitekey": "6Lc...",
"url": "https://target.com/login",
"action": "login"
}, timeout=90).json()
print(f"Solved: {r['solved']}, Score method: {r['method']}")
# Solve clearance
cf = httpx.post(f"{SOLVER}/solve", json={
"type": "cloudflare",
"url": "https://protected-site.com",
"proxy": "http://user:pass@resi-proxy:port"
}, timeout=90).json()
if cf["solved"]:
# Replay with curl-impersonate or matching TLS
cookies = {c["name"]: c["value"] for c in cf["cookies"]}
headers = cf["headers"] # includes exact User-Agent
print(f"cf_clearance: {cf['cf_clearance']['value'][:30]}...")
curl -s -X POST http://127.0.0.1:8877/solve \
-H "Content-Type: application/json" \
-d '{"type":"turnstile","sitekey":"0x4AAA...","url":"https://target.com"}' \
| jq '.token'
curl -s -X POST http://127.0.0.1:8877/solve \
-H "Content-Type: application/json" \
-d '{"type":"recaptcha","version":"v2","sitekey":"6Lf...","url":"https://target.com/form"}' \
| jq '.'
curl -s -X POST http://127.0.0.1:8877/solve \
-H "Content-Type: application/json" \
-d '{"type":"awswaf","url":"https://waf-protected.com","proxy":"http://u:p@ip:port"}' \
| jq '.aws_waf_token'
const SOLVER = "http://127.0.0.1:8877";
async function solveCaptcha(type, sitekey, url, opts = {}) {
const r = await fetch(`${SOLVER}/solve`, {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ type, sitekey, url, ...opts }),
});
return r.json();
}
// Usage
const result = await solveCaptcha("turnstile", "0x4AAA...", "https://target.com");
if (result.solved) {
console.log("Token:", result.token.slice(0, 50));
}
The typical flow for any auto-register / auto-login / airdrop farming script:
┌─────────────────────────────────┐
│ Your Script (Python/Node/etc) │
│ │
│ 1. Open target page / API │
│ 2. Find sitekey in HTML │
│ 3. POST /solve → get token │──── captcha-solver (:8877)
│ 4. Submit form with token │ │
│ 5. Continue automation │ CloakBrowser
└─────────────────────────────────┘ (headless Chromium)
Look in the target page HTML for these patterns:
<!-- Turnstile -->
<div class="cf-turnstile" data-sitekey="0x4AAAAAAA...">
<!-- reCAPTCHA -->
<div class="g-recaptcha" data-sitekey="6LcXXXX...">
<script src="...recaptcha/api.js?render=6LcXXXX...">
<!-- hCaptcha -->
<div class="h-captcha" data-sitekey="xxxxxxxx-xxxx-...">
type + url.
Some sites reject tokens from route-intercepted pages. Use real_page: true to navigate the actual site:
{"type": "turnstile", "real_page": true,
"url": "https://app.example.com/login",
"sitekey": "0x4AAA..."}
Steps to run before solving (e.g., click buttons, fill forms to make captcha appear):
"pre_actions": [
{"type": "click", "selector": "text=Continue with Email"},
{"type": "fill", "selector": "input[type=email]", "value": "user@ex.com"},
{"type": "click", "selector": "button[type=submit]"},
{"type": "wait", "value": "2"}
]
Supported selectors: CSS (default), //xpath, text=..., regex=..., role=button[name='X']
API calls from the same browser session after solving (keeps cookies/origin):
"post_fetch": [
{"url": "https://api.example.com/verify",
"method": "POST",
"body": {"token": "__TOKEN__"}}
]
Use __TOKEN__ placeholder — it's replaced with the solved token.
Two rules — 2xx → read solved; non-2xx → read detail. Never both.
{"type": "turnstile", "solved": true,
"token": "0.eyJ...", "method": "route",
"elapsed": 8.1, "expires_in": 300}
{"type": "turnstile", "solved": false,
"error": "Token not received via route-intercept",
"elapsed": 22.3}
{"detail": "sitekey is required for type=turnstile"}
| Code | When |
|---|---|
| 400 | Bad type, missing sitekey/url, SSRF-blocked host |
| 403 | Invalid or missing Bearer token (remote only) |
| 408 | Exceeded timeout_s deadline |
| 422 | Request body failed schema validation |
| 500 | Solver crashed (browser launch failure, etc) |
| Variable | Default | Effect |
|---|---|---|
PORT | 8877 | Listen port |
DISPLAY | :99 | X display for headed browser |
TURNSTILE_HEADLESS | 0 | 1 = headless (lower success) |
TURNSTILE_PROXY | — | Proxy URL for Turnstile/CF/WAF |
TURNSTILE_GEOIP | — | 1 = align tz/locale to proxy IP |
RECAPTCHA_HEADLESS | 0 | 1 = headless (more detected) |
RECAPTCHA_PROXY | — | Proxy URL for reCAPTCHA |