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
- Cómo resolver reCAPTCHA v2 usando API- tutorial completo de casilla de verificación v2
- Cómo funciona reCAPTCHA Invisible- mecanismo invisible explicado
- Cómo resolver reCAPTCHA Invisible usando API— tutorial de resolución invisible
- Errores y soluciones comunes de reCAPTCHA Invisible— solución de problemas invisible
- Cómo resolver reCAPTCHA Invisible usando API
- Cómo funciona reCAPTCHA Invisible
- reCAPTCHA v2 vs v3 explicado