Troubleshooting

Resolvendo erros e correções comuns do reCAPTCHA v2

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:

  1. googlekey errado ou ausente — a sitekey vem do atributo data-sitekey no widget do reCAPTCHA ou do parâmetro k na URL do anchor. Se estiver errada, em branco, ou copiada de outra página do mesmo site, a API rejeita a tarefa na hora com ERROR_GOOGLEKEY ou ERROR_WRONG_GOOGLEKEY.
  2. pageurl incorreto — 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 gera ERROR_PAGEURL ou ERROR_BAD_TOKEN_OR_PAGEURL.
  3. 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. Procure data-callback no widget ou uma propriedade callback dentro de grecaptcha.render().
  4. 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-sitekey no HTML da página ou o parâmetro k na 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_GOOGLEKEY ou ERROR_WRONG_GOOGLEKEY — a sitekey foi copiada certinho de data-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_READY por 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-callback e 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 pageurl e 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.br separado de loja-exemplo.com.br). Nesse caso, o pageurl precisa ser a URL de origem do iframe, não a da página pai — o erro ERROR_BAD_TOKEN_OR_PAGEURL costuma sinalizar exatamente esse cenário. Correção: inspecione a página, encontre o iframe do reCAPTCHA e use a URL src desse iframe como pageurl.

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

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