Solução de Problemas

Erros e correções invisíveis comuns do reCAPTCHA

O reCAPTCHA invisível remove a caixa de seleção, mas adiciona novos modos de falha para automação. Os maiores problemas são não detectar o widget invisível, perder a função de retorno de chamada, enviar tokens expirados e usar parâmetros padrão v2 quando parâmetros invisíveis são necessários.

Este guia cobre todos os padrões de erros comuns com a correção exata. Se você precisar de informações sobre como funciona o reCAPTCHA invisível, leiaComo funciona o reCAPTCHA Invisible e como resolvê-loprimeiro.


Referência rápida de erros

Erro Causa Correção
ERROR_WRONG_GOOGLEKEY Sitekey incorreto ou sitekey de um domínio diferente Extraia a chave do site da div do widget invisível ou da chamada grecaptcha.render()
ERROR_PAGEURL Incompatibilidade de URL – URL da página pai enviado em vez do URL do iframe Use o URL exato onde o widget invisível é carregado
ERROR_CAPTCHA_UNSOLVABLE O Google sinalizou a tarefa como impossível Tente novamente com proxy e cookies novos; verifique se o site mudou para v3
ERROR_BAD_TOKEN_OR_PAGEURL Token rejeitado pelo site de destino Verifique se o pageurl corresponde exatamente; injetar via retorno de chamada, não campo oculto
CAPCHA_NOT_READY Tarefa ainda em processamento Continue pesquisando a cada 5 segundos; soluções invisíveis levam de 10 a 30 segundos
ERROR_KEY_DOES_NOT_EXIST Chave de API CaptchaAI inválida Verifique a chave emcaptchaai.com/account
Token aceito, mas formulário falha Retorno de chamada não executado após envio controlado ao endpoint QA Encontre e chame a função data-callback com o token

Erro 1: não detectando reCAPTCHA invisível na página

O reCAPTCHA invisível não tem nenhuma caixa de seleção visível. Se o seu raspador não detectá-lo, as solicitações protegidas por captcha falharão silenciosamente com erros ou redirecionamentos de envio de formulário.

Como detectar reCAPTCHA invisível

Procure estes padrões na página HTML:

<!-- Pattern 1: div with data-size="invisible" -->
<div class="g-recaptcha" data-sitekey="6LdKlZEU..."
     data-size="invisible"
     data-callback="onSubmit"></div>

<!-- Pattern 2: button with data-sitekey and invisible size -->
<button class="g-recaptcha"
        data-sitekey="6LdKlZEU..."
        data-callback="onSubmit"
        data-action="submit">Submit</button>

<!-- Pattern 3: programmatic render with size: invisible -->
<script>
  grecaptcha.render('submit-btn', {
    sitekey: '6LdKlZEU...',
    callback: onSubmit,
    size: 'invisible'
  });
</script>

Script de detecção (Python):

import requests
from bs4 import BeautifulSoup
import re

def detect_invisible_recaptcha(url):
    resp = requests.get(url)
    soup = BeautifulSoup(resp.text, "html.parser")

    # Check for data-size="invisible"
    widget = soup.find("div", {"data-size": "invisible", "class": "g-recaptcha"})
    if widget:
        return {
            "type": "invisible",
            "sitekey": widget.get("data-sitekey"),
            "callback": widget.get("data-callback")
        }

    # Check for programmatic render with invisible
    scripts = soup.find_all("script")
    for script in scripts:
        if script.string and "size" in str(script.string) and "invisible" in str(script.string):
            key_match = re.search(r"sitekey['\"]?\s*[:=]\s*['\"]([^'\"]+)", script.string)
            if key_match:
                return {
                    "type": "invisible-programmatic",
                    "sitekey": key_match.group(1),
                    "callback": "check grecaptcha.render() call"
                }

    return None

Script de detecção (Node.js):

const axios = require("axios");
const cheerio = require("cheerio");

async function detectInvisibleRecaptcha(url) {
  const { data } = await axios.get(url);
  const $ = cheerio.load(data);

  // Check for data-size="invisible"
  const widget = $(".g-recaptcha[data-size='invisible']");
  if (widget.length) {
    return {
      type: "invisible",
      sitekey: widget.attr("data-sitekey"),
      callback: widget.attr("data-callback"),
    };
  }

  // Check script tags for programmatic invisible render
  const scriptContent = $("script")
    .map((_, el) => $(el).html())
    .get()
    .join("\n");
  if (scriptContent.includes("invisible")) {
    const keyMatch = scriptContent.match(/sitekey['"]?\s*[:=]\s*['"]([^'"]+)/);
    if (keyMatch) {
      return {
        type: "invisible-programmatic",
        sitekey: keyMatch[1],
        callback: "check grecaptcha.render() call",
      };
    }
  }

  return null;
}

Erro 2: chave de site errada – ERROR_WRONG_GOOGLEKEY

Isso acontece quando você envia uma chave de site que não corresponde ao widget reCAPTCHA invisível na página de destino. Causas comuns:

  • Copiou a chave do site de uma caixa de seleção v2 em uma página diferente
  • Usou uma chave de site do URL âncora de uma versão diferente do reCAPTCHA
  • A página tem vários widgets reCAPTCHA e você pegou o errado

Correção: extraia a chave do site invisível correta

import requests
from bs4 import BeautifulSoup

def get_invisible_sitekey(url):
    resp = requests.get(url)
    soup = BeautifulSoup(resp.text, "html.parser")

    # Priority 1: invisible widget
    widget = soup.find(attrs={"data-size": "invisible", "class": "g-recaptcha"})
    if widget:
        return widget["data-sitekey"]

    # Priority 2: any g-recaptcha div (may be invisible without data-size)
    widget = soup.find(class_="g-recaptcha")
    if widget and widget.get("data-sitekey"):
        return widget["data-sitekey"]

    return None

sitekey = get_invisible_sitekey("https://staging.example.com/qa-login")
print(f"Sitekey: {sitekey}")

Erro 3: Retorno de chamada não executado – o formulário é enviado, mas nada acontece

Esta é a falha invisível número um do reCAPTCHA que os desenvolvedores não percebem. Ao contrário da caixa de seleção v2, onde injetar o token em g-recaptcha-response é suficiente, o reCAPTCHA invisível quase sempre usa uma função de retorno de chamada JavaScript. Se você injetar o token, mas não chamar o retorno de chamada, o formulário nunca será processado.

Como funciona o fluxo de retorno de chamada

  1. grecaptcha.execute() dispara o desafio invisível
  2. Após resolver, o Google chama a função especificada em data-callback
  3. Essa função de retorno de chamada envia o formulário ou faz a chamada da API

Correção: encontre e execute o retorno de chamada

Etapa 1 — Identifique o nome do retorno de chamada:

# From HTML: data-callback="onSubmit"
# From JS: callback: onSubmit
# From grecaptcha.render: second argument with callback property

Etapa 2 — Injetar token E chamar o retorno de chamada (Selenium):

from selenium import webdriver
import requests
import time

driver = webdriver.Chrome()
driver.get("https://example.com/form")

# Get sitekey
sitekey = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-sitekey")
callback_name = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-callback")

# Solve with CaptchaAI
task_id = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": driver.current_url,
    "invisible": 1
}).text.split("|")[1]

# Poll for result
token = None
for _ in range(60):
    time.sleep(5)
    resp = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY",
        "action": "get",
        "id": task_id
    }).text
    if resp.startswith("OK|"):
        token = resp.split("|")[1]
        break

# Inject token into the response field
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").value = "{token}";'
)

# CRITICAL: Call the callback function
driver.execute_script(f'{callback_name}("{token}");')

Etapa 2 — Injetar token E chamar o retorno de chamada (Puppeteer):

const puppeteer = require("puppeteer");
const axios = require("axios");

(async () => {
  const browser = await puppeteer.launch({ headless: "new" });
  const page = await browser.newPage();
  await page.goto("https://example.com/form");

  // Get sitekey and callback
  const { sitekey, callback } = await page.evaluate(() => {
    const el = document.querySelector(".g-recaptcha[data-size='invisible']");
    return {
      sitekey: el?.getAttribute("data-sitekey"),
      callback: el?.getAttribute("data-callback"),
    };
  });

  // Submit to CaptchaAI
  const submitResp = await axios.get("https://ocr.captchaai.com/in.php", {
    params: {
      key: "YOUR_API_KEY",
      method: "userrecaptcha",
      googlekey: sitekey,
      pageurl: page.url(),
      invisible: 1,
    },
  });
  const taskId = submitResp.data.split("|")[1];

  // Poll for result
  let token;
  for (let i = 0; i < 60; i++) {
    await new Promise((r) => setTimeout(r, 5000));
    const result = await axios.get("https://ocr.captchaai.com/res.php", {
      params: { key: "YOUR_API_KEY", action: "get", id: taskId },
    });
    if (result.data.startsWith("OK|")) {
      token = result.data.split("|")[1];
      break;
    }
  }

  // Inject token and fire callback
  await page.evaluate(
    (tok, cb) => {
      document.getElementById("g-recaptcha-response").value = tok;
      if (cb && typeof window[cb] === "function") {
        window[cb](tok);
      }
    },
    token,
    callback,
  );

  await browser.close();
})();

Erro 4: Parâmetro invisible=1 ausente

Ao resolver o reCAPTCHA invisível por meio de CaptchaAI, você deve incluir invisible=1 em sua solicitação. Sem ele, o solucionador trata a tarefa como um desafio de caixa de seleção v2 padrão, que pode levar a ERROR_CAPTCHA_UNSOLVABLE ou tokens que o site de destino rejeita.

Solicitação errada versus correta

# WRONG — missing invisible=1
params = {
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": page_url
}

# CORRECT — includes invisible=1
params = {
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": page_url,
    "invisible": 1  # Required for invisible reCAPTCHA
}

response = requests.get("https://ocr.captchaai.com/in.php", params=params)

Erro 5: o token expirou antes do envio

Os tokens reCAPTCHA invisíveis expiram em 120 segundos — o mesmo que o padrão v2. Mas os fluxos de trabalho invisíveis geralmente têm etapas de processamento adicionais entre a resolução e o envio, tornando a expiração mais provável.

Sintomas

  • Formulário retorna erro genérico após envio controlado ao endpoint QA
  • siteverify do lado do servidor retorna timeout-or-duplicate
  • O token era válido, mas demorou muito para chegar à etapa de envio

Correção: solução just-in-time

Solicite a resolução apenas quando estiver pronto para enviar imediatamente:

import requests
import time

def solve_invisible_recaptcha(api_key, sitekey, page_url):
    # Submit task
    resp = requests.get("https://ocr.captchaai.com/in.php", params={
        "key": api_key,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": page_url,
        "invisible": 1
    })
    if not resp.text.startswith("OK|"):
        raise Exception(f"Submit failed: {resp.text}")
    task_id = resp.text.split("|")[1]

    # Poll for result
    for _ in range(60):
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key,
            "action": "get",
            "id": task_id
        })
        if result.text.startswith("OK|"):
            return result.text.split("|")[1]
        if result.text != "CAPCHA_NOT_READY":
            raise Exception(f"Solve failed: {result.text}")

    raise Exception("Solve timed out after 5 minutes")

# Usage: solve JUST before you need to submit
# 1. Navigate to page and prepare form data first
# 2. THEN solve the captcha
# 3. Inject token and submit immediately
token = solve_invisible_recaptcha("YOUR_API_KEY", sitekey, page_url)
# Submit within 120 seconds of receiving the token

Erro 6: Token rejeitado — ERROR_BAD_TOKEN_OR_PAGEURL

O site de destino verificou o token com o Google e falhou. Causas comuns:

Causa Como identificar Correção
pageurl errado URL não corresponde ao domínio no registro do sitekey Use o URL exato onde o widget é carregado
Token usado em domínio diferente Reutilização de token entre domínios Resolva com o pageurl do domínio correto
Token já usado Enviando o mesmo token duas vezes Solicite uma nova solução para cada envio
Incompatibilidade de IP Seu IP difere do IP do solucionador Adicione seu parâmetro proxy para corresponder ao IP da sessão
Bandeira invisível faltando Resolvido como padrão v2, usado em página invisível Adicione invisible=1 à solicitação de resolução

Lista de verificação de depuração

def debug_invisible_solve(api_key, sitekey, page_url, proxy=None):
    """Run a diagnostic solve with detailed logging."""
    print(f"Sitekey: {sitekey}")
    print(f"Page URL: {page_url}")
    print(f"Proxy: {proxy or 'none'}")

    params = {
        "key": api_key,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": page_url,
        "invisible": 1
    }
    if proxy:
        params["proxy"] = proxy
        params["proxytype"] = "HTTP"

    # Submit
    resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
    print(f"Submit response: {resp.text}")
    if not resp.text.startswith("OK|"):
        return None

    task_id = resp.text.split("|")[1]
    print(f"Task ID: {task_id}")

    # Poll with timing
    start = time.time()
    for _ in range(60):
        time.sleep(5)
        result = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key, "action": "get", "id": task_id
        })
        elapsed = time.time() - start
        print(f"  [{elapsed:.0f}s] {result.text[:50]}")
        if result.text.startswith("OK|"):
            token = result.text.split("|")[1]
            print(f"Token received after {elapsed:.0f}s")
            print(f"Token length: {len(token)} characters")
            print(f"Token starts with: {token[:30]}...")
            return token
        if result.text != "CAPCHA_NOT_READY":
            print(f"FAILED: {result.text}")
            return None

    print("TIMEOUT after 5 minutes")
    return None

Erro 7: vários widgets reCAPTCHA em uma página

Algumas páginas têm uma caixa de seleção v2 visível E um reCAPTCHA invisível. Se você resolver o problema errado, o token será válido, mas não corresponderá ao widget que protege a ação necessária.

Correção: direcione o widget correto

from bs4 import BeautifulSoup

def find_all_recaptcha_widgets(html):
    soup = BeautifulSoup(html, "html.parser")
    widgets = []

    for el in soup.find_all(class_="g-recaptcha"):
        widgets.append({
            "sitekey": el.get("data-sitekey"),
            "size": el.get("data-size", "normal"),
            "callback": el.get("data-callback"),
            "tag": el.name,
            "id": el.get("id")
        })

    return widgets

# Example output:
# [
#   {"sitekey": "6LdA...", "size": "normal", "callback": None, "tag": "div", "id": "recaptcha-login"},
#   {"sitekey": "6LdB...", "size": "invisible", "callback": "onRegister", "tag": "div", "id": "recaptcha-register"}
# ]
# Use the widget with size="invisible" for the invisible solve

Solucionador reCAPTCHA invisível completo com tratamento de erros

Este wrapper pronto para produção lida com todos os erros acima:

import requests
import time
import logging

logger = logging.getLogger(__name__)

class InvisibleRecaptchaSolver:
    def __init__(self, api_key, max_retries=3):
        self.api_key = api_key
        self.max_retries = max_retries
        self.base_url = "https://ocr.captchaai.com"

    def solve(self, sitekey, page_url, proxy=None):
        """Solve invisible reCAPTCHA with automatic retry on transient errors."""
        for attempt in range(1, self.max_retries + 1):
            try:
                token = self._attempt_solve(sitekey, page_url, proxy)
                if token:
                    return token
            except Exception as e:
                logger.warning(f"Attempt {attempt} failed: {e}")
                if attempt < self.max_retries:
                    time.sleep(2 ** attempt)
        raise Exception(f"Failed to solve after {self.max_retries} attempts")

    def _attempt_solve(self, sitekey, page_url, proxy):
        params = {
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": page_url,
            "invisible": 1
        }
        if proxy:
            params["proxy"] = proxy
            params["proxytype"] = "HTTP"

        # Submit task
        resp = requests.get(f"{self.base_url}/in.php", params=params)

        if "ERROR" in resp.text:
            error = resp.text.strip()
            if error in ("ERROR_WRONG_GOOGLEKEY", "ERROR_KEY_DOES_NOT_EXIST"):
                raise Exception(f"Configuration error (do not retry): {error}")
            if error == "ERROR_ZERO_BALANCE":
                raise Exception("Account balance is zero — add funds")
            raise Exception(f"Submit error: {error}")

        if not resp.text.startswith("OK|"):
            raise Exception(f"Unexpected submit response: {resp.text}")

        task_id = resp.text.split("|")[1]

        # Poll for result
        for _ in range(60):
            time.sleep(5)
            result = requests.get(f"{self.base_url}/res.php", params={
                "key": self.api_key,
                "action": "get",
                "id": task_id
            })

            if result.text.startswith("OK|"):
                return result.text.split("|")[1]

            if result.text == "CAPCHA_NOT_READY":
                continue

            if result.text == "ERROR_CAPTCHA_UNSOLVABLE":
                logger.warning("Captcha unsolvable — will retry with new task")
                return None

            raise Exception(f"Poll error: {result.text}")

        raise Exception("Solve timed out after 5 minutes")


# Usage
solver = InvisibleRecaptchaSolver("YOUR_API_KEY")
token = solver.solve(
    sitekey="6LdKlZEU...",
    page_url="https://staging.example.com/qa-login"
)
print(f"Token: {token[:50]}...")
const axios = require("axios");

class InvisibleRecaptchaSolver {
  constructor(apiKey, maxRetries = 3) {
    this.apiKey = apiKey;
    this.maxRetries = maxRetries;
    this.baseUrl = "https://ocr.captchaai.com";
  }

  async solve(sitekey, pageUrl, proxy) {
    for (let attempt = 1; attempt <= this.maxRetries; attempt++) {
      try {
        const token = await this._attemptSolve(sitekey, pageUrl, proxy);
        if (token) return token;
      } catch (err) {
        console.warn(`Attempt ${attempt} failed: ${err.message}`);
        if (attempt < this.maxRetries) {
          await new Promise((r) => setTimeout(r, 2 ** attempt * 1000));
        }
      }
    }
    throw new Error(`Failed to solve after ${this.maxRetries} attempts`);
  }

  async _attemptSolve(sitekey, pageUrl, proxy) {
    const params = {
      key: this.apiKey,
      method: "userrecaptcha",
      googlekey: sitekey,
      pageurl: pageUrl,
      invisible: 1,
    };
    if (proxy) {
      params.proxy = proxy;
      params.proxytype = "HTTP";
    }

    // Submit task
    const submitResp = await axios.get(`${this.baseUrl}/in.php`, { params });
    if (submitResp.data.includes("ERROR")) {
      const error = submitResp.data.trim();
      if (["ERROR_WRONG_GOOGLEKEY", "ERROR_KEY_DOES_NOT_EXIST"].includes(error)) {
        throw new Error(`Configuration error (do not retry): ${error}`);
      }
      throw new Error(`Submit error: ${error}`);
    }

    const taskId = submitResp.data.split("|")[1];

    // Poll for result
    for (let i = 0; i < 60; i++) {
      await new Promise((r) => setTimeout(r, 5000));
      const result = await axios.get(`${this.baseUrl}/res.php`, {
        params: { key: this.apiKey, action: "get", id: taskId },
      });

      if (result.data.startsWith("OK|")) {
        return result.data.split("|")[1];
      }
      if (result.data === "CAPCHA_NOT_READY") continue;
      if (result.data === "ERROR_CAPTCHA_UNSOLVABLE") return null;
      throw new Error(`Poll error: ${result.data}`);
    }
    throw new Error("Solve timed out after 5 minutes");
  }
}

// Usage
const solver = new InvisibleRecaptchaSolver("YOUR_API_KEY");
solver.solve("6LdKlZEU...", "https://staging.example.com/qa-login").then((token) => {
  console.log(`Token: ${token.substring(0, 50)}...`);
});

Lista de verificação de solução de problemas

Execute esta lista de verificação quando a solução do reCAPTCHA invisível falhar:

Passo Verifique Comando/Action
1 Confirme que é invisível, não o padrão v2 Procure data-size="invisible" ou size: 'invisible' na chamada de renderização
2 Verifique se a chave do site está correta Compare com data-sitekey especificamente no widget invisível
3 Confirme invisible=1 na solicitação de API Verifique seus parâmetros in.php
4 Verifique se pageurl corresponde exatamente Use o URL do DevTools do navegador, não um URL de redirecionamento
5 Encontre o nome da função de retorno de chamada Procure o atributo data-callback ou callback em grecaptcha.render()
6 Verifique a envio controlado ao endpoint QA + chamada de retorno Ambas as etapas são necessárias – o token por si só não é suficiente
7 Verifique a atualização do token O token deve ser usado dentro de 120 segundos
8 Teste com proxy se o IP for importante Adicione os parâmetros proxy e proxytype

Perguntas frequentes

Qual a diferença entre o reCAPTCHA invisível e o padrão v2 para resolução?

O método API é o mesmo (method=userrecaptcha), mas você deve adicionar invisible=1 à sua solicitação. A diferença crítica está no lado da injeção: o reCAPTCHA invisível quase sempre requer a chamada de uma função de retorno de chamada JavaScript após a injeção do token, enquanto o padrão v2 geralmente funciona apenas com o campo oculto.

Por que meu token funciona nos testes, mas falha na produção?

Provavelmente uma incompatibilidade de IP. Nos testes, o solucionador e seu navegador podem compartilhar IPs semelhantes. Na produção, o IP do solucionador e o IP do seu servidor são diferentes. Adicione um parâmetro de proxy que corresponda ao IP da sua sessão para corrigir isso.

Quanto tempo leva para resolver o reCAPTCHA invisível?

Os tempos de resolução típicos são de 10 a 30 segundos até CaptchaAI. Os desafios invisíveis são geralmente com menor latência do que os desafios de caixa de seleção v2 porque não exigem reconhecimento de imagem – eles dependem de análise de risco.

Posso resolver o reCAPTCHA invisível sem um navegador?

Sim. Como a solução acontece no lado do servidor por meio da API, você só precisa do sitekey e do pageurl. O navegador só será necessário se você precisar executar a função de retorno de chamada na página real. Para fluxos de trabalho de API puros, extraia a chave do site, resolva via CaptchaAI e envie o token com sua solicitação HTTP.


Próximas etapas

  • Como funciona o reCAPTCHA Invisible e como resolvê-lo- antecedentes do mecanismo invisível
  • Como resolver reCAPTCHA v2 usando API— solução padrão v2 para comparação
  • reCAPTCHA v2 comum resolvendo erros e correções— padrões de erro padrão v2
  • Códigos de erro CaptchaAI: referência completa— tabela completa de códigos de erro

Artigos relacionados

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