GeeTest CAPTCHA v3 and v4: How to Solve Both Versions
Guide to solving GeeTest v3 (slide puzzle) and v4 (click/match) CAPTCHAs — understanding challenge types, API parameters, and integration examples.
GeeTest CAPTCHA v3 and v4: How to Solve Both Versions
GeeTest CAPTCHA is one of the most widely deployed challenge systems globally, particularly across Chinese-language platforms and increasingly on international sites. GeeTest uses interactive puzzles — slider challenges in v3 and click/match tasks in v4 — combined with behavioral analysis to verify human users. This guide covers how both versions work, the parameters you need to extract, and how to solve them programmatically through a CAPTCHA solver API.
For context on how GeeTest fits into the broader anti-bot ecosystem alongside platforms like Cloudflare, DataDome, and Arkose Labs, see our pillar guide on understanding anti-bot systems.
GeeTest v3: The Slide Puzzle
GeeTest v3 is the older and still widely deployed version. Its primary challenge type is the slide puzzle: a jigsaw piece is cut from a background image, and the user must drag a slider to move the piece horizontally into the correct gap position.
How GeeTest v3 Works
When a page loads the GeeTest v3 widget, several things happen:
- Initialization — The page’s JavaScript calls GeeTest’s API with a
gt(app ID) parameter to register a new challenge session. - Challenge generation — GeeTest’s server returns a
challengestring that identifies this specific puzzle instance, along with the puzzle images. - User interaction — The user drags the slider to solve the puzzle. GeeTest’s JavaScript records the drag trajectory, speed, and timing, and submits both the answer and behavioral data for validation.
- Server-side validation — GeeTest’s backend validates the puzzle answer and the behavioral data. If both pass, a validation token is returned that the website’s backend can verify.
Beyond the primary slide puzzle, GeeTest v3 also includes less common challenge types: icon click (click specific icons in order) and space puzzle (drag a piece to the correct position in both X and Y axes). The slide puzzle accounts for the vast majority of v3 deployments.
Finding GeeTest v3 Parameters
To solve GeeTest v3 via API, you need two values:
gt (App ID) — A 32-character hexadecimal string that identifies the GeeTest account. This value is static per site and does not change between sessions.
Where to find it:
- Search the page source for
gt:or"gt"in JavaScript configuration objects. - Monitor network requests to
api.geetest.comand look for thegtparameter.
challenge — A session-specific string generated for each CAPTCHA instance. This value changes every time the CAPTCHA widget loads.
Where to find it:
- The challenge is typically returned from the site’s backend API. Look for an endpoint that the page calls before initializing the GeeTest widget — it usually returns JSON containing
gt,challenge, andsuccessfields. - In network requests, filter for the site’s own API calls (not geetest.com) that return GeeTest initialization data.
// Typical server response containing GeeTest v3 parameters
{
"gt": "81388ea1fc187e0c335c0a8907ff2625",
"challenge": "4c936c7e78c3dd5daa1e01abc8a2b73b",
"success": 1,
"new_captcha": true
}
Solving GeeTest v3
Use the GeeTestTaskProxyless task type with the gt and challenge parameters:
import requests
import time
API_KEY = "YOUR_UCAPTCHA_API_KEY"
BASE_URL = "https://api.ucaptcha.net"
# Step 1: Get fresh challenge from the target site
site_response = requests.get("https://example.com/api/geetest/init").json()
gt = site_response["gt"]
challenge = site_response["challenge"]
# Step 2: Create the GeeTest task
task_response = requests.post(f"{BASE_URL}/createTask", json={
"clientKey": API_KEY,
"task": {
"type": "GeeTestTaskProxyless",
"websiteURL": "https://example.com/login",
"gt": gt,
"challenge": challenge
}
}).json()
task_id = task_response["taskId"]
# Step 3: Poll for the result
while True:
time.sleep(5)
result = requests.post(f"{BASE_URL}/getTaskResult", json={
"clientKey": API_KEY,
"taskId": task_id
}).json()
if result["status"] == "ready":
solution = result["solution"]
print(f"challenge: {solution['challenge']}")
print(f"validate: {solution['validate']}")
print(f"seccode: {solution['seccode']}")
break
elif result["status"] == "processing":
print("Solving...")
else:
raise Exception(f"Error: {result.get('errorDescription')}")
GeeTest v3 Solution Format
The solution object for GeeTest v3 contains three fields that you submit to the target site’s validation endpoint:
| Field | Description |
|---|---|
challenge | The validated challenge string (may differ from the input challenge) |
validate | A validation hash proving the puzzle was solved |
seccode | A security code derived from the validate value |
Submit all three values to the target site in the same format it expects:
# Submit the solution to the target site
validation_response = requests.post("https://example.com/api/login", data={
"username": "user@example.com",
"password": "password",
"geetest_challenge": solution["challenge"],
"geetest_validate": solution["validate"],
"geetest_seccode": solution["seccode"]
})
GeeTest v4: Click and Match Challenges
GeeTest v4 is the newer generation, launched to address limitations of the v3 slider format. It replaces the slide puzzle with diverse click-based and matching challenges that are harder to solve with simple automation.
GeeTest v4 Challenge Types
GeeTest v4 includes several challenge variants:
- Icon click — Click specific icons in the order shown by a prompt.
- Space reasoning — Identify which image matches a described spatial relationship.
- Word matching — Click characters or words in a specific sequence.
- Object matching — Match pairs of related images.
- Semantic reasoning — Select the image that answers a question or matches a description.
The challenge type is determined dynamically by GeeTest’s risk engine. Higher-risk sessions receive harder challenge types.
Finding GeeTest v4 Parameters
GeeTest v4 uses a different parameter structure than v3. The primary identifier is the captcha_id:
captcha_id — A UUID-format string that identifies the GeeTest v4 account. This replaces the gt parameter from v3.
Where to find it:
- Search the page source for
captcha_idorcaptchaIdin JavaScript configuration. - Monitor network requests to
gcaptcha4.geetest.comand look for thecaptcha_idparameter.
Unlike v3, GeeTest v4 does not require you to fetch a separate challenge parameter. The challenge is generated internally when the task is created.
// Typical GeeTest v4 initialization in page source
initGeetest4({
captchaId: "e392e1d7fd421dc63325744d5a2b9c73",
product: "bind"
});
Solving GeeTest v4
Use the same GeeTestTaskProxyless task type, but pass captcha_id instead of gt and challenge:
import requests
import time
API_KEY = "YOUR_UCAPTCHA_API_KEY"
BASE_URL = "https://api.ucaptcha.net"
# Create the GeeTest v4 task
task_response = requests.post(f"{BASE_URL}/createTask", json={
"clientKey": API_KEY,
"task": {
"type": "GeeTestTaskProxyless",
"websiteURL": "https://example.com/register",
"captcha_id": "e392e1d7fd421dc63325744d5a2b9c73"
}
}).json()
task_id = task_response["taskId"]
# Poll for the result
while True:
time.sleep(5)
result = requests.post(f"{BASE_URL}/getTaskResult", json={
"clientKey": API_KEY,
"taskId": task_id
}).json()
if result["status"] == "ready":
solution = result["solution"]
print(f"captcha_id: {solution['captcha_id']}")
print(f"lot_number: {solution['lot_number']}")
print(f"pass_token: {solution['pass_token']}")
print(f"gen_time: {solution['gen_time']}")
print(f"captcha_output: {solution['captcha_output']}")
break
elif result["status"] == "processing":
print("Solving...")
GeeTest v4 Solution Format
The v4 solution contains a different set of fields than v3:
| Field | Description |
|---|---|
captcha_id | The CAPTCHA ID echoed back |
lot_number | A unique identifier for this solve session |
pass_token | The validation token proving the challenge was solved |
gen_time | Timestamp of token generation |
captcha_output | Encoded output of the challenge interaction |
Submit these values to the target site’s backend for verification:
validation_response = requests.post("https://example.com/api/register", json={
"email": "user@example.com",
"password": "password",
"captcha_id": solution["captcha_id"],
"lot_number": solution["lot_number"],
"pass_token": solution["pass_token"],
"gen_time": solution["gen_time"],
"captcha_output": solution["captcha_output"]
})
v3 vs v4: Key Differences
| Aspect | GeeTest v3 | GeeTest v4 |
|---|---|---|
| Primary challenge | Slide puzzle | Click/match challenges |
| Identifier | gt (32-char hex) | captcha_id (UUID) |
| Challenge parameter | Required (session-specific) | Not required (generated internally) |
| Solution fields | challenge, validate, seccode | captcha_id, lot_number, pass_token, gen_time, captcha_output |
| API domain | api.geetest.com | gcaptcha4.geetest.com |
| Difficulty scaling | Limited (same slide puzzle) | Dynamic (multiple challenge types) |
Tips for Reliable GeeTest Solving
Use fresh challenges for v3. The challenge parameter in GeeTest v3 expires quickly. Fetch a new challenge immediately before creating your solver task. Using a stale challenge will result in failed solves.
Check the version first. v3 and v4 use different parameters. Sending v3 parameters for a v4 challenge (or vice versa) will fail. Inspect the page’s network requests to determine which version is in use — api.geetest.com indicates v3, while gcaptcha4.geetest.com indicates v4.
Handle both versions. Some sites are migrating from v3 to v4. Your integration should detect which version is present and use the correct parameters. Checking for the presence of captcha_id versus gt in the page’s JavaScript is the simplest way to differentiate.
Expect moderate solve times. GeeTest challenges typically take 10 to 25 seconds to solve. This is faster than FunCaptcha but slower than reCAPTCHA. Adjust your polling intervals and timeouts accordingly. For more on how FunCaptcha compares, see our FunCaptcha and Arkose Labs guide.
Conclusion
GeeTest v3 and v4 represent two generations of interactive puzzle CAPTCHAs, each with distinct challenge formats, parameters, and solution structures. Solving them programmatically requires extracting the correct identifiers from the target page and using the GeeTestTaskProxyless task type with the appropriate parameters.
uCaptcha handles both GeeTest versions through a single API at api.ucaptcha.net, routing each task to the provider with the best solve rate for the specific challenge type. Whether you encounter a v3 slide puzzle or a v4 click challenge, one integration covers both.
Related Articles
FunCaptcha and Arkose Labs: How They Work and How to Solve Them
Understanding FunCaptcha (Arkose Labs) — the 3D rotating puzzle CAPTCHA, how it detects bots, and how to solve it programmatically using CAPTCHA solver APIs.
Pillar Guide
Understanding Anti-Bot Systems: A Developer's Guide
Deep dive into how anti-bot systems work — browser fingerprinting, behavioral analysis, CAPTCHA triggers, IP reputation, and how modern bot protection detects automation.