Tutorials

Solving GeeTest v3 with Python and CaptchaAI API

GeeTest v3 is a slider-based CAPTCHA commonly found on Chinese and international platforms. Unlike reCAPTCHA, GeeTest requires extracting specific challenge parameters (gt, challenge) before solving. This guide shows the complete flow using Python and CaptchaAI's GeeTest solver — which achieves 100% success rate.


Prerequisites

pip install requests

You need:

  • A CaptchaAI API key from captchaai.com
  • The target page URL
  • GeeTest gt (account ID) and challenge (per-session token)

GeeTest v3 parameters

GeeTest v3 requires two parameters for solving:

Parameter Description Where to find
gt GeeTest account ID (32-char hex) Static in page source or API response
challenge Per-session challenge token (32-char hex) Dynamic — must be fetched fresh per solve

How parameters flow


1. Page loads → JavaScript requests GeeTest API
2. API returns: { gt: "abc...", challenge: "def...", success: 1 }
3. User completes slider
4. GeeTest returns: { geetest_challenge, geetest_validate, geetest_seccode }
5. Server verifies with GeeTest backend

Step 1: Extract GeeTest parameters

Method A: From page HTML

import re
import requests

def extract_geetest_from_html(url):
    """Extract GeeTest gt and challenge from page HTML."""
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 Chrome/120.0.0.0",
    }
    response = requests.get(url, headers=headers, timeout=15)
    html = response.text

    # Extract gt (account ID)
    gt_match = re.search(r'gt\s*[:=]\s*["\']([a-f0-9]{32})["\']', html)
    gt = gt_match.group(1) if gt_match else None

    # Extract challenge
    challenge_match = re.search(
        r'challenge\s*[:=]\s*["\']([a-f0-9]{32})["\']', html
    )
    challenge = challenge_match.group(1) if challenge_match else None

    return {"gt": gt, "challenge": challenge}

Method B: From GeeTest register API (more common)

def extract_geetest_from_api(register_url):
    """Fetch fresh GeeTest parameters from the site's register endpoint."""
    headers = {
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                      "AppleWebKit/537.36 Chrome/120.0.0.0",
        "Referer": "https://example.com/login",
    }

    response = requests.get(register_url, headers=headers, timeout=15)
    data = response.json()

    # Common response format:
    # { "gt": "abc123...", "challenge": "def456...", "success": 1 }
    return {
        "gt": data.get("gt"),
        "challenge": data.get("challenge"),
        "success": data.get("success"),
    }


# Example: Many sites have a /geetest/register endpoint
params = extract_geetest_from_api("https://example.com/api/geetest/register")
print(f"GT: {params['gt']}")
print(f"Challenge: {params['challenge']}")

Method C: Intercept from network requests

from selenium import webdriver
from selenium.webdriver.common.by import By
import json

def extract_geetest_from_network(url):
    """Use Selenium to intercept GeeTest register call."""
    options = webdriver.ChromeOptions()
    options.add_argument("--disable-blink-features=AutomationControlled")
    options.set_capability("goog:loggingPrefs", {"performance": "ALL"})

    driver = webdriver.Chrome(options=options)
    driver.get(url)

    import time
    time.sleep(5)  # Wait for GeeTest to initialize

    # Check performance logs for GeeTest API calls
    logs = driver.get_log("performance")
    for entry in logs:
        message = json.loads(entry["message"])["message"]
        if message["method"] == "Network.responseReceived":
            resp_url = message["params"]["response"]["url"]
            if "geetest" in resp_url or "gt=" in resp_url:
                # Found the GeeTest register call
                request_id = message["params"]["requestId"]
                body = driver.execute_cdp_cmd(
                    "Network.getResponseBody", {"requestId": request_id}
                )
                data = json.loads(body["body"])
                driver.quit()
                return {"gt": data.get("gt"), "challenge": data.get("challenge")}

    driver.quit()
    return None

Step 2: Submit to CaptchaAI

import requests

API_KEY = "YOUR_API_KEY"

def submit_geetest(gt, challenge, page_url):
    """Submit GeeTest v3 solving task to CaptchaAI."""
    response = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "geetest",
        "gt": gt,
        "challenge": challenge,
        "pageurl": page_url,
        "json": 1,
    })

    data = response.json()

    if data.get("status") != 1:
        raise Exception(f"Submit failed: {data.get('request')}")

    return data["request"]

Step 3: Poll for the result

GeeTest returns three values instead of a single token:

import time

def poll_geetest_result(task_id, timeout=120):
    """Poll CaptchaAI for GeeTest v3 solution."""
    start = time.time()

    while time.time() - start < timeout:
        time.sleep(5)

        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": 1,
        }).json()

        if result.get("status") == 1:
            # GeeTest returns three values
            answer = result["request"]
            # Format: "geetest_challenge:xxx|geetest_validate:xxx|geetest_seccode:xxx"
            return parse_geetest_response(answer)

        if result.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
            raise Exception("GeeTest could not be solved")

    raise TimeoutError("Solve timed out")


def parse_geetest_response(response_str):
    """Parse GeeTest response into individual components."""
    parts = {}
    for pair in response_str.split("|"):
        if ":" in pair:
            key, value = pair.split(":", 1)
            parts[key] = value
    return parts

Complete working example

import re
import time
import requests

API_KEY = "YOUR_API_KEY"
TARGET_URL = "https://example.com/login"
GEETEST_REGISTER_URL = "https://example.com/api/geetest/register"


def get_geetest_params(session, register_url):
    """Fetch fresh GeeTest parameters."""
    response = session.get(register_url, timeout=15)
    data = response.json()
    return data["gt"], data["challenge"]


def solve_geetest(gt, challenge, page_url):
    """Solve GeeTest v3 via CaptchaAI."""
    # Submit
    submit = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": API_KEY,
        "method": "geetest",
        "gt": gt,
        "challenge": challenge,
        "pageurl": page_url,
        "json": 1,
    })

    data = submit.json()
    if data.get("status") != 1:
        raise Exception(f"Submit error: {data.get('request')}")

    task_id = data["request"]
    print(f"Task submitted: {task_id}")

    # Poll
    for _ in range(30):
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": API_KEY,
            "action": "get",
            "id": task_id,
            "json": 1,
        }).json()

        if result.get("status") == 1:
            return result["request"]

    raise TimeoutError("Solve timed out")


# --- Main flow ---
session = requests.Session()
session.headers.update({
    "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
                  "AppleWebKit/537.36 Chrome/120.0.0.0",
    "Accept": "application/json, text/html, */*;q=0.8",
    "Accept-Language": "en-US,en;q=0.9",
})

# 1. Get fresh challenge parameters
gt, challenge = get_geetest_params(session, GEETEST_REGISTER_URL)
print(f"GT: {gt}")
print(f"Challenge: {challenge}")

# 2. Solve GeeTest
solution = solve_geetest(gt, challenge, TARGET_URL)
print(f"Solution received")

# 3. Submit to target site
# The exact submission format varies by site
form_response = session.post(TARGET_URL, data={
    "geetest_challenge": challenge,
    "geetest_validate": solution.split("|")[1].split(":")[1] if "|" in solution else solution,
    "geetest_seccode": solution.split("|")[2].split(":")[1] if "|" in solution else f"{solution}|jordan",
    "username": "user@example.com",
    "password": "password123",
})
print(f"Login status: {form_response.status_code}")

GeeTest response values

The CaptchaAI response contains three components that the target site validates:

Value Description Format
geetest_challenge The original challenge token 32-char hex string
geetest_validate Validation hash 32-char hex string
geetest_seccode Security code {validate}\|jordan

Constructing the seccode

The geetest_seccode is typically the geetest_validate value followed by |jordan:

validate = "abc123..."  # From CaptchaAI response
seccode = f"{validate}|jordan"

Common GeeTest v3 patterns

Pattern 1: JSON API submission

response = session.post("https://example.com/api/verify", json={
    "geetest_challenge": challenge,
    "geetest_validate": validate,
    "geetest_seccode": seccode,
    "action": "login",
})

Pattern 2: Form POST

response = session.post("https://example.com/login", data={
    "geetest_challenge": challenge,
    "geetest_validate": validate,
    "geetest_seccode": seccode,
    "email": "user@example.com",
    "password": "pass123",
})

Pattern 3: Combined with CSRF token

# Some sites require CSRF token alongside GeeTest
csrf_match = re.search(r'name="csrf_token" value="([^"]+)"', page_html)
csrf_token = csrf_match.group(1) if csrf_match else ""

response = session.post("https://example.com/login", data={
    "csrf_token": csrf_token,
    "geetest_challenge": challenge,
    "geetest_validate": validate,
    "geetest_seccode": seccode,
    "username": "user",
})

Error handling

class GeeTestSolveError(Exception):
    pass

def solve_geetest_robust(gt, challenge, page_url, max_retries=3):
    """Solve GeeTest with robust error handling."""
    for attempt in range(1, max_retries + 1):
        try:
            submit = requests.post(
                "https://ocr.captchaai.com/in.php",
                data={
                    "key": API_KEY,
                    "method": "geetest",
                    "gt": gt,
                    "challenge": challenge,
                    "pageurl": page_url,
                    "json": 1,
                },
                timeout=30,
            )
            submit.raise_for_status()
            data = submit.json()

            if data.get("status") != 1:
                error = data.get("request", "Unknown")
                if error in ("ERROR_WRONG_USER_KEY", "ERROR_ZERO_BALANCE"):
                    raise GeeTestSolveError(f"Fatal: {error}")
                raise GeeTestSolveError(f"Submit: {error}")

            task_id = data["request"]

            for _ in range(30):
                time.sleep(5)
                result = requests.get("https://ocr.captchaai.com/res.php", params={
                    "key": API_KEY,
                    "action": "get",
                    "id": task_id,
                    "json": 1,
                }, timeout=30).json()

                if result.get("status") == 1:
                    return result["request"]
                if result.get("request") == "ERROR_CAPTCHA_UNSOLVABLE":
                    break

            print(f"Attempt {attempt} failed")

        except requests.RequestException as e:
            print(f"Network error attempt {attempt}: {e}")
            if attempt == max_retries:
                raise GeeTestSolveError(f"Network failure: {e}")
            time.sleep(10)

    raise GeeTestSolveError(f"Failed after {max_retries} attempts")

Troubleshooting

Symptom Cause Fix
"Invalid gt" error GT parameter wrong Verify 32-char hex format
Challenge expired Challenge token is per-session, expires fast Fetch fresh challenge immediately before solving
Solve succeeds but site rejects Challenge reused or expired Use fresh challenge per attempt
"geetest_validate" empty Response parsing error Check CaptchaAI response format
GeeTest API returns success=0 GeeTest in fallback mode Check if site uses offline challenge

Frequently asked questions

How fresh does the challenge need to be?

The challenge token expires within 60-120 seconds. Always fetch a fresh challenge immediately before submitting to CaptchaAI. Never cache or reuse challenges.

What's the difference between GeeTest v3 and v4?

GeeTest v3 uses gt + challenge parameters. GeeTest v4 uses captcha_id + lot_number. This guide covers v3 only.

What's the solve time?

GeeTest v3 typically solves in 5-15 seconds. CaptchaAI achieves a 100% success rate on GeeTest v3.

Can I solve GeeTest offline (fallback) mode?

GeeTest fallback mode is used when GeeTest's servers are unreachable. The challenge type changes. Contact CaptchaAI support for fallback mode handling.


Summary

Solving GeeTest v3 with Python requires: fetch fresh gt and challenge parameters from the site's register API, submit to CaptchaAI using method=geetest, then submit the three result values (geetest_challenge, geetest_validate, geetest_seccode) to the target site. Always use fresh challenge tokens — they expire in under 2 minutes.

Discussions (0)

No comments yet.

Related Posts

Use Cases Multi-Step Checkout Automation with CAPTCHA Solving
Automate multi-step e-commerce checkout flows that include CAPTCHA challenges at cart, payment, or confirmation stages using Captcha AI.

Automate multi-step e-commerce checkout flows that include CAPTCHA challenges at cart, payment, or confirmatio...

Automation Python reCAPTCHA v2
Mar 21, 2026
Reference CAPTCHA Token Injection Methods Reference
Complete reference for injecting solved CAPTCHA tokens into web pages.

Complete reference for injecting solved CAPTCHA tokens into web pages. Covers re CAPTCHA, Turnstile, and Cloud...

Automation Python reCAPTCHA v2
Apr 08, 2026
Tutorials Pytest Fixtures for CaptchaAI API Testing
Build reusable pytest fixtures to test CAPTCHA-solving workflows with Captcha AI.

Build reusable pytest fixtures to test CAPTCHA-solving workflows with Captcha AI. Covers mocking, live integra...

Automation Python reCAPTCHA v2
Apr 08, 2026
Reference Browser Session Persistence for CAPTCHA Workflows
Manage browser sessions, cookies, and storage across CAPTCHA-solving runs to reduce repeat challenges and maintain authenticated state.

Manage browser sessions, cookies, and storage across CAPTCHA-solving runs to reduce repeat challenges and main...

Automation Python reCAPTCHA v2
Feb 24, 2026
Tutorials GeeTest Token Injection in Browser Automation Frameworks
how to inject Gee Test v 3 solution tokens into Playwright, Puppeteer, and Selenium — including the three-value response, callback triggering, and form submissi...

Learn how to inject Gee Test v 3 solution tokens into Playwright, Puppeteer, and Selenium — including the thre...

Automation Python Testing
Jan 18, 2026
Tutorials CAPTCHA Handling in Mobile Apps with Appium
Handle CAPTCHAs in mobile app automation using Appium and Captcha AI — extract Web sitekeys, solve, and inject tokens on Android and i OS.

Handle CAPTCHAs in mobile app automation using Appium and Captcha AI — extract Web View sitekeys, solve, and i...

Automation Python All CAPTCHA Types
Feb 13, 2026
Reference CaptchaAI CLI Tool: Command-Line CAPTCHA Solving and Testing
A reference for building and using a Captcha AI command-line tool — solve CAPTCHAs, check balance, test parameters, and integrate with shell scripts and CI/CD p...

A reference for building and using a Captcha AI command-line tool — solve CAPTCHAs, check balance, test parame...

Automation Python All CAPTCHA Types
Feb 26, 2026
API Tutorials Solve GeeTest v3 CAPTCHA with Python and CaptchaAI
Step-by-step Python tutorial for solving Gee Test v 3 slide puzzle CAPTCHAs using the Captcha AI API.

Step-by-step Python tutorial for solving Gee Test v 3 slide puzzle CAPTCHAs using the Captcha AI API. Includes...

Automation Python Testing
Mar 23, 2026
Use Cases CAPTCHA Solving in Ticket Purchase Automation
How to handle CAPTCHAs on ticketing platforms Ticketmaster, AXS, and event sites using Captcha AI for automated purchasing workflows.

How to handle CAPTCHAs on ticketing platforms Ticketmaster, AXS, and event sites using Captcha AI for automate...

Automation Python reCAPTCHA v2
Feb 25, 2026
Tutorials Caching CAPTCHA Tokens for Reuse
Cache and reuse CAPTCHA tokens with Captcha AI to reduce API calls and costs.

Cache and reuse CAPTCHA tokens with Captcha AI to reduce API calls and costs. Covers token lifetimes, cache st...

Automation Python reCAPTCHA v2
Feb 15, 2026
Tutorials Using Fiddler to Inspect CaptchaAI API Traffic
How to use Fiddler Everywhere and Fiddler Classic to capture, inspect, and debug Captcha AI API requests and responses — filters, breakpoints, and replay for tr...

How to use Fiddler Everywhere and Fiddler Classic to capture, inspect, and debug Captcha AI API requests and r...

Automation Python All CAPTCHA Types
Mar 05, 2026
Tutorials Streaming Batch Results: Processing CAPTCHA Solutions as They Arrive
Process CAPTCHA solutions the moment they arrive instead of waiting for tasks to complete — use async generators, event emitters, and callback patterns for stre...

Process CAPTCHA solutions the moment they arrive instead of waiting for all tasks to complete — use async gene...

Automation Python All CAPTCHA Types
Apr 07, 2026