v2.1.0 Operational
K
API Status Dashboard
API Reference • visusolve.yorubacinemax.xyz

Ship captcha solving
in under 5 minutes

VisuSolve is a high-performance AI captcha solver. ONNX runtime running locally—no third-party human farms. reCAPTCHA v2, v3, Geetest v4 at <400ms median latency, 99.9% uptime SLA, and predictable credit-based billing. Built for automation engineers, not CAPTCHA farms.

99.9% Uptime <400ms p50 latency 1.8M+ solves/day ONNX local inference
Built for developers

Unlike human-solver APIs, VisuSolve runs a fine-tuned vision transformer locally on your infra or ours. No queues, no human latency variance, no ethical concerns. You get deterministic JSON and a token you can submit directly.

What you get

  • reCAPTCHA v2 classification — image grid challenge solver (1×1, 3×3, 4×4) via POST /classify. Returns boolean mask.
  • reCAPTCHA v2 browser solver — full token flow via POST /solve with website_key + website_url. Returns g-recaptcha-response token.
  • reCAPTCHA v3 — score-emulation v3 solver, 0.9 score guaranteed, enterprise support.
  • Geetest v4 — slide, icon, gobang, AI, invisible, winlinze. Both full captcha_id flow and image gap detection.
  • Management plane — balance, usage, API key rotation.
  • MV3 Extension — auto-detects captchas on any page, solves in-place.
BASE https://visusolve.yorubacinemax.xyz TLS 1.3

Quickstart #

Get your first solve in under 2 minutes. Three steps: create an account, grab an API key, make a request. We'll show all three languages side-by-side in the right panel — use the tabs to switch.

1. Create account & get API key

Go to visusolve.yorubacinemax.xyz/signup, sign up, and copy your key from Dashboard → API Keys. New accounts get a bonus key with 1000 free credits that expires after 30 days if unused. You can create unlimited additional keys per service/worker.

Bonus credits auto-applied

Your first 1000 solves are free with the bonus key. No credit card required. All endpoints available on free tier. Upgrade anytime in dashboard.

2. Install httpx (Python) or use fetch (JS)

Python: pip install httpx — 3.9+ recommended, async support built-in. Node.js 18+ has global fetch. Bun/Deno also work identically.

3. First real request — classify

Classify a reCAPTCHA v2 grid challenge. Replace sk_live_xxx with your real key. The right panel shows the full payload — base64 image can be raw or data-URI.

4. Handle dynamic refresh

Google sometimes sends a second grid after first selection (e.g. you selected 3 crosswalks, now it asks for new images with crosswalks again). Implement a loop: while response contains target tiles, click them in your automation (Selenium/Playwright) and call /classify again with new tiles. Max 3 iterations is safe; more looks bot-like.

5. Go production

  • Add retry with exponential backoff on 429/500/503 (see Error Handling)
  • Cache website_key parsing; don't scrape target HTML on every solve
  • Use solving_id to correlate logs
  • Monitor balance via GET /api/balance in a cron; alert if <100 credits
BASEhttps://visusolve.yorubacinemax.xyz All endpoints under here

Testing with curl

All endpoints are curl-friendly. Use the cURL tab. For image heavy endpoints, save base64 to file and use $(cat file.b64).

Authentication #

All API requests are authenticated via API key. Keep keys secret—they have full access to your credits and solves.

Methods

You can authenticate using either header or query param (header preferred).

MethodExampleNotes
X-API-Key headerX-API-Key: sk_live_abc123...Recommended, not logged in CDN
?key query?key=sk_live_abc123...Fallback for browser img GETs
Authorization BearerAuthorization: Bearer sk_live_...Alias, accepted

Key format

  • Prefix sk_live_ for production, sk_test_ reserved for future sandbox.
  • Length 48-64 chars after prefix, URL-safe alphanum.
  • Example placeholder: sk_live_4eC39HqLyjWDarjtT1zdp7dcEXAMPLE
Security

Never expose keys in client-side JS. Use server-to-server calls. Rotate if committed to git. Enable IP allowlist in Dashboard → Security if available.

Getting a key

  1. Create account at visusolve.yorubacinemax.xyz/signup
  2. Verify email
  3. Dashboard → API Keys → Create Key → Copy
  4. Bonus key (1000 credits) auto-created; deletable after upgrade

SDKs & Libraries #

Official SDKs wrap the REST API with retry, backoff, and typed responses. Bring your own http client if you prefer.

LanguageInstallStatus
Pythonpip install visusolve (coming soon) / use httpxsnippet ready
JavaScript / Nodenpm i visusolve (coming soon) / native fetchsnippet ready
GoCommunityplanned
cURLsupported

Until SDKs ship, use the cURL/Python/JS snippets in the right panel. They are production-grade with timeouts and error handling.

reCAPTCHA v2 — POST /classify #

Primary endpoint. Classifies a reCAPTCHA v2 image challenge grid: given images (base64) and target keyword like "Select all images with traffic lights", returns boolean array of which tiles match.

POST /classify 1 credit / req

Request body (JSON)

ParamTypeRequiredDescription
images required if no image_base64string[] (base64)conditionalArray of base64-encoded image tiles. For 3×3 grid, 9 images. Can be raw base64 or data URI data:image/jpeg;base64,.... Max 16 images per request.
image_base64string (base64)conditionalSingle image containing the full grid (most clients use this). Server auto-splits by grid_size.
target_keyword requiredstringyesChallenge text like "traffic lights", "buses", "crosswalks", "fire hydrant", etc. Lowercased internally; partial match OK.
gridenumno"1x1" (single image choice), "3x3" (default), "4x4". If omitted, inferred from images length.
grid_sizeintegernoAlias for grid: 3 = 3×3, 4 = 4×4. Precedence: grid > grid_size.
modeenumno"fast" (default, ~150ms), "accurate" (~320ms, better on ambiguous). Use accurate for crosswalk / chimney.
solving_idstringnoClient-side correlation ID for logs & support. Returned in X-Request-Id.
target_sitestringnoDomain hint for fine-tuned models (e.g. "google.com"). Optional.

Response 200

FieldTypeDescription
successbooleanTrue if inference succeeded
databoolean[]Length == grid count. True = tile contains target
confidencefloat[] (optional)Per-tile confidence 0-1 when mode=accurate
model_versionstringe.g. v2.1.0-onnx-fp16
time_taken_msintegerServer inference time ms
Dynamic challenges

Some v2 challenges refresh after first selection. Call /classify again with new tiles. Best practice: implement loop with max 3 iterations; each iteration is 1 credit.

reCAPTCHA v2 — POST /solve (browser solver) #

Full browser automation solve. You provide website_key and website_url; server spins headless browser (optional proxy) and returns a valid g-recaptcha-response token ready to POST to target site.

POST /solve 3 credits / solve
ParamTypeRequiredDescription
website_key requiredstringyesData-sitekey from target page (e.g. 6Le-wvkSAAAAAPBMRTvw0Q4Muexq9bi0DJwx_mJ-)
website_url requiredstring URLyesFull URL where captcha loads
timeoutinteger (sec)noMax wait sec, default 60, max 120
proxystringnohttp://user:pass@host:port or socks5://...
is_invisiblebooleannotrue for invisible v2

Response

FieldTypeDescription
tokenstringg-recaptcha-response token string
time_takenfloatsec
solvedboolean

reCAPTCHA v2 — Code examples #

Copy-paste production snippets. Handle dynamic refresh by looping until no target tiles remain (google tracks behavior).

Best practices

  • Always send target_keyword lowercase, trimmed.
  • For base64 images, strip data:image/...;base64, prefix server accepts both but raw is faster.
  • Retry once on 429/503 with exponential backoff.
  • Cache sitekey → avoid re-parsing HTML each time.

reCAPTCHA v3 — POST /api/v3/solve #

Emulates v3 client behavior and returns a valid enterprise-grade token with high score (0.7–0.9). Token must be verified server-side by target within 2 minutes.

POST/api/v3/solve 2 credits
ParamTypeRequiredDescription
website_key requiredstringyessitekey
website_url requiredstring URLyesURL where v3 loads
actionstringnogrecaptcha action, e.g. "submit", "login", "homepage". Default "submit"
remote_ipstring IPv4noEnd-user IP to tie token to (recommended for anti-abuse)
is_enterprisebooleannoEnterprise endpoint variant
proxystringnoProxy URL

Response

FieldTypeDescription
tokenstringv3 token (JWT-like, ~400-800 chars)
scorefloatEmulated score ~0.9
actionstringEchoed action
time_takenfloat secTotal time
successboolean
Score explanation

reCAPTCHA v3 returns a score 0.0–1.0. VisuSolve emulates human-like browsing signals to achieve 0.7–0.9 consistently. If target requires 0.9+, set a realistic action matching frontend (not generic "submit") and pass remote_ip.

reCAPTCHA v3 — POST /api/v3/verify #

Verify a token returned from /solve before forwarding to your backend. Validates token shape, expiry, and optionally remote_ip binding.

POST/api/v3/verifyfree
ParamTypeRequiredDescription
token requiredstringyesToken to verify
remote_ipstringnoIf token was bound to IP

reCAPTCHA v3 — GET /api/v3/health #

Healthcheck for v3 solver cluster. Returns uptime, model version, avg latency.

GET/api/v3/healthno auth, cached

Geetest v4 — POST /api/geetest/v4/solve #

Solves Geetest v4 challenges — slide, icon, gobang, AI, invisible, winlinze captcha. Provide captcha_id (gt + challenge combined or just captcha_id) and risk_type. Returns lot_number + captcha_output + etc required to pass verification.

POST/api/geetest/v4/solve 2 credits
ParamTypeRequiredDescription
captcha_id requiredstringyesGeetest captcha_id, e.g. 54088bb07d2df3c46b79f80300b0ab6b or full gt+challenge JSON string
risk_typeenumnoslide (default), gobang, icon, ai, invisible, winlinze. Auto-detect if omitted but slower.
proxystringnoProxy URL
user_agentstringnoCustom UA

Response

FieldTypeDescription
lot_numberstringlot_number for verification payload
captcha_outputstringcaptcha_output
pass_tokenstringpass_token
gen_timestringgen_time
captcha_idstringechoed

Geetest v4 — POST /api/geetest/v4/solve-image #

Low-level image gap solver: you supply Geetest background + slice (puzzle piece) image URLs (or base64), we return gap x coordinate / slide distance. Use when you have already extracted images client-side.

POST/api/geetest/v4/solve-image1 credit
ParamTypeRequiredDescription
background_urlstring URL / base64conditionalBackground image URL or base64
slice_urlstring URL / base64conditionalSlice (puzzle piece) image
background_base64string base64altAlternative to background_url
slice_base64string base64altAlternative to slice_url
ResponseTypeDescription
gapintegerx coordinate px from left
gap_ratiofloat 0-1normalized x position
confidencefloat0-1

Geetest v4 — GET /api/geetest/v4/health #

Healthcheck for Geetest solvers.

GET/api/geetest/v4/health

Management — GET /api/balance #

Returns credit balance, usage today, and bonus credits left.

GET/api/balance

Response

FieldTypeDescription
balanceintegerRemaining credits
bonus_remainingintegerFree tier left
total_usedintegerTotal lifetime solves
planstringfree | starter | pro | enterprise

Management — GET /api/usage #

Daily usage breakdown, per-endpoint counts, error rate, p50/p95 latency.

GET/api/usage?range=7d
QueryTypeDescription
rangeenum1d 7d 30d 90d default 7d
granularityenumhour day default day for 1d/7d, day for others

Management — API Keys CRUD #

Programmatic key management. Bonus key cannot be deleted via API for safety—it requires dashboard confirmation.

GET/api/keysList keys (metadata only, no secret suffix)
POST/api/keysBody: { name: "prod-server-1" }
DELETE/api/keys/{id}
POST/api/keys/{id}/regenerateOld key invalidated immediately

Create key request

ParamTypeDescription
namestringLabel, e.g. "prod-api"
expires_in_daysintegerOptional TTL, default never
rate_limit_rpmintegerOptional per-key RPM override

Response on create

Only time full key is returned. Store securely immediately.

FieldType
iduuid
keystring sk_live_...
namestring
created_atISO8601

Webhooks #

For long-running browser solves (/solve), optionally provide webhook_url to get async callback when token is ready instead of polling.

FieldTypeDescription
webhook_urlstring URL httpsAdd to /solve or /api/v3/solve body. Server POSTs JSON with token on completion.
webhook_secretstringOptional HMAC SHA256 signed in header X-Webhook-Signature
Verification

Webhook payloads include event: "solve.completed", token, solving_id, time_taken. Verify signature: HMAC-SHA256(webhook_secret, raw_body) equals header X-Webhook-Signature.

Browser Extension (MV3) #

Official Chrome MV3 extension auto-detects reCAPTCHA v2/v3 and Geetest v4 on any page and solves in-place using your VisuSolve key. No code changes needed.

Install

  1. Download extension.zip from VisuSolve.
  2. Unzip locally: unzip extension.zip -d visusolve-extension
  3. Open chrome://extensions, enable Developer mode (top right toggle).
  4. Click Load unpacked → select visusolve-extension folder.
  5. Pin extension from toolbar puzzle icon.
  6. Click extension icon → paste your sk_live_... key → Save.

How it works

  • Content script observes DOM for iframe[src*="recaptcha"], div.geetest_*, #g-recaptcha, etc.
  • On detection, extracts images / sitekey / url and sends to VisuSolve API via background worker.
  • For v2 grid, overlays checkboxes auto-clicked; for token flow, fills g-recaptcha-response and dispatches callback.
  • Extension popup shows remaining balance, toggle per-site enable/disable, and auto-solve on/off.
  • No browsing data leaves device except captcha payloads directly to visusolve.yorubacinemax.xyz. No analytics.
Permissions

Extension requests activeTab + storage + host permission for visusolve domain only on install, then optional <all_urls> after user approval for auto-detect. You can limit to specific sites in extension settings.

Error handling #

Standard HTTP status + consistent JSON error shape. Always check HTTP status before parsing body.

StatusMeaningRetry?
400Bad request — missing param, invalid base64, unsupported gridFix request, no retry
401Missing or invalid API keyNo
402Insufficient credits — balance exhaustedTop up or wait reset
403Key revoked / IP blocked / bonus key expiredNo
429Rate limit exceeded (RPM per key or global)Yes, with backoff, respect Retry-After
500Server error — ONNX runtime failureOnce, after 1s
503Service overloadedYes, after Retry-After

Error response shape

Always JSON:

Rate limits #

Prevent abuse and ensure fairness. Limits are per-API-key, sliding window 60s.

TierRPMCreditsConcurr.
Bonus (Free)30 RPM1000 free2
Starter120 RPM10k/mo10
Pro600 RPM50k/mo40
EnterpriseUnlimited*CustomCustom

Credit costs

EndpointCost
POST /classify (v2 grid)1 credit
POST /api/geetest/v4/solve-image1 credit
POST /api/v3/solve2 credits
POST /api/geetest/v4/solve2 credits
POST /solve (browser)3 credits
Management GET /api/balance, /api/usage, /health0 credits

Headers

HeaderDescription
X-RateLimit-RemainingRequests left in window
X-RateLimit-ResetUnix epoch sec when window resets
Retry-AfterSeconds to wait when 429/503
X-Request-IdUnique request ID for support

Security best practices #

Treat API keys like passwords.

  • Server-side only — never embed keys in frontend JS, mobile apps, or public repos.
  • Env vars — load from VISUSOLVE_API_KEY env var or secrets manager, never hardcoded.
  • Rotate regularly — use POST /api/keys/{id}/regenerate quarterly or after personnel change.
  • Per-service keys — create separate keys per service (e.g. prod-worker vs staging) so you can revoke one without downtime.
  • Proxy through backend — if you must solve from browser, proxy through your backend that adds X-API-Key server-side.
  • Monitor usage — set up alerts on sudden spike via /api/usage.
  • Webhook sig — always verify X-Webhook-Signature if using callbacks.

Data handling

We do not log image payloads. Only metadata (grid size, keyword hash, time_taken, result count) kept for metrics 7 days. ONNX inference runs in isolated sandbox, no outbound network. GDPR compliant—no PII stored beyond account email.

Pricing #

Simple credit system. 1 solve ≈ 1 credit except browser & v3/geetest flows (see rate limits). Unused credits roll over 1 month on paid plans.

Free

Perfect to test

$0/forever
  • 1,000 bonus solves
  • v2 / v3 / Geetest v4
  • 30 RPM
  • No SLA
Pro

Automation at scale

$49/month
  • 50,000 solves + rollover
  • 600 RPM, priority queue
  • 99.9% SLA, webhook, IP allow
  • Discord + email priority

Enterprise: custom volume (500k+), dedicated ONNX pool, on-prem deploy option, audit logs, SSO. Contact sales@visusolve.

Integrations & Framework Adaptors #

VisuSolve integrates with popular automation stacks via lightweight adaptors. No heavy SDK — just drop-in helpers.

Puppeteer Extra

Use puppeteer-extra + puppeteer-extra-plugin-stealth to avoid detection. VisuSolve token injection works even with stealth.

StackRecommended patternCredits
Selenium 4 gridExtract tiles via execute_script canvas -> /classify -> Actions click1 per classify call
PlaywrightframeLocator + evaluate canvas -> /classify, or /solve fallback1-3
Puppeteerpage.$eval tile extraction -> /classify1
ScrapyMiddleware: on captcha middleware pause -> /solve token -> retry request with token header2-3
curl / cronUse balance endpoint to gate; /health before batch

Environment variables reference

VarDescription
VISUSOLVE_API_KEYYour sk_live_... key
VISUSOLVE_BASE_URLOverride base, default https://visusolve.yorubacinemax.xyz
VISUSOLVE_TIMEOUTSeconds, default 15 for classify
VISUSOLVE_RETRIESDefault 2

Docker

For self-hosted Enterprise: docker run -p 8000:8000 visusolve/on-prem:latest exposes same API on localhost. License key via VISUSOLVE_LICENSE env. Health at :8000/health.

Rate limit env

On-prem has no rate limit; you control concurrency via gunicorn workers --workers 4. Each worker holds one ONNX session (~1.2GB VRAM if GPU, 600MB RAM if CPU).

Models — accuracy, latency, versioning #

We version every model. Use model_version field in responses for debugging. Pinning not supported — you always get latest stable; changelog announces improvements.

ModelVersionLatency p50AccuracyNotes
v2 fastv2.1.0-fp16~142ms96.3% tile224px, vit-small
v2 accuratev2.1.0-fp32-tta~320ms98.1% tile320px + flip TTA
v3v3.0.2~870ms0.9 score 98% of time, 0.7+ 100%enterprise + normal
geetest slidegt4-slide-v1.3~210ms image, ~1.2s full captcha_id99.1% gap <3pxONNX+cv2 fallback
geetest icongt4-icon-v1.1~380ms96.8%

Evaluation methodology

Internal set: 12k v2 challenges scraped from google domains, balanced across 15 keywords (bus, car, traffic light, crosswalk, bicycle, fire hydrant, truck, motorcycle, boat, airplane, parking meter, bench, etc). Accuracy measured tile-level IoU >0.5 and end-to-end solve (checkbox checked). Sets rebuilt weekly to avoid overfit.

Rate Limits Deep Dive & Concurrency Control #

Understanding limits helps you avoid 429s and build adaptive concurrency.

Sliding window algorithm

We use Redis-backed sliding window per API key, 60s window. At 100% Pro RPM 600, you can burst 20 in first second, but remainder throttled. Use token bucket mental model: refill rate = RPM/60 per second.

Adaptive client example (pseudocode)

Start with semaphore = RPM. If 429 received, halve semaphore and sleep Retry-After. If 10 successes in row, increment semaphore by 1 until Max. This converges near limit without constant 429s.

Headers recap

HeaderMeaning
X-RateLimit-LimitYour max RPM (e.g. 600)
X-RateLimit-RemainingRequests left in current 60s window
X-RateLimit-ResetUnix sec when window resets, can use for precise sleep
Retry-AfterSeconds to wait when 429/503, honor this
X-Request-IdUnique id for support, include in tickets

Credit vs rate limit

Rate limit is requests per minute, credit is lifetime / monthly usage. You can have credits but be rate limited if too fast. Also you can have 0 credits and well under rate limit — then 402.

Free tier queue

Bonus key requests share a shared async queue that may delay 1-2s at peak. Upgrade Starter to skip queue (dedicated workers).

Testing & Sandbox #

No separate sandbox today: use bonus key for testing, 1000 credits enough for ~100 test solves. For unit tests, mock VisuSolve response: return { success: true, data: [true,false,...] } for /classify, and { token: "test_token_"+random } for /solve.

Fixtures for CI

  • Save a base64 tile fixture set in repo (not the real challenge? use synthetic white images) — mock classify returns deterministic.
  • Integration tests: if CI has VISUSOLVE_API_KEY, run 1 real /classify request with 1 tile grid 1x1 and keyword "bus" to assert success true and time_taken_ms <1000.
  • For v3, test token shape: starts with 03AG or 03AF and length 400-1200.

FAQ #

No. All solvers run locally via ONNX Runtime with a fine-tuned vision transformer. No queues, no human latency variance, deterministic results. We never forward your images to third parties.
On our internal eval set (12k challenges across crosswalk, bus, traffic light, bicycle, fire hydrant, etc), fast mode: 96.3% tile accuracy, accurate mode: 98.1%. End-to-end solve rate ~92% on first attempt, ~98% with up to 2 dynamic refresh retries.
You should not expose API keys client-side. Proxy via your backend or use the official Chrome extension which stores key securely in extension storage. If you must, scope key with low RPM and short expiry.
Yes, set is_enterprise: true. Enterprise uses different endpoint domain (recaptchaenterprise.googleapis.com) — our solver handles both.
Give us captcha_id from your target page (found in network request to gcaptcha4.geetest.com). We solve and return payload fields to submit back to Geetest validation API. We also offer low-level image gap endpoint if you extracted images yourself.
You'll get HTTP 429 with Retry-After header. Implement exponential backoff. On Pro plan you can request burst increase via Dashboard → Support. All rate limit responses include X-Request-Id to share with support.
Yes on Enterprise plan. We provide Docker image with ONNX runtime + gRPC API, license-checked hourly. Contact sales for evaluation.
Use Dashboard → Logs → Report, include X-Request-Id. We review and retrain weekly. Bonus: reports that lead to model improvement earn credit rewards.

SDKs Deep Dive — patterns #

Until official SDKs ship, here are robust integration patterns for Python httpx and Node fetch that handle retries, timeouts, and logging idiomatically.

Python sync client pattern

Wrap VisuSolve in a class with tenacity/retry. Use httpx.Client to reuse TCP connections — important at high QPS.

Python async + asyncio.gather

For bulk solving, use httpx.AsyncClient + asyncio.Semaphore(limit=10) to parallelize while respecting rate limits. Example in right panel scales to ~6 solves/sec on Pro.

Node.js batch

Use p-limit for concurrency. Set fetch timeout via AbortController. Example: solve 100 v2 grids in parallel with 10 concurrency, total ~15s.

Playwright integration

Typical flow: page.goto(url) → page.evaluate -> extract base64 tiles via canvas → call VisuSolve → page.click() on matching tiles using checkbox selectors → loop.

Changelog #

We ship weekly model improvements. No breaking changes without major version bump.

VersionDateNotes
v2.1.02026-07-15Geetest v4 winlinze support, 12% latency cut on v2 fast mode, accuracy mode for crosswalk/chimney improves 1.8pp
v2.0.02026-06-20Brand rename Solvify→VisuSolve, base URL moved to visusolve.yorubacinemax.xyz (old URL 301), ONNX fp16, v3 enterprise
v1.9.22026-05-02Extension MV3 stable, auto-detect Geetest, popup balance refresh
v1.9.02026-04-10v3 solve GA, score 0.9 default, verify endpoint
v1.8.02026-03-01Geetest v4 GA (slide, icon, gobang, ai)

Common Playbooks #

Playbook 1: Selenium + VisuSolve v2

  1. Driver finds iframe[src*="recaptcha/api2/bframe"]
  2. Extract data-sitekey via JS
  3. Wait for checkbox click → image challenge appears
  4. Scrape .rc-imageselect-tile images as base64 via canvas.toDataURL
  5. Read instruction via .rc-imageselect-instructions
  6. POST /classify → get boolean mask → click tiles where true
  7. Click Verify, loop if new challenge, else extract token via grecaptcha.getResponse() or via hidden textarea

Playbook 2: v3 token injection

  1. Frontend loads grecaptcha via script? Extract sitekey
  2. POST /api/v3/solve with sitekey + page url + action (find action in page JS, often grecaptcha.execute(key, {action: 'submit'}))
  3. Receive token, inject into form: POST your form with g-recaptcha-response=TOKEN
  4. Token valid ~110 sec, single use

Playbook 3: Geetest v4 from browser network tab

  1. Open target site with DevTools → Network tab → filter gcaptcha4
  2. Find request to /load → copy captcha_id
  3. POST /api/geetest/v4/solve with captcha_id → receive lot_number etc
  4. Call Geetest verify endpoint /verify with those fields + your challenge payload (docs on Geetest site)

Health & System — GET /health #

Global health check for the entire platform — model status, queue depth, and region. No auth required, suitable for uptime monitors and load-balancer health probes. Returns 200 even when degraded, check status field.

GET/healthpublic, no auth, cache 5s
FieldTypeDescription
statusstringok | degraded | down — degraded when queue >50 or latency p95 >800ms
uptime_secintegerSeconds since last deploy, resets on rolling deploys
modelsobjectPer-model status: v2, v3, geetest_v4 with version, latency p50/p95, queue depth, healthy bool
regionstringCurrent serving region: us-east-1, eu-west-1, ap-southeast-1 (auto-routed via latency)
versionstringAPI version e.g. v2.1.0
GET/api/v3/healthv3 cluster only
GET/api/geetest/v4/healthgeetest cluster only

Recommended monitors

  • Ping /health every 30s from your uptime checker (BetterUptime, StatusCake)
  • Alert if status != ok for >2 minutes
  • For Pro, monitor X-RateLimit-Remaining drop <10% as early warning to auto-buy more credits webhook (future)

Concurrency & Performance Tips #

VisuSolve is built for throughput. Median /classify latency is <400ms, p95 <650ms, p99 <950ms on Pro. Here is how to squeeze max QPS without 429s.

  • Reuse connections — Use httpx.Client / fetch with keep-alive. TCP+TLS handshake is ~80ms, inference is ~140ms, so reuse saves 36%.
  • Batch vs parallel — /classify accepts up to 16 images array; if you have 3x3 grid, single request is cheaper than 9 separate. For multiple pages, parallelize across pages with semaphore.
  • Model warm — First request after idle may be ~30% slower due to ONNX session cold start. Send a dummy request on app boot to warm. Example: POST with 1x1 white pixel and keyword "bus" — costs 1 credit but warms model worker.
  • mode=fast vs accurate — fast uses FP16 224px input tensor, accurate uses FP32 320px + TTA (horizontal flip). Use fast unless tile class is crosswalk, chimney, or traffic light in fog/night — those +1.8pp better in accurate.
  • Timeout tuning — Set client timeout = server expected + 2s. For /classify: 10s client; for /solve: 90s; v3: 40s; geetest slide: 30s.
  • Async bulk — Use httpx.AsyncClient + asyncio.Semaphore(10-40 depending on plan) to saturate your RPM without 429s. See right panel bulk example.
  • Proxy hint — For /solve browser flow, pass fastest proxy you can; solver's headless chromium will use it for target site. If no proxy, solver uses datacenter egress which some sites block.

Latency breakdown (typical /classify)

PhaseTimeNotes
TLS handshake (if new conn)60-120msEliminate via Client reuse
Image decode + resize8-15msServer side
ONNX inference (fast)90-160msGPU shared, FP16
Post-process + JSON ser4-8ms
Total p50~140msWith keep-alive

Automation — Selenium, Playwright, Puppeteer #

Complete end-to-end examples are in the right panel (see advanced client + Playwright groups). Key ideas for each framework:

Selenium 4

  • Use driver.execute_script to extract tiles via canvas (avoid screenshot cropping offset bugs especially on HiDPI).
  • Click tiles using Actions API move_to_element with pause(80-150ms) to look human; Google tracks mouse trajectory for some challenges.
  • Sometimes checkbox re-renders after click — wait for .rc-imageselect-dynamic-selected count to stabilize before clicking Verify.
  • Disable dom.webdriver.enabled pref or use undetected-chromedriver / selenium-stealth.
  • Always set realistic navigator.userAgent and languages — not headless default.

Playwright (recommended)

  • Preferred for reliability + auto-wait. Use page.locator + frameLocator for bframe — outer page & checkbox are separate iframes.
  • For base64, use Playwright's locator.evaluate(el => canvas) method — see right snippet. Do NOT use screenshot as it may be throttled by target's CSP.
  • Enable --disable-blink-features=AutomationControlled and real user-agent; VisuSolve does not need that but target site does.
  • Playwright trace viewer useful for debugging dynamic refresh loops.

Puppeteer

Similar to Playwright; use page.$eval to pull images. Remember to await page.waitForTimeout after each tile click to let Google validate (300-600ms). Enable stealth plugin puppeteer-extra-plugin-stealth.

Stealth & proxies

VisuSolve solves the image challenge, but target site may have additional bot detection (Cloudflare, DataDome, Imperva). Use a residential proxy for /solve browser flow if you get 403 on target even with valid token. Token validation happens at target site, not ours.

Dynamic challenge loop detail

Google may refresh tiles after you click some. Logic:

  1. Call /classify with current tiles → get mask → click true tiles.
  2. Wait 400ms; check if new images loaded (compare image src or use MutationObserver via evaluate).
  3. If new images, repeat from step 1 with only new tiles (some tutorials require re-classifying whole grid — safe to just classify whole 3x3 again).
  4. If no new images after Verify, check for checkbox checked or new challenge. Max 4 rounds.
  5. If still unsolved, fall back to /solve browser API and request a fresh token (costs 3 credits but saves manual loops).

Troubleshooting #

Common issues and fixes. Always include X-Request-Id from response headers when contacting support.

SymptomCauseFix
401 invalid api key / unauthorizedCopy paste error, extra newline/space, or bonus key deleted/expiredRegenerate key in dashboard, strip whitespace, load from env var VISUSOLVE_API_KEY, ensure header name X-API-Key exact
402 insufficient credits (error insufficient_credits)Balance zero, bonus expired, or monthly reset hitCheck GET /api/balance, dashboard → Billing → Top up. 402 also returned if per-day burst limit exceeded on Free
Classify returns all false for traffic lightsWrong target_keyword e.g. "traffic light" vs "traffic lights" or language mismatch (German etc)Use exact keyword lowercased matching challenge text; model supports EN, DE, FR, ES, PT, ZH auto-translated internally but pass EN for best
v3 token rejected by target site with "invalid-input-response"Action mismatch, token expired (>120s), or IP mismatch when target reuses remoteipEnsure action equals page's grecaptcha.execute action string, submit within 110s, pass same remote_ip as user if target validates it
Geetest solve fails with invalid captcha_idWrong captcha_id format — often grabbing gt challenge instead of captcha_id from /loadOpen Network tab, filter gcaptcha4.geetest.com/load, copy captcha_id query param (32 hex chars), not gt file
First request slow ~800ms, next 150msModel cold start after 15m idle on Free tierWarm on app start, or upgrade Starter to keep worker warm 24/7
Dynamic refresh loops forever / never becomes checkedGoogle sends new challenges if prior selection wrong or mouse path flaggedMax 3 rounds, then call /solve browser API fallback; add random delays 120-300ms between tile clicks; use Playwright not bare httpx for click simulation
403 from target even with valid tokenTarget site has extra WAF / Cloudflare / bot detection beyond captchaUse residential proxy, realistic UA, and ensure cookies from target site accompany token submit request
Still stuck?

Run GET /health, copy X-Request-Id from failing request, and email both to [email protected] with your keyword + grid size. We reply within 4h on Pro.

Support & SLA #

Pro plan includes 99.9% monthly uptime SLA. Credits refunded pro-rata on downtime >0.1%. Enterprise includes dedicated Slack channel + 1h initial response + 4h resolution target.

  • Email: [email protected] — include X-Request-Id
  • Dashboard logs: every request logs time_taken, model_version, balance remaining — searchable by solving_id
  • Discord: link in dashboard footer (invite-only for Pro+ customers)
  • Status page: /health — bookmark for monitors, supports HEAD as well
  • Changelog: see section above — no breaking API changes without major version bump (v2 → v3 etc)

Data retention & privacy

We do not retain base64 images. Only hashed keyword + grid size + latency + result count stored 7 days for metrics. ONNX inference runs in gVisor sandboxed container, no outbound network allowed. GDPR: we store only email + hashed IP for rate limit. DPA available on request for Enterprise.

Webhook Signature Verification — Detailed #

When you configure webhook_url in /solve or /api/v3/solve, VisuSolve POSTs JSON to your endpoint within 100ms of solve completion. Verify HMAC SHA256 to prevent spoofing.

Headers

HeaderExample
X-Webhook-Signaturesha256=5d9c...
X-Request-Idreq_...
Content-Typeapplication/json
User-AgentVisuSolve-Webhooks/2.1

Payload shape

FieldType
event"solve.completed" | "solve.failed"
tokenstring (when completed)
solving_idstring client correlation id
time_takenfloat sec
errorstring when failed

Verification in Python:

VERIFYHMAC-SHA256(webhook_secret, raw_body_bytes).hexdigest()

Compare constant-time (hmac.compare_digest). If signature missing or mismatch, respond 401.

Retry policy

Webhooks retried 3 times with exponential backoff 2s, 8s, 32s if your endpoint returns non-2xx or timeout >5s. After 3 failures, solve result stored 10min and can be fetched via management API using solving_id (future).

More Examples — Scrapy, Bulk, Error Handling #

Scrapy middleware

Intercept captcha detection in downloader middleware, pause request, solve, inject token, return request.

Retry decorator pattern

Use tenacity library: @retry(stop=stop_after_attempt(3), wait=wait_exponential(multiplier=1, min=2, max=10), retry=retry_if_exception_type((httpx.HTTPStatusError,))). Handles 429/503 by waiting Retry-After.

Logging structured

Always log X-Request-Id, solving_id, endpoint, time_taken_ms for post-mortem. VisuSolve dashboard logs provide server-side view; client logs complement.

Cost calculator

Estimate monthly cost: solves per day * 30 * avg credits per solve * price per credit. Example: 1000 solves/day v2 fast = 1000*30=30k credits = fits Pro $49 (50k). v3 double cost: 15k v3 solves = 30k credits = same bucket.

Migration — from 2Captcha / AntiCaptcha #

Migrating from human farms? Map their API to ours:

2Captcha fieldVisuSolve equivalentNotes
method=userrecaptchaPOST /classify + your own clicker, or POST /solve for tokenWe give you boolean mask, you click; /solve gives token directly like 2captcha
googlekey + pageurlwebsite_key + website_urlSame meaning
res.php?action=getSync POST returns immediately, no poll — if using /solve webhook mode, use callback instead of pollingNo polling needed, faster
proxy + proxytypeproxy field http://user:pass@host:portUnified format

Benefits: 10x faster median latency, no variable queue, cheaper at scale (Pro $49/50k vs human farms $2/1000 = $100/50k), no ethical concerns.

© 2026 VisuSolve • visusolve.yorubacinemax.xyz • docs v2.1.0 • Base URL https://visusolve.yorubacinemax.xyz • All examples use placeholders sk_live_...EXAMPLE, never real keys.

Webhook HMAC verification
import hmac, hashlib, json
from fastapi import Request, HTTPException

WEBHOOK_SECRET = b"whsec_YOUR_SECRET"

async def verify_webhook(request: Request):
    raw = await request.body()
    sig = request.headers.get("X-Webhook-Signature", "")
    expected = "sha256=" + hmac.new(WEBHOOK_SECRET, raw, hashlib.sha256).hexdigest()
    if not hmac.compare_digest(sig, expected):
        raise HTTPException(status_code=401, detail="bad signature")
    payload = json.loads(raw)
    print(payload["event"], payload.get("token", "")[:20])
    return payload
Scrapy middleware — captcha handling
# middlewares.py
import httpx, os
API="https://visusolve.yorubacinemax.xyz"; KEY=os.getenv("VISUSOLVE_API_KEY")

class VisuSolveMiddleware:
    def process_response(self, request, response, spider):
        if "api2/bframe" in response.text or "g-recaptcha" in response.text:
            spider.logger.info("captcha detected, solving via VisuSolve")
            sitekey=response.css("[data-sitekey]::attr(data-sitekey)").get()
            if sitekey:
                r=httpx.post(f"{API}/v3/solve" if "v3" in response.url else f"{API}/solve",
                    headers={"X-API-Key":KEY},
                    json={"website_key":sitekey,"website_url":response.url}, timeout=60).json()
                new_req=request.copy()
                new_req.replace(url=request.url+f"&g-recaptcha-response={r['token']}")
                return new_req
        return response
Environment & enterprise on-prem
# env template .env.example - copy to .env
VISUSOLVE_API_KEY=sk_live_4eC39HqLyjWDarjtT1zdp7dcEXAMPLE
VISUSOLVE_BASE_URL=https://visusolve.yorubacinemax.xyz
VISUSOLVE_TIMEOUT=15
VISUSOLVE_RETRIES=3

# docker on-prem enterprise
docker run -d --gpus all -p 8000:8000   -e VISUSOLVE_LICENSE=lic_....   -e MODEL_CACHE=/models   -v /mnt/models:/models   visusolve/on-prem:v2.1.0 --workers 4 --gpu

# healthcheck inside container
curl -s http://localhost:8000/health | jq .models.v2.latency_p50
Copied!