API Tutorials

Como resolver GeeTest v3 usando API

Para resolver um desafio GeeTest v3 pela API da CaptchaAI, você primeiro precisa capturar três valores que o próprio site gera: gt, challenge e, em alguns casos, api_server. Sem eles, a chamada para in.php falha direto com ERROR_BAD_PARAMETERS. Diferente do reCAPTCHA, o GeeTest não aceita apenas uma sitekey fixa — é preciso extrair esses valores da página antes de enviar qualquer coisa.

Este guia cobre o fluxo completo em quatro etapas:

  • onde achar os parâmetros na página
  • como enviar a tarefa para a API
  • como fazer o polling do resultado
  • como devolver a solução ao site

O que você precisa antes de começar

Reúna estes cinco itens antes de escrever qualquer código — sem eles a chamada para in.php não passa:

  • Chave de API da CaptchaAI, obtida em captchaai.com
  • Valor gt do GeeTest, identificador estático (um por site)
  • Valor challenge do GeeTest, dinâmico — muda a cada sessão
  • URL da página onde o GeeTest é exibido
  • Ambiente: Python 3.7+ ou Node.js 14+

Etapa 1: extraia os parâmetros do GeeTest na página

Dois fatos importantes antes de começar:

  • o gt é estático — o mesmo valor em todas as requisições ao mesmo site
  • o challenge muda a cada sessão — busque-o de novo antes de cada tentativa

Opção 1: aba Rede do DevTools

Abra o DevTools na aba Rede (Network), filtre por register-slide, gettype.php ou get.php, e dispare o CAPTCHA na página. A resposta da requisição de inicialização traz gt, challenge e, às vezes, api_server.

{
  "success": 1,
  "gt": "019924a82c70bb123aae90d483087f94",
  "challenge": "12345678abc90def12345678abc90def",
  "new_captcha": true
}

Dica: se a resposta da inicialização não aparecer na aba Rede, o site provavelmente já carregou o gt/challenge no HTML inicial — vá direto para a Opção 2.

Opção 2: código-fonte da página

// Search page source for initGeetest or gt value
document.querySelectorAll('script').forEach(s => {
  if (s.textContent.includes('initGeetest')) {
    console.log(s.textContent);
  }
});

Opção 3: endpoint de registro do próprio site

Muitos sites buscam os parâmetros do GeeTest em uma API interna deles mesmos:

# The site's registration endpoint
params_response = requests.get("https://example.com/api/captcha/register")
data = params_response.json()
gt = data["gt"]
challenge = data["challenge"]

Nota: nem todo site expõe um endpoint de registro próprio. Se nenhuma das três opções funcionar, capture o challenge diretamente do evento de disparo do widget (onSuccess/initGeetest callback) via DevTools.


Etapa 2: envie a tarefa para a API da CaptchaAI

Python

import requests
import time

API_KEY = "YOUR_API_KEY"

response = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": API_KEY,
    "method": "geetest",
    "gt": "019924a82c70bb123aae90d483087f94",
    "challenge": "12345678abc90def12345678abc90def",
    "api_server": "api.geetest.com",  # Optional, use if site specifies
    "pageurl": "https://staging.example.com/qa-login",
    "json": 1
})

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

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

Node.js

const axios = require('axios');

const API_KEY = 'YOUR_API_KEY';

async function submitGeeTest(gt, challenge, pageurl) {
  const { data } = await axios.get('https://ocr.captchaai.com/in.php', {
    params: {
      key: API_KEY,
      method: 'geetest',
      gt,
      challenge,
      api_server: 'api.geetest.com',
      pageurl,
      json: 1
    }
  });

  if (data.status !== 1) throw new Error(`Submit error: ${data.request}`);
  return data.request;
}

Nota: api_server é opcional na maioria dos casos — inclua o parâmetro apenas quando o site especificar explicitamente um servidor GeeTest diferente do padrão.


Etapa 3: consulte o resultado por polling

A resolução devolve três valores:

  • challenge
  • validate
  • seccode

Faça polling em res.php até o status virar 1 — a task_id sozinha não serve para nada no formulário.

Python

def get_geetest_solution(task_id):
    for attempt 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"]
        if result.get("request") != "CAPCHA_NOT_READY":
            raise Exception(f"Error: {result.get('request')}")

    raise Exception("Timeout")

solution = get_geetest_solution(task_id)
# solution = {
#   "geetest_challenge": "12345678abc90def12345678abc90def1a",
#   "geetest_validate": "abcdef1234567890abcdef1234567890",
#   "geetest_seccode": "abcdef1234567890abcdef1234567890|jordan"
# }

Node.js

async function getGeeTestSolution(taskId) {
  for (let i = 0; i < 30; i++) {
    await new Promise(r => setTimeout(r, 5000));
    const { data } = await axios.get('https://ocr.captchaai.com/res.php', {
      params: { key: API_KEY, action: 'get', id: taskId, json: 1 }
    });
    if (data.status === 1) return data.request;
    if (data.request !== 'CAPCHA_NOT_READY') throw new Error(data.request);
  }
  throw new Error('Timeout');
}

Dica de latência: testando a partir de sa-east-1 (São Paulo) contra um serviço hospedado longe dali? Some o RTT extra ao polling — o desafio em si não fica mais lento, só a ida e volta.


Etapa 4: envie a solução ao endpoint do site

Envie estes três campos retornados para o endpoint de verificação do site:

  • geetest_challenge
  • geetest_validate
  • geetest_seccode

Exemplo de envio via formulário:

# Submit the GeeTest solution with the form data
verify_response = requests.post("https://example.com/api/login", data={
    "username": "[email protected]",
    "password": "password123",
    "geetest_challenge": solution["geetest_challenge"],
    "geetest_validate": solution["geetest_validate"],
    "geetest_seccode": solution["geetest_seccode"]
})

print(f"Login status: {verify_response.status_code}")

Exemplo completo em Python

import requests
import time

API_KEY = "YOUR_API_KEY"
SITE_URL = "https://staging.example.com/qa-login"

# 1. Get GeeTest parameters from the site
params = requests.get("https://example.com/api/captcha/register").json()

# 2. Submit to CaptchaAI
submit = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": API_KEY,
    "method": "geetest",
    "gt": params["gt"],
    "challenge": params["challenge"],
    "pageurl": SITE_URL,
    "json": 1
}).json()
task_id = submit["request"]

# 3. Poll for solution
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:
        solution = result["request"]
        break

# 4. Submit to site
login = requests.post(SITE_URL, data={
    "username": "[email protected]",
    "password": "pass",
    "geetest_challenge": solution["geetest_challenge"],
    "geetest_validate": solution["geetest_validate"],
    "geetest_seccode": solution["geetest_seccode"]
})
print(f"Result: {login.status_code}")

Erros comuns do GeeTest v3 e como corrigir

Os cinco problemas mais frequentes na integração, com a causa e a correção direta:

  • ERROR_BAD_PARAMETERS — faltam gt ou challenge. Os dois são obrigatórios; extraia-os da página antes de enviar.
  • ERROR_CAPTCHA_UNSOLVABLE — o desafio expirou ou é inválido. Busque um challenge novo direto no site.
  • Site rejeita a solução — valor de challenge desatualizado. O challenge é de uso único; gere um novo a cada tentativa.
  • geetest_validate vem vazio — falha interna na resolução. Tente novamente com um challenge recém-obtido.
  • Página nunca expõe gt/challenge no formato esperado — o site migrou para GeeTest v4. A CaptchaAI ainda não suporta GeeTest v4 (previsto como "em breve"); confirme a versão antes de integrar.

Quer o projeto pronto para rodar?

Precisa de um projeto completo com setup de ambiente, polling, retentativas e tratamento de erros já resolvidos?

Veja o exemplo executável completo no GitHub →


Perguntas frequentes

Por que preciso buscar um challenge novo a cada tentativa?

Porque ele é de uso único. O backend do site rejeita qualquer reenvio com o mesmo valor assim que ele é consumido, seja por:

  • uma resolução bem-sucedida, ou
  • expiração

Capture um challenge novo antes de cada chamada a in.php.

O fluxo muda entre desafios de slide, seleção de ícones e correspondência de palavras?

Não. O GeeTest v3 tem vários formatos visuais:

  • quebra-cabeça de slide
  • seleção de ícones
  • correspondência de palavras

Mas os parâmetros da API e o processo de envio são idênticos em todos. A CaptchaAI trata os três tipos da mesma forma — você não precisa detectar qual variante apareceu.

Como evito travar minha fila de automação enquanto o polling roda?

Duas práticas resolvem isso:

  • trate o polling em res.php como uma etapa isolada, com timeout próprio (os 30 intervalos de 5 s do exemplo já cobrem a maioria dos casos), rodando fora da thread principal do pipeline
  • em volume alto, use um worker dedicado por task_id em vez de bloquear o restante da fila

Preciso me preocupar com a LGPD ao registrar esses parâmetros em log?

Se o log de QA junta pageurl, gt ou challenge a dados de usuário reais, trate isso como dado pessoal para fins de LGPD (RGPD em Portugal) e não persista além do necessário para depuração. Em teste, prefira dados fictícios e URLs de staging — os parâmetros em si não são pessoais, mas o contexto ao redor pode ser.

O que devo checar antes de sair do staging para produção?

Confirme estes três pontos antes do deploy:

  • pageurl de produção (não staging)
  • retentativa automática para ERROR_CAPTCHA_UNSOLVABLE
  • um challenge novo a cada carregamento

Reaproveitar valores entre ambientes é a causa mais comum de rejeição.


Guias relacionados

Para aprofundar: entenda como funciona o CAPTCHA GeeTest v3, consulte a lista completa de erros comuns do GeeTest v3 e como corrigir, ou veja GeeTest vs. reCAPTCHA: qual escolher para decidir qual tipo integrar primeiro.

Os comentários estão desativados para este artigo.