Comparisons

reCAPTCHA v2 padrão vs Enterprise: o que muda na resolução

Quem escolhe entre reCAPTCHA v2 padrão e Enterprise é o site, não a sua integração. Do seu lado a diferença cabe em um parâmetro — enterprise=1 — e quase toda falha vem de detectar a versão errada, não de resolver o desafio.

  • Na página: a padrão carrega api.js; a Enterprise, enterprise.js.
  • Na API: mesmo method=userrecaptcha, mesma sitekey (chave pública do widget), mesmo g-recaptcha-response.
  • No desafio: idêntico — caixa "Não sou um robô" e grades 3×3 ou 4×4.
  • No custo: nada muda; a cobrança é por thread simultânea (BASIC, US$ 15/mês, 5 threads).

Como saber se a página usa reCAPTCHA v2 ou Enterprise

A checagem decisiva leva dois segundos: veja qual arquivo do Google entra no HTML.

<!-- Standard v2 -->
<script src="https://www.google.com/recaptcha/api.js"></script>

<!-- Enterprise v2 -->
<script src="https://www.google.com/recaptcha/enterprise.js"></script>

Em varreduras de QA, automatize a checagem — versão e sitekey na mesma passada:

import requests
from bs4 import BeautifulSoup

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

    enterprise_script = soup.find("script", src=lambda s: s and "enterprise.js" in s)
    standard_script = soup.find("script", src=lambda s: s and "recaptcha/api.js" in s)

    widget = soup.find(class_="g-recaptcha")
    sitekey = widget["data-sitekey"] if widget else None

    if enterprise_script:
        return {"version": "enterprise_v2", "sitekey": sitekey}
    elif standard_script:
        return {"version": "standard_v2", "sitekey": sitekey}
    return None

info = detect_recaptcha_version("https://staging.example.com/qa-login")
print(info)

A mesma checagem em Node.js, com axios e cheerio:

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

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

  const hasEnterprise = $('script[src*="enterprise.js"]').length > 0;
  const hasStandard = $('script[src*="recaptcha/api.js"]').length > 0;
  const sitekey = $(".g-recaptcha").attr("data-sitekey");

  if (hasEnterprise) return { version: "enterprise_v2", sitekey };
  if (hasStandard) return { version: "standard_v2", sitekey };
  return null;
}

No DevTools, para conferir uma página à mão:

// Quick check in DevTools
if (document.querySelector('script[src*="enterprise.js"]')) {
  console.log("Enterprise v2");
} else if (document.querySelector('script[src*="recaptcha/api.js"]')) {
  console.log("Standard v2");
}

O que o Enterprise muda no back-end do site

Enterprise não é um desafio mais difícil: é outro modelo de administração do site — projeto no Google Cloud, regras por ação, códigos de motivo e verificação em endpoint pago. Só duas linhas desta tabela exigem ação de quem resolve.

Sinal v2 padrão v2 Enterprise
Arquivo JS carregado api.js enterprise.js
Função de execução grecaptcha.execute() grecaptcha.enterprise.execute()
Verificação no site siteverify (gratuita) recaptchaenterprise.googleapis.com (paga)
Códigos de motivo Não Sim (AUTOMATION, TOO_MUCH_TRAFFIC)
Regras personalizadas Não Sim (limites por ação)
Parâmetro na CaptchaAI enterprise=1
Tempo de resolução (SLA) < 60 s < 60 s

Erros de detecção que derrubam a integração

Erro O que acontece Correção
enterprise=1 em site padrão Token pode voltar inválido Confirme enterprise.js antes
Sem enterprise=1 em site Enterprise O site recusa o token Envie sempre que houver enterprise.js
Sitekey errada ERROR_WRONG_GOOGLEKEY Leia data-sitekey no elemento .g-recaptcha
Confundir v2 com v3 Enterprise Parâmetros errados O v2 é visível; o v3 devolve score

Se o token for recusado, confira nesta ordem:

  1. o arquivo JS carregado nesta execução;
  2. a sitekey enviada versus a do HTML atual;
  3. a pageurl exata do widget.

Resolvendo os dois casos com a CaptchaAI

O fluxo é o mesmo: envie a tarefa ao in.php, consulte o resultado no res.php e escreva o token no formulário. Os exemplos usam staging.example.com (QA autorizado).

Versão padrão

Sem parâmetro extra; consulta a cada 5 s:

import requests
import time

# Submit task
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": page_url
})
task_id = resp.text.split("|")[1]

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

Versão Enterprise

Uma linha a mais no envio; o polling não muda:

import requests
import time

# Submit task — only difference is enterprise=1
resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": page_url,
    "enterprise": 1  # Required for Enterprise
})
task_id = resp.text.split("|")[1]

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

Detecção e resolução no mesmo componente

Em bases de código que atendem vários sites, deixe a decisão com o programa: a classe abaixo lê o HTML, escolhe a versão e devolve o token com o que detectou.

import requests
import time
from bs4 import BeautifulSoup

class RecaptchaV2Solver:
    def __init__(self, api_key):
        self.api_key = api_key

    def detect_and_solve(self, page_url, page_html=None):
        if not page_html:
            page_html = requests.get(page_url).text

        soup = BeautifulSoup(page_html, "html.parser")
        is_enterprise = bool(soup.find("script", src=lambda s: s and "enterprise.js" in s))
        widget = soup.find(class_="g-recaptcha")
        sitekey = widget["data-sitekey"] if widget else None

        if not sitekey:
            raise Exception("No reCAPTCHA sitekey found on page")

        params = {
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": page_url
        }
        if is_enterprise:
            params["enterprise"] = 1

        resp = requests.get("https://ocr.captchaai.com/in.php", params=params)
        if not resp.text.startswith("OK|"):
            raise Exception(f"Submit failed: {resp.text}")

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

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

        raise Exception("Solve timed out")


solver = RecaptchaV2Solver("YOUR_API_KEY")
result = solver.detect_and_solve("https://staging.example.com/qa-login")
print(f"Enterprise: {result['is_enterprise']}, Token: {result['token'][:40]}...")

Envio do token ao endpoint de verificação

Depois do token, os caminhos convergem: escreva o valor em g-recaptcha-response e chame o callback do widget, quando houver.

# Selenium injection — works for both standard and enterprise
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").value = "{token}";'
)

# If the page uses a callback function
callback = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-callback")
if callback:
    driver.execute_script(f'{callback}("{token}");')
// Puppeteer injection — works for both
await page.evaluate((token) => {
  document.getElementById("g-recaptcha-response").value = token;
  // Find and call callback if present
  const widget = document.querySelector(".g-recaptcha");
  const cb = widget?.getAttribute("data-callback");
  if (cb && typeof window[cb] === "function") {
    window[cb](token);
  }
}, token);

Cenário: a suíte que quebrou sem mudança de código

Um time em São Paulo mantém um portal de atendimento com formulários de três fornecedores; a suíte roda contra staging, com workers em sa-east-1. De um sprint para o outro, um formulário passou a recusar o token sem mudança no código: o fornecedor havia migrado o widget para enterprise.js.

A correção não foi ajustar uma constante, e sim rodar o detector em todas as URLs da suíte a cada execução, registrando a versão no resultado. Com dados fictícios nos formulários, a auditoria continua simples do ponto de vista da LGPD.


Perguntas frequentes

E se o site trocar api.js por enterprise.js?

É a causa mais comum de token recusado "do nada". Mantenha a detecção no código: leia o HTML a cada execução e derive o parâmetro dali.

reCAPTCHA v2 Enterprise é o mesmo que v3 Enterprise?

Não. O v2 mantém a interação visível; o v3 é invisível e devolve um score. A CaptchaAI resolve os dois, com envios diferentes.

Preciso de conta no Google Cloud?

Não. O projeto e a chave de verificação pertencem ao site. Do seu lado ficam a sitekey pública, a pageurl e a sua chave de API.

E se o site migrar para hCaptcha?

Nesse caso, este caminho não serve: o hCaptcha não é suportado pela CaptchaAI. A cobertura inclui:

  • reCAPTCHA v2 e v3, inclusive Enterprise;
  • Cloudflare Turnstile e Challenge;
  • GeeTest v3, imagem/OCR e grade de imagens.

Guias relacionados

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