Skip to content

GeeTest v3 / v4

The right payload for the right GeeTest version. Identify the widget generation first. GeeTest v4 uses captchaId; v3 uses a fresh gt and challenge pair, with different result fields.

POST /createTask · example
{
  "clientKey": "capzy_YOUR_API_KEY",
  "task": {
    "type": "GeeTestTaskProxyLess",
    "websiteURL": "https://example.com",
    "captchaId": "647f5ed2ed8acb4be36784e01556bb71"
  }
}

Illustrative values. Replace the inputs with values from your current integration.

v4 captchaId or v3 gt + challengeProxyless or your own proxyVersion-specific verification fields

Identify the widget version first.

Identify the widget generation first. GeeTest v4 uses captchaId; v3 uses a fresh gt and challenge pair, with different result fields.

Your API key authenticates Capzy.
Provider keys, challenge IDs, images, and session values belong inside task.

Read captcha_id and the current load options.

  1. Search Sources for initGeetest4 or inspect the widget's /load request in Network. Copy captcha_id into Capzy's captchaId field.
  2. If /load uses a custom host, preserve it in apiServer. Copy a supplied risk_type into riskType exactly, including signed suffixes.
  3. Select GeeTest v4 in Parameters and use the complete page URL as websiteURL. Capture time-bound riskType immediately before solving.
Input collection example - replace illustrative values
{
  "websiteURL": "https://example.com/login",
  "captchaId": "YOUR_V4_CAPTCHA_ID",
  "apiServer": "YOUR_CONFIGURED_API_HOST",
  "riskType": "YOUR_COMPLETE_RISK_TYPE"
}

apiServer and riskType are optional when the integration does not supply them. Keep captchaId distinct from a v3 gt value.

How GeeTest v3 / v4 works

GeeTest is a popular captcha used by many Chinese and international sites. It offers multiple challenge types: slider puzzles (drag to complete the image), click-in-order (click words/icons in sequence), and icon selection. GeeTest v3 uses a 'gt' key + server-generated 'challenge' value. GeeTest v4 uses a simpler 'captchaId' format.

Send websiteURL with the selected version's inputs: captchaId for v4, or the fresh gt and challenge pair for v3. We solve the challenge and return that version's verification fields. Forward the complete v4 captcha_id/lot_number/pass_token/gen_time/captcha_output set, or the v3 challenge/validate/seccode set, to the original site's validation flow. These are verification values, not a returned cookie jar.

  • Supports GeeTest v3 and v4
  • Solves the slider puzzle reliably
  • Click-in-order challenge support
  • ~8 second average solve time
  • Auto-detects v3 vs v4 from parameters
  • High-quality solves

Know what goes in.

Choose a field to see its purpose, where to get it, and its place in the request. Optional values omitted from the example can be added when your flow uses them.

captchaId-based widgets. Send just the captchaId — we return the lot_number / pass_token / gen_time / captcha_output tuple.

Request authentication

Required task inputs

Optional context

websiteURL

stringRequired

The page URL

Where it comes from

Copy the full page URL from the address bar or the document request in Network, including the path where this flow runs.

Open the input guide
Example valuehttps://example.com
POST /createTask · selected configuration
{
  "clientKey": "capzy_YOUR_API_KEY",
  "task": {
    "type": "GeeTestTaskProxyLess",
    "websiteURL": "https://example.com",
    "captchaId": "647f5ed2ed8acb4be36784e01556bb71"
  }
}

The selected field is highlighted when present. Preserve the declared value type and current challenge context.

How to find the riskType for a bound GeeTest captcha: copy the full risk_type value (e.g. 'icon|<timestamp>|<token>|<signature>') from the widget's /load request in the Network tab, and pass it verbatim as the riskType parameter. It is time-bound, so capture a fresh one before each solve.
How to find the riskType for a bound GeeTest captcha: copy the full risk_type value (e.g. 'icon|<timestamp>|<token>|<signature>') from the widget's /load request in the Network tab, and pass it verbatim as the riskType parameter. It is time-bound, so capture a fresh one before each solve.
How to find the apiServer value for a private GeeTest deployment: read the apiServers array in the page's initGeetest4 config and pass that host as the apiServer parameter.
How to find the apiServer value for a private GeeTest deployment: read the apiServers array in the page's initGeetest4 config and pass that host as the apiServer parameter.

Make your first request.

Create the task, keep its taskId, and poll until status is ready. Then read the selected variant's solution.

More examples
  1. Create the task

    Send clientKey and the selected task to /createTask from your server. Keep the returned taskId.

  2. Wait for the solution

    Send that same key and ID to /getTaskResult. While processing, wait two seconds before checking again. Stop on Ready or an error.

  3. Apply the result

    For v4, forward captcha_id, lot_number, pass_token, gen_time, and captcha_output together. For v3, forward challenge, validate, and seccode together. The selected variant below shows the matching response and usage.

solve_geetest.py
import json, os, time
import requests

API = "https://api.capzy.ai"
KEY = os.environ["CAPZY_API_KEY"]
task = json.loads("{\"type\":\"GeeTestTaskProxyLess\",\"websiteURL\":\"https://example.com\",\"captchaId\":\"647f5ed2ed8acb4be36784e01556bb71\"}")

def call(path, payload):
    response = requests.post(f"{API}/{path}", json={"clientKey": KEY, **payload}, timeout=30)
    response.raise_for_status()
    data = response.json()
    if data.get("errorId", 0) or data.get("status") == "failed":
        raise RuntimeError(data.get("errorDescription") or data.get("errorCode") or "Task failed")
    return data

created = call("createTask", {"task": task})
for attempt in range(60):
    result = call("getTaskResult", {"taskId": created["taskId"]})
    if result.get("status") == "ready":
        solution = result["solution"]
        print(solution)
        break
    time.sleep(2)
else:
    raise TimeoutError("Task is still processing; keep the taskId to check it later.")

Before runningReplace all illustrative inputs with your captured values. Set CAPZY_API_KEY in your environment. Install requests with pip install requests.

Polling and failuresThe example checks HTTP/API failures, uses 30-second request timeouts, and stops after 60 result checks. Retain taskId if your task is still processing.

Understand what comes back.

Follow this task from creation to completion. Response fields and usage follow your selected request variant.

Version-specific verification fields

For v4, forward captcha_id, lot_number, pass_token, gen_time, and captcha_output together. For v3, forward challenge, validate, and seccode together. The selected variant below shows the matching response and usage.

string
GeeTest v4: the captcha ID echoed back
string
GeeTest v4: lot number
string
GeeTest v4: pass token for server validation
string
GeeTest v4: generation timestamp
string
GeeTest v4: captcha output string
POST /getTaskResult · example response
{
  "errorId": 0,
  "status": "ready",
  "solution": {
    "captcha_id": "647f5ed2ed8acb4be36784e01556bb71",
    "lot_number": "8a2c4e5b3f1d4567a9b8c0d2e3f4a5b6",
    "pass_token": "<long pass token from validation server>",
    "gen_time": "1735689600",
    "captcha_output": "<base64-encoded captcha output>"
  }
}

Illustrative values. Additional metadata may be returned; only Ready contains a completed solution.

GeeTest v4

captchaId-based widgets — submit these five fields; your backend forwards them to GeeTest's /validate.

Execution context result is the parsed Ready response from the polling example. session, when referenced, is your existing requests.Session (or browser-compatible session) with the original cookie jar, headers, and solving proxy configured in session.proxies for both http and https. Keep this client for the complete flow. task is the task object you submitted. For Shape, action_body is the original protected request body as bytes or a string, with its original Content-Type in session.headers. Install curl_cffi when the fragment imports it; match the target's required browser/TLS identity.

Use the result · Python

# Step 3 — GeeTest v4: submit these to your site's form / endpoint
sol = result["solution"]
requests.post("https://target.example.com/verify", data={
    "captcha_id":     sol["captcha_id"],
    "lot_number":     sol["lot_number"],
    "pass_token":     sol["pass_token"],
    "gen_time":       sol["gen_time"],
    "captcha_output": sol["captcha_output"],
})

When something doesn't work.

Check your captured values, the selected variant, and the response before starting another task.

How do I know if it's v3 or v4?

If the site uses 'gt' + 'challenge' parameters, it's v3. If it uses 'captchaId', it's v4. Send whichever parameters you find — our auto-router detects the version.

The challenge parameter expires. How do I handle that?

For v3, the 'challenge' is single-use and time-limited. Fetch a fresh challenge from the site's API right before creating the task.

I get 'not captcha' / CAPTCHAID_INVALID but the captchaId is correct. Why?

Some sites run a private or self-hosted GeeTest deployment, so the captchaId is not registered on the public GeeTest servers. Pass the 'apiServer' parameter set to the host the widget loads (find it in the page's initGeetest4 config under 'apiServers', or in the widget's /load request). If it still fails, contact support.

I get 'illegal risk_type' / RISKTYPE_UNSUPPORTED. What do I send?

That site binds a server-signed risk_type — the captchaId alone isn't enough. Open DevTools, find the widget's /load request in the Network tab, and copy the FULL 'risk_type' value (it looks like 'icon|<timestamp>|<token>|<signature>'). Pass it verbatim as the 'riskType' parameter. It's time-bound, so capture a fresh one right before each solve. If the base type (before the first '|') is one we don't support yet, you'll get RISKTYPE_UNSUPPORTED — contact support to add it.

Connect GeeTest v3 / v4 to your workflow.

Get your Capzy API key and use this guide's integration.

$2.00Per 1,000 solves
13.6sAverage solve time

GeeTestTaskProxyLess · Live configuration