Se a sua integração com o GeeTest v3 está caindo com erro no envio, ou a API devolve um resultado válido que a página de destino recusa mesmo assim, o motivo mais provável é um único parâmetro: um challenge que já não é mais o mais recente.
O GeeTest v3 gera um challenge novo a cada carregamento do widget na página. Se você captura esse valor uma vez e reaproveita em duas ou três tentativas de resolução, a primeira chamada até pode funcionar — as seguintes praticamente sempre falham, seja rejeitadas pela API no envio, seja aceitas pela API e recusadas pela página de destino.
Este guia organiza os erros do GeeTest v3 por estágio — envio, consulta de resultado e validação na página — com a causa provável e a correção direta para cada um. Comece pela tabela abaixo para localizar seu erro; a seção seguinte cobre em detalhe a causa nº 1: o challenge desatualizado.
Onde está o seu erro? Referência rápida
| Erro / sintoma | Estágio | Causa provável | Correção |
|---|---|---|---|
ERROR_WRONG_USER_KEY |
Envio | Chave de API malformada | Verificar a chave de 32 caracteres |
ERROR_KEY_DOES_NOT_EXIST |
Envio | Chave inválida ou inativa | Conferir no painel da CaptchaAI |
ERROR_ZERO_BALANCE |
Envio | Nenhuma thread livre no plano | Aguardar liberação ou fazer upgrade do plano |
ERROR_PAGEURL |
Envio | pageurl ausente |
Adicionar a URL completa da página |
ERROR_BAD_PARAMETERS |
Envio | gt, challenge ou pageurl ausente/incorreto |
Conferir todos os campos obrigatórios |
CAPCHA_NOT_READY |
Consulta | Resolução ainda em andamento | Aguardar 5 s e consultar de novo |
ERROR_WRONG_ID_FORMAT |
Consulta | ID de captcha não numérico | Usar o ID exato retornado por in.php |
ERROR_WRONG_CAPTCHA_ID |
Consulta | ID não corresponde a nenhuma tarefa | Verificar o ID da resposta de envio |
ERROR_EMPTY_ACTION |
Consulta | Falta action=get |
Incluir o parâmetro action |
ERROR_CAPTCHA_UNSOLVABLE |
Consulta | Challenge desatualizado ou variante não suportada | Buscar um challenge novo e tentar de novo |
ERROR_INTERNAL_SERVER_ERROR |
Consulta | Problema no lado do servidor da CaptchaAI | Aguardar 10 s e tentar de novo |
| Resposta em HTML ou erro 500/502 | Envio | Falha transitória do servidor | Aguardar de 5 a 10 s e reenviar |
| API retorna valores, página recusa | Validação | Challenge desatualizado, campos trocados ou pageurl errado |
Buscar challenge novo e revisar o mapeamento de campos |
Duas correções da tabela merecem contexto: para ERROR_WRONG_USER_KEY e ERROR_KEY_DOES_NOT_EXIST, confira a chave em captchaai.com/api.php e confirme no painel da CaptchaAI que ela está ativa — sem caracteres extras nem espaços em branco.
A causa nº 1: challenge desatualizado
Se você só tiver tempo de checar uma coisa antes de investigar qualquer outra, seja a atualidade do challenge.
O GeeTest v3 exige dois parâmetros centrais:
| Parâmetro | O que é | Muda entre carregamentos? |
|---|---|---|
gt |
Chave pública do site | Não — é estática |
challenge |
Chave de desafio dinâmica | Sim — a cada carregamento da página |
Por que isso acontece
O valor de challenge é gerado no momento em que o widget GeeTest é inicializado na página. Se você captura esse valor uma vez e reutiliza em várias requisições de resolução, a requisição seguinte à primeira normalmente é rejeitada pela API no momento do envio, ou retorna um resultado que a página de destino recusa porque o challenge já expirou.
A CaptchaAI é explícita sobre isso nos documentos da API do GeeTest v3: é preciso obter um challenge novo a cada requisição de resolução — assim que o captcha carrega na página, o desafio anterior se torna inválido.
Exemplo comum: um pipeline de QA rodando em uma instância na região sa-east-1 (São Paulo) captura o challenge uma vez no início do teste, enfileira três variações do mesmo formulário e só envia cada resolução alguns segundos depois de a anterior terminar. A primeira resolução passa; a segunda e a terceira caem em ERROR_CAPTCHA_UNSOLVABLE ou são recusadas pela página — porque o challenge capturado no início do pipeline já não é mais válido quando chega a vez das últimas requisições. A correção é sempre a mesma: buscar um challenge novo imediatamente antes de cada resolução, nunca uma vez por lote.
Como resolver
Antes de cada requisição de resolução, inspecione as requisições de rede da página para encontrar a chamada de API que retorna um challenge novo. Repita essa requisição para obter um valor atualizado e envie-o imediatamente à CaptchaAI.
# Pseudocode: fetch a fresh challenge before each solve
import requests
def get_fresh_challenge(target_url):
"""Hit the GeeTest init endpoint to get a new challenge."""
resp = requests.get(f"{target_url}/geetest/register", timeout=10)
data = resp.json()
return data["challenge"], data["gt"]
challenge, gt = get_fresh_challenge("https://example.com")
# Now submit to CaptchaAI immediately — do not delay
Regra prática: se o tempo entre capturar o
challengee enviar a requisição de resolução passar de poucos segundos, busque um valor novo antes de enviar.
Erros que pedem atenção extra
A tabela acima já dá a correção rápida para a maioria dos códigos. Cinco deles têm uma pegadinha que vale a pena destrinchar antes de você sair copiando a correção — os demais (ERROR_WRONG_USER_KEY, ERROR_KEY_DOES_NOT_EXIST, ERROR_WRONG_ID_FORMAT, ERROR_WRONG_CAPTCHA_ID, ERROR_CAPTCHA_UNSOLVABLE, HTML/500/502 e ERROR_INTERNAL_SERVER_ERROR) são autoexplicativos: a causa e a correção da tabela resolvem o caso sem mistério.
ERROR_ZERO_BALANCE: aparece mesmo com saldo positivo
Esse erro acontece ao enviar a tarefa para https://ocr.captchaai.com/in.php e não tem relação com dinheiro em conta — é sobre threads livres. Cada plano da CaptchaAI libera um número fixo de threads simultâneas; quando todas estão ocupadas no momento do envio, a próxima requisição recebe ERROR_ZERO_BALANCE mesmo com créditos disponíveis.
Correção: aguarde a liberação de threads, reduza a simultaneidade das requisições ou faça upgrade do plano.
ERROR_PAGEURL: falta a URL completa da página
Causa: o parâmetro pageurl está ausente na requisição de envio.
Correção: adicione a URL completa da página onde o widget GeeTest é carregado. Exemplo:
pageurl=https://staging.example.com/qa-login
ERROR_BAD_PARAMETERS: qual campo está faltando
Causa: um ou mais campos obrigatórios estão ausentes ou malformados no envio. Para o GeeTest, os parâmetros obrigatórios são:
| Parâmetro | Tipo | Obrigatório | Descrição |
|---|---|---|---|
key |
String | Sim | Sua chave de API da CaptchaAI |
method |
String | Sim | Deve ser geetest |
gt |
String | Sim | Chave pública estática do site |
challenge |
String | Sim | Chave de desafio dinâmica (precisa estar atualizada) |
pageurl |
String | Sim | URL completa da página |
Correção: confira se gt, challenge e pageurl estão todos presentes e formatados corretamente.
Este guia cobre apenas o GeeTest v3 (
method=geetest), que é totalmente suportado hoje. O GeeTest v4 ainda não está disponível na CaptchaAI — consulte os documentos da API da CaptchaAI para a lista mais atual de tipos suportados.
CAPCHA_NOT_READY: isso não é um erro
Esse "erro" aparece ao consultar https://ocr.captchaai.com/res.php e só significa que a resolução ainda está em andamento. O GeeTest v3 costuma ser resolvido pela CaptchaAI em menos de 12 segundos, com alta taxa de sucesso nos tipos suportados.
Correção: aguarde 5 segundos e consulte novamente. Não trate isso como falha nem interrompa o fluxo.
ERROR_EMPTY_ACTION: falta o parâmetro action
Causa: o parâmetro action está ausente ou vazio na requisição de consulta.
Correção: inclua action=get em toda requisição de consulta:
https://ocr.captchaai.com/res.php?key=YOUR_KEY&action=get&id=CAPTCHA_ID
A API acertou, mas a página recusa: falhas de validação
Essas são as falhas mais difíceis de depurar: a API da CaptchaAI retorna um resultado válido, mas a página de destino recusa mesmo assim.
Quando uma resolução do GeeTest v3 é bem-sucedida, a API retorna três valores:
{
"challenge": "1a2b3456cd67890e12345fab678901c2de",
"validate": "09fe8d7c6ba54f32e1dcb0a9fedc8765",
"seccode": "12fe3d4c56789ba01f2e345d6789c012|jordan"
}
Eles precisam ser enviados à página de destino como:
| Campo da resposta da API | Campo esperado pela página |
|---|---|
challenge |
geetest_challenge |
validate |
geetest_validate |
seccode |
geetest_seccode |
Esse modelo de três campos é específico do GeeTest — outros tipos, como o reCAPTCHA v2, retornam um único token. Se você também integra reCAPTCHA v2, veja Como resolver reCAPTCHA v2 usando a API.
| Falha | Sintoma | Causa | Correção |
|---|---|---|---|
| Mapeamento de campo errado | A página recusa os valores de imediato | Os valores foram inseridos nos campos errados ou no caminho de requisição errado | Inspecione a requisição POST de uma resolução manual e faça os nomes de campo corresponderem exatamente |
challenge desatualizado usado na etapa anterior |
A página diz que o challenge expirou ou é inválido | O challenge foi capturado cedo demais ou reutilizado em mais de uma requisição |
Busque um challenge novo imediatamente antes de cada requisição — nunca cache nem reutilize |
| Contexto de página errado | A validação falha mesmo com valores recém-obtidos | O pageurl enviado à CaptchaAI não corresponde à página real onde o widget foi carregado |
Use a URL exata, incluindo protocolo e caminho; se o widget carrega via AJAX numa rota diferente, use a URL dessa rota |
| Formato de requisição incompatível | Os campos estão corretos, mas o formato está errado | A página espera os campos em um tipo de conteúdo específico (JSON vs. formulário) ou junto de outros campos | Compare com o tráfego de rede de uma resolução manual: tipo de conteúdo, ordem dos campos, campos adicionais |
Na prática, a falha mais comum de longe é a segunda linha da tabela: challenge desatualizado. Se você já confirmou que o mapeamento de campos está correto e o pageurl bate com a página real, volte para a seção sobre a causa nº 1 antes de investigar formato de requisição — é raríssimo um site mudar o content-type do POST do GeeTest de um dia para o outro, mas é comum um challenge ficar velho no meio de um lote de testes.
Python: solução completa de GeeTest v3 com renovação automática de challenge
import time
import requests
API_KEY = "YOUR_CAPTCHAAI_API_KEY"
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"
def get_fresh_challenge(target_url):
"""Fetch a fresh GeeTest challenge from the target page."""
resp = requests.get(f"{target_url}/api/geetest/register", timeout=10)
data = resp.json()
return data["gt"], data["challenge"]
def solve_geetest_v3(api_key, gt, challenge, pageurl):
"""Submit a GeeTest v3 challenge and return the validation package."""
# Submit
submit_resp = requests.post(
SUBMIT_URL,
data={
"key": api_key,
"method": "geetest",
"gt": gt,
"challenge": challenge,
"pageurl": pageurl,
"json": 1,
},
timeout=30,
)
submit_resp.raise_for_status()
submit_data = submit_resp.json()
if submit_data.get("status") != 1:
raise RuntimeError(f"Submit failed: {submit_data}")
captcha_id = submit_data["request"]
print(f"Task created — captcha ID: {captcha_id}")
# Wait before first poll
time.sleep(15)
# Poll for result
for _ in range(60):
result_resp = requests.get(
RESULT_URL,
params={
"key": api_key,
"action": "get",
"id": captcha_id,
"json": 1,
},
timeout=30,
)
result_resp.raise_for_status()
result_data = result_resp.json()
if result_data.get("request") == "CAPCHA_NOT_READY":
time.sleep(5)
continue
if result_data.get("status") == 1:
return result_data["request"]
raise RuntimeError(f"Polling error: {result_data}")
raise TimeoutError("GeeTest v3 solve timed out")
# Usage: always fetch a fresh challenge first
PAGE_URL = "https://staging.example.com/qa-login"
gt, challenge = get_fresh_challenge(PAGE_URL)
result = solve_geetest_v3(API_KEY, gt, challenge, PAGE_URL)
print(f"Result: {result}")
# The result contains: challenge, validate, seccode
# Map them to: geetest_challenge, geetest_validate, geetest_seccode
Node.js: solução completa de GeeTest v3 com renovação automática de challenge
const API_KEY = "YOUR_CAPTCHAAI_API_KEY";
const SUBMIT_URL = "https://ocr.captchaai.com/in.php";
const RESULT_URL = "https://ocr.captchaai.com/res.php";
function sleep(ms) {
return new Promise((resolve) => setTimeout(resolve, ms));
}
async function getFreshChallenge(targetUrl) {
const resp = await fetch(`${targetUrl}/api/geetest/register`);
const data = await resp.json();
return { gt: data.gt, challenge: data.challenge };
}
async function solveGeetestV3(apiKey, gt, challenge, pageurl) {
// Submit
const submitResp = await fetch(SUBMIT_URL, {
method: "POST",
headers: { "Content-Type": "application/x-www-form-urlencoded" },
body: new URLSearchParams({
key: apiKey,
method: "geetest",
gt: gt,
challenge: challenge,
pageurl: pageurl,
json: "1",
}),
});
const submitData = await submitResp.json();
if (submitData.status !== 1) {
throw new Error(`Submit failed: ${JSON.stringify(submitData)}`);
}
const captchaId = submitData.request;
console.log(`Task created — captcha ID: ${captchaId}`);
await sleep(15_000);
// Poll for result
for (let i = 0; i < 60; i++) {
const resultResp = await fetch(
`${RESULT_URL}?${new URLSearchParams({
key: apiKey,
action: "get",
id: captchaId,
json: "1",
})}`
);
const resultData = await resultResp.json();
if (resultData.request === "CAPCHA_NOT_READY") {
await sleep(5_000);
continue;
}
if (resultData.status === 1) {
return resultData.request;
}
throw new Error(`Polling error: ${JSON.stringify(resultData)}`);
}
throw new Error("GeeTest v3 solve timed out");
}
// Usage
const PAGE_URL = "https://staging.example.com/qa-login";
(async () => {
const { gt, challenge } = await getFreshChallenge(PAGE_URL);
const result = await solveGeetestV3(API_KEY, gt, challenge, PAGE_URL);
console.log("Result:", result);
// Map result fields to: geetest_challenge, geetest_validate, geetest_seccode
})();
Perguntas frequentes
Por que a requisição do GeeTest v3 falha mesmo com gt e challenge aparentemente corretos?
Na grande maioria dos casos, o challenge usado já não é mais o mais recente. Mesmo com gt e pageurl corretos, um challenge expirado faz a API falhar ou faz a página de destino recusar os valores retornados. Busque um challenge novo imediatamente antes de cada requisição de resolução — nunca reaproveite o mesmo valor em mais de uma tentativa.
ERROR_ZERO_BALANCE apareceu, mas meu saldo está positivo. Por quê?
Porque esse erro não é sobre saldo em dinheiro — é sobre threads livres. Cada plano da CaptchaAI libera um número fixo de threads simultâneas; se todas estiverem ocupadas no momento do envio, a próxima requisição recebe ERROR_ZERO_BALANCE mesmo com créditos disponíveis na conta. Reduza a simultaneidade das suas requisições, aguarde uma thread liberar ou faça upgrade do plano.
Preciso abrir um navegador de verdade para capturar um challenge novo, ou dá para automatizar direto por requisição HTTP?
Dá para automatizar totalmente por requisição HTTP — não é preciso abrir um navegador completo em produção. O endpoint que gera o challenge no GeeTest normalmente é uma chamada de API simples (o exemplo deste guia usa /api/geetest/register); basta repeti-la programaticamente antes de cada resolução. Um navegador (ou uma ferramenta como Selenium ou Playwright) só é necessário na fase de investigação, para descobrir qual chamada de rede retorna o challenge no site específico.
A API retornou challenge, validate e seccode certos, mas a página ainda recusa. Por onde eu começo?
Verifique três pontos, nesta ordem:
- Atualidade do challenge — o
challengefoi obtido imediatamente antes do envio? - Mapeamento de campos —
geetest_challenge,geetest_validateegeetest_seccodeestão indo para os campos que a página realmente espera? - Formato da requisição — a página espera JSON, dados de formulário ou outro formato? Compare com o tráfego de rede de uma resolução manual.
Um challenge capturado em staging funciona se eu reusar em produção?
Não. O challenge está amarrado à sessão e ao carregamento específico do widget na página onde ele foi gerado — mesmo que o gt (chave pública do site) seja igual nos dois ambientes, um challenge capturado em staging não passa na validação em produção. Sempre capture o challenge no mesmo ambiente e na mesma carga de página onde a resolução será enviada.
Corrija seu fluxo GeeTest em 4 passos
Se a sua integração com o GeeTest estiver falhando, siga esta ordem:
- Confira o challenge — ele é o mais recente? Busque um novo imediatamente antes de cada resolução.
- Verifique os parâmetros —
gt,challengeepageurlprecisam estar todos corretos. - Inspecione o mapeamento de campos — os valores retornados de
challenge,validateeseccodeprecisam ir para os campos certos na página. - Compare com uma resolução manual — use o DevTools do navegador para capturar a estrutura exata da requisição de uma resolução manual bem-sucedida do GeeTest.
Comece pelo solucionador GeeTest v3 da CaptchaAI, confira seus parâmetros nos documentos da API e leia Como funciona o CAPTCHA GeeTest v3 se precisar de contexto sobre o fluxo do desafio.
Registro de iteração
| Iteração | Foco | Mudanças |
|---|---|---|
| Rascunho 1 | Estrutura e conteúdo | Rascunho inicial da solução de problemas – 3 estágios de erro, tabela de erros para correção, perguntas frequentes |
| Rascunho 2 | Precisão técnica | Verificou todos os códigos de erro e parâmetros GeeTest em captchaai.com/api-docs. Adicionada tabela de parâmetros de API. Mapeamento de campo do desafio /validate/seccode confirmado. |
| Rascunho 3 | Exemplos de código | Adicionados exemplos completos de Python e Node.js com busca de novos desafios. Adicionado pseudocódigo para padrão de atualização de desafio. |
| Rascunho 4 | Profundidade de falhas de validação | Seção expandida de validação da página de destino com 4 modos de falha distintos. Adicionada tabela de mapeamento de campo. Adicionado diagnóstico de incompatibilidade de estrutura de requisição. |
| Rascunho 5 | Polimento final do controle de qualidade | Verificados todos os códigos de erro correspondem aos documentos oficiais. Adicionada tabela de referência rápida. Introdução apertada. Adicionados links cruzados para agrupar artigos. As respostas confirmadas das perguntas frequentes estão prontas para o esquema. |
| Rascunho 6 | Transcriação nativa pt-BR | Introdução reescrita com gancho próprio; tabela de referência rápida movida para logo após a introdução; terminologia padronizada (thread, requisição, consulta) conforme o guia de estilo; taxa de sucesso absoluta substituída por linguagem qualitativa, conforme captchaai-solve-metrics.md; adicionado exemplo local (pipeline QA em sa-east-1); 5 perguntas frequentes novas com menor sobreposição com o artigo em inglês; description, meta_description, keywords e CTA reescritos nativamente. |
Resumo do recurso visual
Imagem do herói
- Texto alternativo: Solução de problemas do desenvolvedor para erros GeeTest v3 — diagnóstico de falhas de requisição, consulta e validação
- Deve mostrar: Contexto de depuração com estágios de fluxo de erros e pontos de falha
- Nome do arquivo: geetest-v3-errors-troubleshooting-hero.png
Visual no artigo 1
- Posicionamento: Após "Erros que pedem atenção extra"
- Tipo: Árvore de decisão
- Texto alternativo: Árvore de decisão para falhas GeeTest v3 — erros de envio versus erros de consulta versus falhas de validação
- Nome do arquivo: geetest-v3-error-decision-tree.png
Visual no artigo 2
- Posicionamento: após "A API acertou, mas a página recusa"
- Tipo: Diagrama de causas e soluções
- Texto alternativo: Diagrama mostrando causas comuns de rejeição de página GeeTest v3 e suas soluções
- Nome do arquivo: geetest-v3-validation-causes-fixes.png