Seu reCAPTCHA v2 devolve um token, mas o formulário não avança? Na prática, quase toda falha nasce em um destes três pontos: um parâmetro errado no envio da tarefa à API (in.php), uma tarefa que trava no polling de res.php, ou um token válido que a página de destino rejeita mesmo assim. E a causa raiz, na maioria dos casos, está em apenas quatro lugares: googlekey, pageurl, execução do callback ou validade do token.
Este guia mapeia cada código de erro retornado pela API da CaptchaAI para a causa exata e o ajuste de código correspondente. Se você ainda não configurou a integração, comece pelo tutorial de reCAPTCHA v2 com a API antes de seguir para o troubleshooting.
Resposta rápida: na grande maioria dos casos, o problema está em um destes quatro pontos, nesta ordem:
googlekey,pageurl, execução do callback, ou validade do token. Confira os quatro antes de abrir qualquer ferramenta de depuração.
Onde o reCAPTCHA v2 mais falha: os 4 pontos críticos
Antes de sair caçando código de erro por código de erro, verifique estes quatro pontos — eles respondem pela maior parte das falhas em produção:
googlekeyerrado ou ausente — a sitekey vem do atributodata-sitekeyno widget do reCAPTCHA ou do parâmetrokna URL do anchor. Se estiver errada, em branco, ou copiada de outra página do mesmo site, a API rejeita a tarefa na hora comERROR_GOOGLEKEYouERROR_WRONG_GOOGLEKEY.pageurlincorreto — precisa ser a URL exata onde o widget é carregado. Se o widget estiver dentro de um iframe hospedado em outro domínio, você precisa da URL do iframe, não da URL da página que o envolve. Enviar a URL errada geraERROR_PAGEURLouERROR_BAD_TOKEN_OR_PAGEURL.- Callback que não é executado — algumas páginas usam uma função de callback em JavaScript em vez do campo oculto
g-recaptcha-response. Se você injeta o token só no campo oculto, mas a página espera um callback, o formulário nunca é enviado. Procuredata-callbackno widget ou uma propriedadecallbackdentro degrecaptcha.render(). - Token expirado ou reaproveitado — um token do reCAPTCHA vale para um único uso e expira em cerca de 2 minutos. Se a automação demora demais entre receber o token e enviar o formulário — ou tenta reutilizar o mesmo token em duas submissões — a página de destino rejeita silenciosamente.
Dica: para achar a sitekey certa, inspecione o atributo
data-sitekeyno HTML da página ou o parâmetrokna URL do anchor do widget:
# Look for data-sitekey in the page HTML
# <div class="g-recaptcha" data-sitekey="6Le-wvkSVVABCPBMRTvw0Q4Muexq1bi0DJwx_mJ-"></div>
# Or find it in the anchor URL
# https://www.google.com/recaptcha/api2/anchor?k=6Le-wvkSVVABCPBMRTvw0Q4Muexq1bi0DJwx_mJ-
Checklist rápido: comece por aqui antes de mexer no código
Antes de abrir o editor, resolva a maioria dos chamados de suporte relacionados a reCAPTCHA v2 com esta lista — sem precisar depurar linha por linha:
ERROR_GOOGLEKEYouERROR_WRONG_GOOGLEKEY— a sitekey foi copiada certinho dedata-sitekey?ERROR_PAGEURL— você enviou a URL completa da página, com protocolo e domínio?ERROR_BAD_TOKEN_OR_PAGEURL— o widget está dentro de um iframe? Use a URL do iframe, não a da página pai.CAPCHA_NOT_READYpor mais de 3 minutos — normal em desafios difíceis; aumente o timeout de polling para 180 s.ERROR_CAPTCHA_UNSOLVABLE— envie uma tarefa nova; se persistir, confira sitekey + pageurl.- O token volta, mas a página não faz nada — verifique se existe
data-callbacke chame o callback diretamente. - O token volta, mas o envio do formulário falha — o token pode ter expirado (>2 min); envie mais rápido após recebê-lo.
- Falhas intermitentes, sem padrão claro — adicione retentativa com IDs de tarefa novos a cada tentativa.
Erros no envio da tarefa (endpoint in.php)
Estes erros aparecem quando você envia a tarefa CAPTCHA para https://ocr.captchaai.com/in.php.
| Código de erro | Causa | Correção |
|---|---|---|
ERROR_WRONG_USER_KEY |
O formato da chave de API é inválido (não tem 32 caracteres) | Confira sua chave de API em captchaai.com/api.php |
ERROR_KEY_DOES_NOT_EXIST |
A chave de API não existe no sistema | Verifique se você copiou a chave inteira, sem espaços extras |
ERROR_ZERO_BALANCE |
O saldo da conta está zerado | Recarregue o saldo ou confira a contagem de threads ativas |
ERROR_PAGEURL |
O parâmetro pageurl está faltando |
Adicione a URL completa onde o widget do reCAPTCHA aparece |
ERROR_GOOGLEKEY |
googlekey está malformado ou vazio |
Extraia a sitekey correta direto da página |
ERROR_WRONG_GOOGLEKEY |
O parâmetro googlekey está totalmente ausente |
Adicione googlekey à sua requisição de API |
ERROR_BAD_TOKEN_OR_PAGEURL |
O par googlekey + pageurl é inválido |
Confira se o widget está num iframe; use a URL do iframe |
ERROR_BAD_PARAMETERS |
Parâmetros obrigatórios ausentes ou mal formados | Revise os documentos da API para ver os campos exigidos |
Exemplo de requisição correta, já com tratamento de erro:
import requests
def submit_recaptcha_v2(api_key, sitekey, page_url):
response = requests.get("https://ocr.captchaai.com/in.php", params={
"key": api_key,
"method": "userrecaptcha",
"googlekey": sitekey,
"pageurl": page_url,
"json": 1
})
data = response.json()
if data.get("status") == 1:
return data["request"] # task ID
error = data.get("request", "UNKNOWN_ERROR")
if error == "ERROR_WRONG_USER_KEY":
raise ValueError("API key format is invalid. Must be 32 characters.")
elif error == "ERROR_ZERO_BALANCE":
raise RuntimeError("Account balance is zero. Top up at captchaai.com")
elif error == "ERROR_PAGEURL":
raise ValueError("pageurl parameter is missing from request")
elif error in ("ERROR_GOOGLEKEY", "ERROR_WRONG_GOOGLEKEY"):
raise ValueError(f"Invalid sitekey. Verify the data-sitekey value on the page.")
elif error == "ERROR_BAD_TOKEN_OR_PAGEURL":
raise ValueError("Sitekey/pageurl mismatch. Check if widget is in an iframe.")
else:
raise RuntimeError(f"API error: {error}")
# Usage
task_id = submit_recaptcha_v2("YOUR_API_KEY", "6Le-wvkSAAAAAN...", "https://staging.example.com/qa-login")
print(f"Task submitted: {task_id}")
async function submitRecaptchaV2(apiKey, sitekey, pageUrl) {
const params = new URLSearchParams({
key: apiKey,
method: "userrecaptcha",
googlekey: sitekey,
pageurl: pageUrl,
json: 1,
});
const res = await fetch(`https://ocr.captchaai.com/in.php?${params}`);
const data = await res.json();
if (data.status === 1) return data.request;
const error = data.request || "UNKNOWN_ERROR";
const fixes = {
ERROR_WRONG_USER_KEY: "API key format is invalid. Must be 32 characters.",
ERROR_ZERO_BALANCE: "Account balance is zero. Top up at captchaai.com",
ERROR_PAGEURL: "pageurl parameter is missing from request",
ERROR_GOOGLEKEY: "Invalid sitekey. Check the data-sitekey attribute.",
ERROR_BAD_TOKEN_OR_PAGEURL: "Sitekey/pageurl mismatch. Check iframe context.",
};
throw new Error(fixes[error] || `API error: ${error}`);
}
// Usage
const taskId = await submitRecaptchaV2("YOUR_API_KEY", "6Le-wvkSAAAAAN...", "https://staging.example.com/qa-login");
console.log(`Task submitted: ${taskId}`);
Erros ao consultar o resultado (endpoint res.php)
Estes erros aparecem quando você faz polling em https://ocr.captchaai.com/res.php esperando o resultado.
| Código de erro | Causa | Correção |
|---|---|---|
CAPCHA_NOT_READY |
A resolução ainda está em andamento | Aguarde 5 segundos e consulte de novo. Isso é normal. |
ERROR_CAPTCHA_UNSOLVABLE |
O CAPTCHA não pôde ser resolvido | Envie uma tarefa nova, com parâmetros atualizados |
ERROR_WRONG_ID_FORMAT |
O formato do ID da tarefa é inválido | Confira o ID que veio de in.php |
ERROR_WRONG_CAPTCHA_ID |
O ID da tarefa não existe | Verifique se você salvou o ID correto |
ERROR_EMPTY_ACTION |
O parâmetro action=get está faltando |
Adicione action=get na sua requisição de consulta |
Se os workers da sua automação rodam fora do Brasil, a latência de rede até res.php soma-se ao tempo total de resolução — em pipelines sensíveis a RTT, hospedar os workers numa região como AWS sa-east-1 (São Paulo), próxima do restante da sua stack, costuma cortar alguns segundos do ciclo de polling.
Nota de conformidade: vale registrar o código de erro, o
pageurle o horário nos seus logs de depuração — isso já cobre a maior parte dos casos. Evite manter o token resolvido ou dados pessoais do usuário nesses registros por mais tempo do que o necessário; como o token está associado ao contexto de uma sessão real, trate esses logs conforme os princípios de minimização e retenção da LGPD.Exemplo de polling com tratamento de erro adequado:
import time
import requests
def poll_result(api_key, task_id, timeout=120):
start = time.time()
while time.time() - start < timeout:
time.sleep(5)
response = requests.get("https://ocr.captchaai.com/res.php", params={
"key": api_key,
"action": "get",
"id": task_id,
"json": 1
})
data = response.json()
if data.get("status") == 1:
return data["request"] # solved token
error = data.get("request", "")
if error == "CAPCHA_NOT_READY":
continue # normal — keep waiting
elif error == "ERROR_CAPTCHA_UNSOLVABLE":
raise RuntimeError("CAPTCHA unsolvable. Submit a new task with fresh params.")
elif error in ("ERROR_WRONG_ID_FORMAT", "ERROR_WRONG_CAPTCHA_ID"):
raise ValueError(f"Invalid task ID: {task_id}")
else:
raise RuntimeError(f"Polling error: {error}")
raise TimeoutError(f"Solve timed out after {timeout}s")
# Usage
token = poll_result("YOUR_API_KEY", task_id)
print(f"Token: {token[:50]}...")
async function pollResult(apiKey, taskId, timeout = 120000) {
const start = Date.now();
while (Date.now() - start < timeout) {
await new Promise((r) => setTimeout(r, 5000));
const params = new URLSearchParams({
key: apiKey,
action: "get",
id: taskId,
json: 1,
});
const res = await fetch(`https://ocr.captchaai.com/res.php?${params}`);
const data = await res.json();
if (data.status === 1) return data.request;
if (data.request === "CAPCHA_NOT_READY") continue;
if (data.request === "ERROR_CAPTCHA_UNSOLVABLE")
throw new Error("Unsolvable. Submit a new task.");
throw new Error(`Polling error: ${data.request}`);
}
throw new Error(`Solve timed out after ${timeout / 1000}s`);
}
Quando a página de destino rejeita um token válido
A API devolveu um token válido, mas o site de destino rejeita mesmo assim — o tipo de falha mais difícil de depurar, porque a API acha que deu tudo certo.
Token injetado no campo errado
Algumas páginas procuram o token na textarea g-recaptcha-response. Outras usam grecaptcha.getResponse(). Outras esperam um callback. Se você escolher o método de injeção errado, o envio do formulário falha silenciosamente.
Correção: inspecione a página para descobrir o caminho esperado:
# Method 1: Hidden field injection
driver.execute_script(
'document.getElementById("g-recaptcha-response").innerHTML = arguments[0];',
token
)
# Method 2: Callback execution (check data-callback attribute)
driver.execute_script(f'onCaptchaSuccess("{token}");')
# Method 3: Direct form field + submit
driver.execute_script(
'document.querySelector("[name=g-recaptcha-response]").value = arguments[0];',
token
)
driver.find_element("css selector", "form").submit()
Callback não disparado
Se o widget tiver data-callback="onSuccess" ou usar grecaptcha.render() com uma propriedade callback, preencher só o campo oculto não faz nada. Você precisa chamar a função de callback diretamente.
Correção: localize e chame o callback:
// In browser console or Puppeteer/Playwright
// Check for data-callback
const widget = document.querySelector('.g-recaptcha');
const callbackName = widget?.getAttribute('data-callback');
if (callbackName && window[callbackName]) {
window[callbackName](token);
}
Outros dois motivos comuns de rejeição
- O token expirou — se passam mais de ~2 minutos entre receber o token e enviar o formulário, o Google rejeita. Isso é comum em pipelines de automação mais lentos. Correção: envie o formulário logo após receber o token; se seu pipeline for lento, peça a resolução mais perto do passo de envio, não no início do fluxo.
- O widget está dentro de um iframe — bastante comum em fluxos de checkout, quando o reCAPTCHA carrega a partir de um subdomínio de pagamento diferente do domínio principal (por exemplo,
checkout.loja-exemplo.com.brseparado deloja-exemplo.com.br). Nesse caso, opageurlprecisa ser a URL de origem do iframe, não a da página pai — o erroERROR_BAD_TOKEN_OR_PAGEURLcostuma sinalizar exatamente esse cenário. Correção: inspecione a página, encontre o iframe do reCAPTCHA e use a URLsrcdesse iframe comopageurl.
Perguntas frequentes
Respostas diretas às dúvidas que mais aparecem nos chamados de suporte sobre reCAPTCHA v2.
Depois de quanto tempo devo desistir de uma tarefa em CAPCHA_NOT_READY?
Depois de cerca de 180 segundos (3 minutos) de polling contínuo. Esse teto cobre até os desafios mais difíceis do reCAPTCHA v2; passado esse limite, é mais confiável enviar uma tarefa nova via in.php do que insistir na mesma. Timeouts curtos demais, na faixa de 20-30 s, acabam cancelando tarefas que ainda terminariam com sucesso.
O reCAPTCHA v2 falha mais em checkouts com subdomínio de pagamento?
Sim, é um padrão recorrente. Quando o widget carrega a partir de um subdomínio de pagamento diferente do domínio principal, o pageurl enviado à API precisa ser o do subdomínio real onde o widget aparece — não o da página que o envolve. Esse descasamento está por trás de boa parte dos ERROR_BAD_TOKEN_OR_PAGEURL em fluxos de e-commerce com gateway de terceiros.
Qual erro merece um alerta automático num pipeline de alto volume?
ERROR_ZERO_BALANCE. Num pipeline com várias threads simultâneas, esse erro pode travar a fila inteira de uma vez, não só uma tarefa isolada. Configure um alerta de saldo mínimo e acompanhe a contagem de threads ativas do seu plano — principalmente em planos com muitas threads, como CORPORATE (US$ 240/mês, 150 threads) ou ENTERPRISE (US$ 300/mês, 200 threads), onde uma fila parada custa mais volume perdido por minuto.
Como confirmo se o widget do reCAPTCHA está dentro de um iframe antes de programar a integração?
Abra o DevTools do navegador, vá até a aba Elements e procure por uma tag <iframe> com src apontando para google.com/recaptcha. Se o widget estiver aninhado, o pageurl da sua chamada à API deve ser o valor desse src, não a URL que aparece na barra de endereço.
Como estabilizar seu fluxo de resolução do reCAPTCHA v2
Comece pelas entradas: extraia googlekey de data-sitekey e use a URL exata da página, checando se há iframes no caminho. Em seguida, confirme o método de injeção — a página espera campo oculto, callback, ou os dois?
Depois de resolver a tarefa, envie o formulário na hora: o token vale só 2 minutos, então quanto mais perto do passo de envio você pedir a resolução, melhor. Por fim, adicione tratamento de erro usando os exemplos de código deste guia, para capturar e reagir a cada tipo de falha automaticamente em vez de deixar a automação travar sem explicação.
Comece a resolver reCAPTCHA v2 com o solucionador da CaptchaAI. Pegue sua chave de API em captchaai.com/api.php.
Guias relacionados
- Como resolver reCAPTCHA v2 usando API — tutorial completo, passo a passo
- Como resolver o callback do reCAPTCHA v2 usando API — guia específico para o cenário de callback
- Desafio de grade do reCAPTCHA explicado — como funcionam os desafios em grade
- Referência de códigos de erro da CaptchaAI — lista completa de códigos de erro