Explainers

GeeTest v3 Challenge-Response Workflow: Technical Deep Dive

GeeTest v3 uses a multi-step challenge-response protocol. Unlike reCAPTCHA where a single token solves everything, GeeTest involves a registration step, a challenge token exchange, and a final validation — each producing different parameters. Understanding this flow is essential for correct integration con CaptchaAI.

The Two-Phase Protocol

GeeTest v3 operates in two phases:

Phase 1: Registration (Server-Side)

The site's backend contacts GeeTest to register a new challenge:

Site Backend → GeeTest Server: "Give me a challenge for this user"
GeeTest Server → Site Backend: { gt, challenge, new_captcha }
Site Backend → Browser: Passes gt and challenge to the page

Phase 2: Verification (Client-Side + Server-Side)

The browser renders the challenge, the user solves it, and the result is verified:

Browser: Renders slider/puzzle using gt + challenge
User: Solves the challenge
Browser → Site Backend: { geetest_challenge, geetest_validate, geetest_seccode }
Site Backend → GeeTest Server: Verifies the three values
GeeTest Server → Site Backend: { result: "success" }

Detailed Flow

Step 1: Registration API Call

The site's backend calls GeeTest's registration endpoint:

GET https://api.geetest.com/register.php?gt=GT_ID&json_format=1

Respuesta:

{
  "success": 1,
  "gt": "81dc9bdb52d04dc20036dbd8313ed055",
  "challenge": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  "new_captcha": true
}
Parámetro Significado
gt GeeTest ID — identifies the site's GeeTest account
challenge Unique challenge token for this session
new_captcha Whether to use the new CAPTCHA format

Important: The challenge value is single-use and time-limited. Each page load generates a new challenge.

Step 2: Challenge Rendering

The browser receives gt and challenge and initializes the GeeTest widget:

initGeetest({
  gt: "81dc9bdb52d04dc20036dbd8313ed055",
  challenge: "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6",
  offline: false,
  new_captcha: true,
  product: "float"
}, function(captchaObj) {
  captchaObj.appendTo('#captcha-container');
  captchaObj.onSuccess(function() {
    var result = captchaObj.getValidate();
    // result contains: geetest_challenge, geetest_validate, geetest_seccode
  });
});

Step 3: Challenge Types

GeeTest v3 supports several challenge types:

Tipo User action Descripción
Slider Drag puzzle piece Move a puzzle piece to complete the image
Icon click Click icons in order Click specific icons in the shown sequence
Word click Click characters Click Chinese characters in the correct order
Space Click/select Spatial reasoning challenge

The challenge type is determined by GeeTest based on the site's configuration and user risk profile.

Step 4: Solution Values

After solving, the widget produces three values:

{
  "geetest_challenge": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6xy",
  "geetest_validate": "abc123def456_validate",
  "geetest_seccode": "abc123def456_validate|jordan"
}
Valor Descripción
geetest_challenge Modified challenge token (original + 2 extra chars)
geetest_validate Validation hash
geetest_seccode Security code (validate + \ | jordan suffix)

Step 5: Server-Side Verification

The site backend sends these three values to GeeTest for verification:

POST https://api.geetest.com/validate.php

seccode=abc123def456_validate|jordan
&challenge=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6xy
&sdk=geetest-python-3.0.0

GeeTest responds with:

{
  "seccode": "abc123def456_validate",
  "validate": "abc123def456_validate"
}

Extracting Parameters for CaptchaAI

To solve con CaptchaAI, you need gt and challenge from the page:

Method 1: Intercept the Registration Response

from playwright.sync_api import sync_playwright
import json

with sync_playwright() as p:
    browser = p.chromium.launch()
    page = browser.new_page()

    geetest_params = {}

    def handle_response(response):
        if "register" in response.url and "geetest" in response.url:
            data = response.json()
            geetest_params["gt"] = data.get("gt")
            geetest_params["challenge"] = data.get("challenge")

    page.on("response", handle_response)
    page.goto("https://staging.example.com/qa-login")

    # Wait for GeeTest to load
    page.wait_for_selector(".geetest_holder")
    print(f"gt: {geetest_params.get('gt')}")
    print(f"challenge: {geetest_params.get('challenge')}")

Method 2: Extract from Page JavaScript

gt = page.evaluate("() => document.querySelector('[data-gt]')?.dataset.gt")
challenge = page.evaluate("() => document.querySelector('[data-challenge]')?.dataset.challenge")

Method 3: From initGeetest Call

Search the page source for the initGeetest call:

import re
source = page.content()
gt_match = re.search(r"gt['\"]?\s*[:=]\s*['\"]([a-f0-9]{32})['\"]", source)
challenge_match = re.search(r"challenge['\"]?\s*[:=]\s*['\"]([a-f0-9]{32})['\"]", source)

Resolviendo con CaptchaAI

Submit the extracted parameters:

POST https://ocr.captchaai.com/in.php

key=YOUR_API_KEY
&method=geetest
&gt=81dc9bdb52d04dc20036dbd8313ed055
&challenge=a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6
&pageurl=https://staging.example.com/qa-login
&json=1

Poll for the result:

GET https://ocr.captchaai.com/res.php?key=YOUR_API_KEY&action=get&id=TASK_ID&json=1

CaptchaAI returns:

{
  "status": 1,
  "request": {
    "geetest_challenge": "a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6xy",
    "geetest_validate": "abc123def456_validate",
    "geetest_seccode": "abc123def456_validate|jordan"
  }
}

You receive all three values needed for the site's verification step.

Offline vs Online Mode

GeeTest v3 has a fallback mode when GeeTest servers are unreachable:

Mode success value Comportamiento
Online 1 Normal challenge-response with GeeTest servers
Offline 0 Simplified local verification

In offline mode, the challenge is generated locally and verification is simpler. Most sites use online mode.

Solución de problemas

Problema causa Solución
challenge value is empty Registration failed Check if the site loads GeeTest correctly
Solution rejected Challenge expired Extract fresh challenge and solve immediately
Valor gt incorrecto Multiple GeeTest instances on page Extract gt from the correct widget
Three values returned but form doesn't submit Missing form fields Inject all three values into the correct inputs

Preguntas frecuentes

Why does GeeTest need both gt and challenge?

The gt identifies the site's GeeTest account (persistent). The challenge is a session-specific token that prevents replay attacks — each challenge can only be solved once.

Can I reuse a GeeTest challenge?

No. Each challenge value is single-use. After it's solved (or expires), you must get a new one from the registration API.

How long does a GeeTest challenge last?

Challenges typically expire within 1-2 minutes. Solve and submit promptly after extracting the parameters.

Artículos relacionados

Próximos pasos

Resuelve los desafíos GeeTest v3:obtenga su clave API CaptchaAIe integre la respuesta de los tres valores en su flujo de trabajo.

Los comentarios están deshabilitados para este artículo.

Publicaciones relacionadas

Explainers GeeTest v4 Guía de resolución y cambios de CAPTCHA
Explicación clara sobre Gee Test v 4 CAPTCHA Changes and Solving Guide y lo que implica para automatización, integración y tasas de éxito con Captcha AI.

Explicación clara sobre Gee Test v 4 CAPTCHA Changes and Solving Guide y lo que implica para automatización, i...

Apr 25, 2026
Comparisons Cloudflare Managed Challenge vs Interactive Challenge
Cloudflare Managed Challenge vs Interactive Challenge: diferencias de comportamiento, códigos HTTP, métodos de resolución con Captcha AI y cuándo usar cada uno.

Cloudflare Managed Challenge vs Interactive Challenge: diferencias de comportamiento, códigos HTTP, métodos de...

Apr 18, 2026
Troubleshooting Errores y soluciones comunes de reCAPTCHA Invisible
Errores comunes en la resolución de re CAPTCHA Invisible y cómo solucionarlos: callback no ejecutado, parámetro invisible=1, token caducado, pageurl incorrecto...

Errores comunes en la resolución de re CAPTCHA Invisible y cómo solucionarlos: callback no ejecutado, parámetr...

Apr 24, 2026