Comparativas

reCAPTCHA v2 vs reCAPTCHA invisible explicado

Ambas son variantes de reCAPTCHA v2 que utilizan la misma tecnología subyacente. La versión casilla de verificación muestra "No soy un robot" y puede presentar cuadrículas de imágenes. La versión invisible se activa automáticamente ante las acciones del usuario (hacer clic en un botón, enviar un formulario o cargar una página) sin ningún widget visible. Para resolver CaptchaAI, la única diferencia es agregar invisible=1 a su solicitud, pero el proceso de inyección de token difiere significativamente.


Comparación lado a lado

Característica Casilla de verificación v2 v2 invisible
widget visible Sí: casilla de verificación "No soy un robot" No, oculto para los usuarios
Mecanismo de disparo El usuario hace clic en la casilla de verificación Hacer clic en un botón, enviar un formulario o cargar una página
Desafío de imagen Se muestra cuando Google sospecha de un bot Ventana emergente en la esquina inferior derecha cuando se sospecha
Experiencia de usuario Fricción moderada Fricción baja/zero
Implementación Agregue el div g-recaptcha a la página Agregue data-callback al botón o grecaptcha.execute()
Formato de clave de sitio Lo mismo que invisible Igual que la casilla de verificación
Campo de token g-recaptcha-response g-recaptcha-response
Función de devolución de llamada Opcional Casi siempre se requiere
Método CaptchaAI method=userrecaptcha method=userrecaptcha + invisible=1
Vida útil del token 120 segundos 120 segundos
resolver el tiempo 10-30 segundos 10-25 segundos

Cómo aparece cada uno en el HTML

Casilla de verificación v2

<!-- Standard checkbox widget -->
<div class="g-recaptcha"
     data-sitekey="6Le-wvkSAAAAAPBMRTvw..."
     data-callback="onSubmit">
</div>

<!-- Widget renders as: -->
<!-- [✓] I'm not a robot     reCAPTCHA logo -->

El usuario ve e interactúa con la casilla de verificación. Si Google sospecha, aparece un desafío de cuadrícula de imágenes en línea.

v2 invisible

<!-- Pattern 1: Invisible widget on a button -->
<button class="g-recaptcha"
        data-sitekey="6Le-wvkSAAAAAPBMRTvw..."
        data-callback="onSubmit"
        data-size="invisible">
  Submit
</button>

<!-- Pattern 2: Invisible div (programmatic trigger) -->
<div class="g-recaptcha"
     data-sitekey="6Le-wvkSAAAAAPBMRTvw..."
     data-size="invisible"
     data-callback="onSubmit">
</div>

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

Ningún widget visible. reCAPTCHA se activa cuando el usuario activa el elemento especificado o cuando se llama a grecaptcha.execute().


Cómo detectar qué variante hay en una página

Detección de Python:

import requests
from bs4 import BeautifulSoup
import re

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

    # Check for invisible indicators
    invisible_widget = soup.find(attrs={"data-size": "invisible", "class": "g-recaptcha"})
    if invisible_widget:
        return {
            "variant": "invisible",
            "sitekey": invisible_widget.get("data-sitekey"),
            "callback": invisible_widget.get("data-callback")
        }

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

    # Check for standard checkbox
    checkbox_widget = soup.find(class_="g-recaptcha")
    if checkbox_widget:
        return {
            "variant": "checkbox",
            "sitekey": checkbox_widget.get("data-sitekey"),
            "callback": checkbox_widget.get("data-callback")
        }

    return None

result = detect_recaptcha_variant("https://staging.example.com/qa-login")
print(result)

Detección de Node.js:

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

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

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

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

  // Check for standard checkbox
  const checkbox = $(".g-recaptcha");
  if (checkbox.length) {
    return {
      variant: "checkbox",
      sitekey: checkbox.attr("data-sitekey"),
      callback: checkbox.attr("data-callback"),
    };
  }

  return null;
}

Comprobación rápida de la consola del navegador:

const el = document.querySelector('[data-size="invisible"]');
console.log(el ? "Invisible reCAPTCHA" : "Checkbox reCAPTCHA");
Señal de detección Casilla de verificación v2 v2 invisible
data-size="invisible" No presente presente
Casilla de verificación visible en la página si No
grecaptcha.execute() llamó No (clics del usuario) Sí (programático)
Posición emergente de desafío En línea, debajo de la casilla de verificación Esquina inferior derecha de la página

Resolviendo con CaptchaAI

Casilla de verificación v2

import requests
import time

resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": "6Le-wvkSAAAA...",
    "pageurl": "https://example.com/form"
})
task_id = resp.text.split("|")[1]

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

v2 invisible

import requests
import time

resp = requests.get("https://ocr.captchaai.com/in.php", params={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": "6Le-wvkSAAAA...",
    "pageurl": "https://example.com/form",
    "invisible": 1  # Only parameter difference
})
task_id = resp.text.split("|")[1]

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

Inyección de tokens: la diferencia crítica

Casilla de verificación v2: el campo oculto suele ser suficiente

# Selenium — inject into hidden field
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").value = "{token}";'
)

# If the page uses a callback, also call it
callback = driver.find_element("css selector", ".g-recaptcha").get_attribute("data-callback")
if callback:
    driver.execute_script(f'{callback}("{token}");')

v2 Invisible: casi siempre se requiere devolución de llamada

# Selenium — inject AND call the callback
driver.execute_script(
    f'document.getElementById("g-recaptcha-response").value = "{token}";'
)

# CRITICAL: Invisible reCAPTCHA almost always requires calling the callback
callback_name = driver.find_element(
    "css selector", ".g-recaptcha[data-size='invisible']"
).get_attribute("data-callback")

driver.execute_script(f'{callback_name}("{token}");')
// Puppeteer — invisible callback injection
await page.evaluate((tok) => {
  // Set the hidden field
  document.getElementById("g-recaptcha-response").value = tok;

  // Find and call the callback function
  const widget = document.querySelector("[data-size='invisible']");
  const cbName = widget?.getAttribute("data-callback");
  if (cbName && typeof window[cbName] === "function") {
    window[cbName](tok);
  }
}, token);

Diferencia clave: Los formularios de casilla de verificación v2 a menudo funcionan solo con la inyección de campo oculto porque el clic del usuario en la casilla de verificación ya registró la devolución de llamada. El reCAPTCHA invisible nunca tiene ese clic: la devolución de llamada debe llamarse explícitamente.


Solucionador universal para ambas variantes.

import requests
import time
from bs4 import BeautifulSoup

class RecaptchaV2UniversalSolver:
    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")

        # Detect variant
        invisible = soup.find(attrs={"data-size": "invisible", "class": "g-recaptcha"})
        widget = invisible or soup.find(class_="g-recaptcha")

        if not widget:
            raise Exception("No reCAPTCHA widget found")

        sitekey = widget.get("data-sitekey")
        is_invisible = invisible is not None
        callback = widget.get("data-callback")

        params = {
            "key": self.api_key,
            "method": "userrecaptcha",
            "googlekey": sitekey,
            "pageurl": page_url
        }
        if is_invisible:
            params["invisible"] = 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],
                    "variant": "invisible" if is_invisible else "checkbox",
                    "callback": callback,
                    "sitekey": sitekey
                }
            if result.text != "CAPCHA_NOT_READY":
                raise Exception(f"Solve error: {result.text}")

        raise Exception("Timed out")

# Usage
solver = RecaptchaV2UniversalSolver("YOUR_API_KEY")
result = solver.detect_and_solve("https://staging.example.com/qa-login")
print(f"Variant: {result['variant']}, Callback: {result['callback']}")

Solución de problemas

problema Corrección de casilla de verificación Solución invisible
Token no aceptado Inyectar en el campo g-recaptcha-response Inyectar Y llamar a la función data-callback
No se encontró el widget Busque la clase .g-recaptcha Verifique data-size="invisible" o llamadas de procesamiento de scripts
El formulario se envía pero falla Compruebe si se espera una devolución de llamada Casi siempre es necesario devolver la llamada: búsquela y llámela
La página se recarga después de la inyección. La validación de JavaScript falló Llamada de devolución de llamada antes de los activadores de envío automático del formulario

Preguntas frecuentes

¿Es el reCAPTCHA invisible más difícil de resolver?

No. El proceso de resolución a través de CaptchaAI es casi idéntico. Agregar invisible=1 a su solicitud es el único cambio. El desafío adicional está en el lado de la inyección: debes encontrar y ejecutar la función de devolución de llamada.

¿Ambos usan el mismo formato de clave de sitio?

Sí. El formato de la clave del sitio es idéntico. No se puede distinguir la variante únicamente a partir de la clave del sitio; busque data-size="invisible" en el HTML.

¿El reCAPTCHA invisible todavía muestra desafíos de imagen?

Sí. Cuando Google detecta un comportamiento sospechoso, reCAPTCHA invisible muestra una ventana emergente de desafío de imagen en la esquina inferior derecha de la página. Por eso todavía necesitas CaptchaAI: la versión invisible aún puede presentar desafíos.

¿Puede un sitio cambiar entre casilla de verificación e invisible?

Sí. Este es un cambio de configuración al final del sitio: misma clave de sitio, implementación diferente. Algunos sitios usan casillas de verificación en computadoras de escritorio y son invisibles en dispositivos móviles. Detecta siempre la variante de forma dinámica.

¿Cuál es más rápido de resolver?

Las soluciones invisibles suelen ser un poco más rápidas (de 10 a 25 segundos frente a 10 a 30 segundos) porque tienden a generar menos desafíos de imagen. Pero la diferencia es marginal.


Guías relacionadas

Los comentarios están deshabilitados para este artículo.