Skip to content
voidcaptcha

Task type

GeeTest solver API

GeeTest serves a different puzzle depending on how the site has configured it and how the session scores, so the useful question is not whether a provider supports GeeTest but which variants it can actually finish. We solve all of them, on both protocols, and the list is below rather than behind a screenshot. Send the page URL and the site key and we pick the variant from what GeeTest serves — you do not have to know in advance which one you will get. Send your own sticky proxy: GeeTest rate-limits datacenter addresses, and the token is tied to the exit that earned it.

Tip

Send task.type as GeetestV4 and the solution arrives in solution.pass_token, with solution.captcha_id and solution.lot_number and solution.gen_time and solution.captcha_output and solution.validate and solution.seccode beside it.

What it looks like#

GeeTest serves a different puzzle depending on how the site is configured and how the session scores. We solve every variant below. Send riskType to force one, or leave it off and we handle whichever appears.

GeeTest: Slide
riskType slideSlideDrag the piece into the gap in the picture.
GeeTest: Icon click
riskType iconIcon clickClick the icons in the order shown, on a photographic background.
GeeTest: Image select
riskType nineImage selectPick the three tiles matching the prompt out of nine.
GeeTest: Icon crush
riskType matchIcon crushSwap two tiles to line up three identical ones.
GeeTest: Gobang
riskType winlinzeGobangDrop a piece to complete a row of five.

Before you integrate

  1. Which puzzle you get is GeeTest’s choice, not yours. On V4 we solve slide, icon (icon click, including the arrows variant), nine, match (icon crush) and winlinze (gobang); on V3, slide, intelligent, icon, space, word click and phrase click. Leave riskType off and we handle whatever is served, including an invisible check that escalates to a puzzle mid-solve.
  2. V3’s challenge is single-use and dies the moment the widget initialises. Fetch a fresh one immediately before each call and do not let the page load the captcha first — a reused or post-init challenge is the most common reason a V3 task fails. V4 needs no challenge at all.

A site that will not solve is worth telling us about — coverage is per target as much as per type. The quickest route is Telegram (@VoidCaptchaSupport), where someone usually answers within minutes. You can also open a ticket from your dashboard or email [email protected]. Send the URL and the site key either way.

task.type
GeetestV4
Median
—
under 50 solves
Success
—
Price / 1k
$1.00
$0.0010 each
Proxy
Required

Solve request#

Solving GeeTest is a single synchronous call. You post one task object and the response carries the finished solution — no task id to store, nothing to poll for.

POSThttps://api.voidcaptcha.com/v1/getResult

The connection is held open for the whole solve. Set a client timeout that covers it — the default socket timeout in most HTTP libraries is shorter than the work. If holding a connection that long does not suit your worker fleet, the same task goes to /v1/createTask and you collect it from /v1/checkTask instead.

When to use it#

  • Registration and login flows on exchanges and travel sites
  • Monitoring a checkout that gates on a behavioural score
  • Keeping a crawl alive when a site escalates to a puzzle

Task object structure#

These fields go inside task. The envelope around it — clientKey and the optional softId — is the same for every type and is described in the API reference.

PropertyTypeRequiredDescription
typestringRequiredLiteral "GeetestV4". Also accepts: GeetestV3. Matching is case-insensitive.
urlstringRequiredThe page the captcha is initialised on.e.g. https://example.com/register
site_keystringRequiredGeetestV4 only: the captcha_id from the widget, 32 hex characters.e.g. 54088bb07d2df3c46b79f80300b0abbe
gtstringOptionalGeetestV3 only, and required for it. The static domain key.e.g. 022397c99c9f646f6477822485f30404
challengestringOptionalGeetestV3 only, and required for it. Single-use — fetch it fresh before every call.e.g. 7f9d3ee0c0f04b2e9b6c3f2a1d8e5c47
riskTypestringOptionalGeetestV4 only. Force a variant: slide, icon, nine, match, winlinze. Omit it and we solve whatever is served.e.g. slide
geetestApiServerSubdomainstringOptionalGeetestV3 only. Some sites front the API on their own subdomain.
proxystringRequiredUpstream proxy. Accepts host:port, host:port:user:pass, or a full http:// URL. Use a sticky session — a rotating exit IP mid-solve looks like a hijacked session and will fail.e.g. proxy.example.com:9090:user:pass
user_agentstringOptionalPin the User-Agent used for the solve. Omit it and a coherent one is chosen for you and returned in the response — match whatever you send downstream.e.g. Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 …

Example payload#

The whole body, assembled from the table above — copy it formatted to read, or on one line to paste straight into a terminal or a REST client. The values are placeholders: swap the key for your own and the URL and site key for the page you are solving.

POSThttps://api.voidcaptcha.com/v1/getResult
{
  "clientKey": "void_a1b2c3d4e5f60718293a4b5c6d7e8f90",
  "task": {
    "type": "GeetestV4",
    "url": "https://example.com/register",
    "site_key": "54088bb07d2df3c46b79f80300b0abbe",
    "proxy": "proxy.example.com:9090:user:pass"
  }
}

Example request#

The smallest thing that gets a token back, in your language. Python and Node.js use the official client (pip install voidcaptcha, npm install voidcaptcha); every other language makes the HTTP call its standard library already has. The complete version, with the key read from the environment and the error envelope checked, is in Sample code at the bottom of this page.

Language choice is remembered across the whole site, so switching here carries to every other sample in the docs.

# pip install voidcaptcha
from voidcaptcha import VoidCaptcha

client = VoidCaptcha("void_a1b2c3d4e5f60718293a4b5c6d7e8f90")

result = client.geetest_v4(
    url="https://example.com/register",
    site_key="54088bb07d2df3c46b79f80300b0abbe",
    proxy="proxy.example.com:9090:user:pass",
)

print(result.value)

Example response#

A successful solve returns errorId: 0 and a solution object. The result is in solution.pass_token; alongside it is the userAgent the solve ran under.

solution carries those and nothing else — the gateway copies the result field, anything extra this type returns, and userAgent across, and drops the rest of whatever the solver sent. Timing arrives at the top level as elapsedMs, present only when the duration is known, beside cost and your remaining balance. The figures below are illustrative: nothing here is a published median.

This type also returns solution.captcha_id. Returned with every V4 solve. GeeTest validates the five V4 fields as a set, so post all of them together.

This type also returns solution.lot_number. The V4 lot number for this attempt.

This type also returns solution.gen_time. Unix seconds the V4 token was minted. Part of the signed set.

This type also returns solution.captcha_output. The V4 payload GeeTest verifies server-side. Long, and must be sent verbatim.

This type also returns solution.validate. V3 only. The field GeeTest’s own form calls geetest_validate.

This type also returns solution.seccode. V3 only. Sent alongside challenge and validate.

JSON
{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "pass_token": "03AGdBq25V6…",
    "captcha_id": "54088bb07d2df3c46b79f80300b0abbe",
    "lot_number": "bcb2c6ce2f8e4e9da74f2c1fa63bd713",
    "gen_time": "1683794919",
    "captcha_output": "XwmTZEJCJEnRIJBlvtEAZ662T…",
    "validate": "6275e26419211d1f526e674d97110e15",
    "seccode": "510cd9735583edcb158601067195a5eb|jordan",
    "userAgent": "Mozilla/5.0 …"
  },
  "cost": "$0.0010",
  "balance": "$411.24",
  "elapsedMs": 4820
}

Send that userAgent on your downstream request as well — for the cookie-based types the result is bound to it and will be rejected under a different one.

Errors for this type#

The codes GeeTest can return, on top of the shared authentication and billing set. Branch on errorCode, not on the HTTP status.

CodeHTTPMeaningRetry
ERROR_KEY_MISSING401No clientKey was supplied.Do not retry
ERROR_KEY_INVALID401The key does not exist or has been revoked.Do not retry
ERROR_KEY_SUSPENDED403The account attached to this key is suspended.Do not retry
ERROR_TYPE_NOT_ENABLED403This account is not enabled for the requested task type.Do not retry
ERROR_BAD_REQUEST400The body was not valid JSON, or task was missing.Do not retry
ERROR_CAPTCHA_UNSOLVABLE200The challenge was served but could not be completed.Retry
ERROR_TIMEOUT200The solve exceeded the maximum time for this type.Retry with backoff
ERROR_INSUFFICIENT_BALANCE402Your balance will not cover this solve.Do not retry
ERROR_THREAD_LIMIT429You have more solves in flight than your key permits.Retry with backoff
ERROR_RATE_LIMITED429Too many requests in a short window.Retry with backoff

Every code, with the fix for each, is on the error reference. A failed solve is never charged.

Sample code#

A complete file: key from the environment, task built, error envelope checked, result used. It calls the endpoint directly rather than through an SDK, so it works as a starting point in any language.

import os
import sys

import requests

API = "https://api.voidcaptcha.com/v1/getResult"

payload = {
    "clientKey": os.environ["VOIDCAPTCHA_KEY"],
    "task": {
        "type": "GeetestV4",
        "url": "https://example.com/register",
        "site_key": "54088bb07d2df3c46b79f80300b0abbe",
        "proxy": "proxy.example.com:9090:user:pass"
    },
}

# The endpoint is synchronous: it holds the connection open for the whole
# solve, so the read timeout has to cover it, not just the handshake.
res = requests.post(API, json=payload, timeout=180).json()

if res["errorId"] != 0:
    sys.exit(f"{res['errorCode']}: {res['errorDescription']}")

solution = res["solution"]

# Carry the User-Agent downstream — the result was earned under it.
print(solution["pass_token"])
print(solution["userAgent"])

Last updated on 2 August 2026