GeeTest v3 + v4
Solve GeeTest v3 (slide) and v4 (slide, icon, svg_icon, nine, word, phrase, space, pencil, voice) challenges automatically
Overview
GeeTest is a behavioral CAPTCHA system used by major exchanges, gaming platforms, and SaaS products. Our API solves GeeTest v3 fullpage (slide puzzle on api.geetest.com) and all 9 v4 challenge types on gcaptcha4.geetest.com, returning the validated seccode payload.
Single task type for both versions
One task type (GeetestTask / GeetestTaskProxyLess) handles both. Routing is automatic based on which fields you send:
gt+challenge-> v3 flowcaptchaIdonly -> v4 flow
Supported Task Types
| Task Type | Proxy Required | Description |
|---|---|---|
GeetestTaskProxyLess | No | Uses our built-in proxy infrastructure |
GeetestTask | Yes | Requires your own proxy |
Supported Challenge Types
The solver auto-detects which challenge GeeTest serves and dispatches to the right routine - you never need to specify a risk_type.
v3
| Type | Description |
|---|---|
slide | Drag the puzzle piece into the gap on the fullpage SDK |
v4
| Risk Type | Description |
|---|---|
slide | Drag the puzzle piece into the gap |
icon | Click matching icons in order |
svg_icon | Click icons matching an SVG prompt |
nine | Pick all matching tiles in a 3x3 grid |
word | Click characters matching a target word |
phrase | Click phrase tokens in order |
space | Spatial reasoning click |
pencil | Tracing/path challenge |
voice | Audio transcription challenge |
Create Task
Endpoint: POST /createTask
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
clientKey | String | Yes | Your API key |
task.type | String | Yes | GeetestTaskProxyLess or GeetestTask |
task.websiteURL | String | Yes | Target page URL serving the GeeTest challenge |
task.gt | String | v3 only | GeeTest gt (32-hex). Required for v3 alongside challenge. |
task.challenge | String | v3 only | GeeTest challenge (32-hex). Presence selects v3 flow. |
task.captchaId | String | v4 only | GeeTest v4 captcha_id (32-hex). Use this without challenge for v4. |
task.captchaHost | String | No | v3 enterprise proxy host (e.g. captcha-api.pingan.com) when site routes geetest through a custom domain |
task.geetestApiServerSubdomain | String | No | v4 custom API host (default gcaptcha4.geetest.com) |
task.proxy | String | No | Proxy (required for GeetestTask). See Proxy Format |
task.userAgent | String | No | User agent to match your client fingerprint |
Request Example - v3
{
"clientKey": "YOUR_API_KEY",
"task": {
"type": "GeetestTaskProxyLess",
"websiteURL": "https://example.com/login",
"gt": "81388ea1fc187e0c335c0a8907ff2625",
"challenge": "7b33c5254c55c432cf558767e36b8ef5"
}
}Request Example - v4
{
"clientKey": "YOUR_API_KEY",
"task": {
"type": "GeetestTaskProxyLess",
"websiteURL": "https://example.com/login",
"captchaId": "fcd636b4514bf7ac4143922550b3008b"
}
}Response
{
"errorId": 0,
"taskId": "07af74e1-6fec-4503-86e3-a8d080126516"
}Get Task Result
Endpoint: POST /getTaskResult
Request
{
"clientKey": "YOUR_API_KEY",
"taskId": "07af74e1-6fec-4503-86e3-a8d080126516"
}Response (Ready) - v3
{
"errorId": 0,
"status": "ready",
"solution": {
"challenge": "7b33c5254c55c432cf558767e36b8ef5g3",
"validate": "5e2af8d1f9c4b1a9e3f6c7d8e9f0a1b2",
"seccode": "5e2af8d1f9c4b1a9e3f6c7d8e9f0a1b2|jordan",
"userAgent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/131.0.0.0 Safari/537.36"
}
}Submit geetest_challenge, geetest_validate, geetest_seccode as form parameters on your target site's verification endpoint - matches the v3 SDK callback shape exactly.
Response (Ready) - v4
{
"errorId": 0,
"status": "ready",
"solution": {
"captcha_id": "fcd636b4514bf7ac4143922550b3008b",
"lot_number": "b851bce155d94932921939de5f0fface",
"pass_token": "fc5d9cec1c9412d1845249a0b70060b939ce94f51833f0324dd91f8f93ccc904",
"gen_time": "1778247610",
"captcha_output": "aDCl9jf9IT64VmwG8eCe9Gjqv..."
}
}The five fields together form the GeeTest v4 seccode payload. Submit them as form parameters (or JSON) on your target site's verification endpoint exactly as you would after a real human solve.
How to Find the captcha_id (v4) or gt+challenge (v3)
v4 - captcha_id
The captcha_id is a 32-hex string that uniquely identifies the v4 deployment on a given site.
- Open the target page in Chrome with DevTools (F12) -> Network tab
- Filter by
gcaptcha4.geetest.com - Look for requests to
/loador/verify - The
captcha_id=query parameter is the value you need
https://gcaptcha4.geetest.com/load?captcha_id=fcd636b4514bf7ac4143922550b3008b&challenge=...
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^captcha_id is constant per site
The captcha_id is fixed for a given page and rarely changes. You can hard-code it in your client once discovered. The challenge UUID rotates per request - our solver handles that automatically.
v3 - gt + challenge
For v3, both gt (constant per site) and challenge (rotates per page load) are issued by your target site's backend when the user requests a captcha. You forward both to us.
- Open the target page in DevTools -> Network tab
- Find the call to
api.geetest.com/gettype.php?gt=...orapi.geetest.com/get.php?gt=...&challenge=... - The
gt=query param is constant per site - The
challenge=query param is fresh per request - capture it from your backend'sregisterresponse and forward it to us with thegt
For enterprise sites that route GeeTest through a custom proxy (e.g. captcha-api.pingan.com/get.php), pass that host via task.captchaHost.
How to Identify GeeTest
| Indicator | v3 | v4 |
|---|---|---|
| Network requests | api.geetest.com, api.geevisit.com, static.geetest.com/v?/... | gcaptcha4.geetest.com, static.geetest.com/v4/... |
| Script | fullpage.X.X.X-*.js, slide.X.X.X.js, gct.*.js | gcaptcha4.js from static.geetest.com/v4/static/v1.9.x-.../js/ |
| Loaded API | window.initGeetest(...) | window.initGeetest4(...) |
| UI | Slide puzzle, "Click to verify" radar widget | Slide puzzle, icon-grid, or "Click in order" prompt |
DevTools Quick Check:
Network tab -> Filter: "geetest" -> Look for /gettype.php (v3) or /load (v4)Code Examples
import requests
import time
API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.capbypass.pro"
def solve_geetest(website_url, *, gt=None, challenge=None, captcha_id=None, proxy=None):
task = {
"type": "GeetestTask" if proxy else "GeetestTaskProxyLess",
"websiteURL": website_url,
}
if challenge: # v3
task["gt"] = gt
task["challenge"] = challenge
else: # v4
task["captchaId"] = captcha_id
if proxy:
task["proxy"] = proxy
res = requests.post(f"{BASE_URL}/createTask", json={
"clientKey": API_KEY,
"task": task,
}).json()
task_id = res["taskId"]
while True:
result = requests.post(f"{BASE_URL}/getTaskResult", json={
"clientKey": API_KEY,
"taskId": task_id,
}).json()
if result["status"] == "ready":
return result["solution"]
if result.get("errorId"):
raise Exception(result.get("errorDescription"))
time.sleep(1)
# v3 example
v3 = solve_geetest(
"https://example.com/login",
gt="81388ea1fc187e0c335c0a8907ff2625",
challenge="7b33c5254c55c432cf558767e36b8ef5",
)
print(v3["seccode"])
# v4 example
v4 = solve_geetest(
"https://example.com/login",
captcha_id="fcd636b4514bf7ac4143922550b3008b",
)
print(v4["pass_token"])const API_KEY = 'YOUR_API_KEY';
const BASE_URL = 'https://api.capbypass.pro';
async function solveGeetest({ websiteURL, gt, challenge, captchaId, proxy }) {
const task = {
type: proxy ? 'GeetestTask' : 'GeetestTaskProxyLess',
websiteURL,
};
if (challenge) { // v3
task.gt = gt;
task.challenge = challenge;
} else { // v4
task.captchaId = captchaId;
}
if (proxy) task.proxy = proxy;
const createRes = await fetch(`${BASE_URL}/createTask`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ clientKey: API_KEY, task }),
});
const { taskId } = await createRes.json();
while (true) {
const resultRes = await fetch(`${BASE_URL}/getTaskResult`, {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ clientKey: API_KEY, taskId }),
});
const result = await resultRes.json();
if (result.status === 'ready') return result.solution;
if (result.errorId) throw new Error(result.errorDescription);
await new Promise((r) => setTimeout(r, 1000));
}
}
// v3 example
const v3 = await solveGeetest({
websiteURL: 'https://example.com/login',
gt: '81388ea1fc187e0c335c0a8907ff2625',
challenge: '7b33c5254c55c432cf558767e36b8ef5',
});
console.log(v3.seccode);
// v4 example
const v4 = await solveGeetest({
websiteURL: 'https://example.com/login',
captchaId: 'fcd636b4514bf7ac4143922550b3008b',
});
console.log(v4.pass_token);Typical Solve Time
| Challenge | Average | Maximum |
|---|---|---|
| v3 slide | 2-4 seconds | 15 seconds |
| v4 slide | 1-2 seconds | 10 seconds |
| v4 icon / svg_icon | 2-3 seconds | 15 seconds |
| v4 nine / word / phrase | 3-5 seconds | 20 seconds |
Pricing
$0.99 per 1,000 successful solves (both v3 and v4). Failed solves are not charged.
Error Codes
| Error Code | Description |
|---|---|
ERROR_KEY_DOES_NOT_EXIST | Invalid API key |
ERROR_ZERO_BALANCE | Insufficient balance |
ERROR_CAPTCHA_UNSOLVABLE | Challenge could not be solved |
ERROR_TASK_NOT_FOUND | Task ID not found |
ERROR_INVALID_TASK_DATA | Missing or invalid parameters |
ERROR_PROXY_NOT_DEFINED | Proxy required for a non-ProxyLess task type — use the ProxyLess variant or supply task.proxy |
ERROR_PROXY_CONNECTION_FAILED | Could not connect through your proxy (refused, unreachable, or bad credentials) - check the proxy is alive and reachable |
ERROR_PROXY_BANNED | The target blocked your proxy IP (datacenter or flagged) - use a residential or mobile proxy |
ERROR_INVALID_DEVELOPER_KEY | The provided developerKey is invalid or disabled |
ERROR_WRONG_TASK_TYPE | Wrong task type for this site (e.g., standard vs enterprise) |
ERROR_TIMEOUT | Task exceeded timeout |
ERROR_TASK_QUEUE_FULL | Server is at capacity — retry in a few seconds |
ERROR_TASK_TYPE_COMING_SOON | Task type is not yet available |
ERROR_TASK_TYPE_INACTIVE | Task type is currently disabled |
ERROR_WORKER_CRASHED | Solver process exited mid-solve — balance refunded, safe to retry |
ERROR_INTERNAL | Internal server error |