Antes de que CaptchaAI pueda resolver un reCAPTCHA necesitas dos datos que viven en el propio código de la página: el sitekey y la URL. Encontrarlos suele ser cuestión de segundos con una expresión regular sobre el HTML servido.
El problema empieza con las variantes. reCAPTCHA v3, los widgets invisibles y las claves Enterprise esconden parámetros extra en sitios distintos del marcado, así que conviene tener claro qué buscas:
- sitekey y
pageurl— obligatorios en todas las versiones. action— solo en v3 (y a veces en Enterprise), dentro del JavaScript que dispara la verificación.data-sy la banderaenterprise— casos especiales de los sitios de Google y de las claves corporativas.
Esta guía recorre cada método de extracción, del atributo más simple a las páginas que montan el widget con JavaScript.
Qué parámetros necesita cada versión de reCAPTCHA
| Parámetro | Estándar v2 | v2 invisible | v3 | Empresa |
|---|---|---|---|---|
googlekey (clave del sitio) |
Requerido | Requerido | Requerido | Requerido |
pageurl |
Requerido | Requerido | Requerido | Requerido |
invisible |
- | 1 |
- | - |
action |
- | - | Requerido | A veces |
data-s |
A veces | A veces | - | - |
enterprise |
- | - | - | 1 |
En la práctica esto aparece a diario. Imagina que automatizas las pruebas de un portal de cita previa o del formulario de un centro de visados BLS, ambos protegidos con reCAPTCHA: antes de validar el flujo de extremo a extremo necesitas el sitekey exacto de ese formulario. Extraerlo del código fuente es siempre el primer paso.
Cómo saber qué versión de reCAPTCHA tienes delante
Identificar la versión antes de extraer nada te ahorra tiempo, porque cambia qué parámetros necesitas y dónde viven:
- v2 estándar o invisible — un elemento con clase
g-recaptchay undata-sitekeyvisible en el HTML. - v3 — no hay casilla visible; el script se carga como
api.js?render=SITEKEYy se dispara por código congrecaptcha.execute. - Enterprise — el script es
enterprise.jsen lugar deapi.js.
Con la versión clara, aplicas el método de extracción que corresponde.
Método 1: leer los atributos del HTML
El sitekey casi siempre está a la vista en el HTML servido, así que empieza por aquí: es el caso más frecuente.
El atributo data-sitekey
import re
import requests
url = "https://staging.example.com/qa-login"
html = requests.get(url).text
# Find data-sitekey
match = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)["\']', html)
if match:
sitekey = match.group(1)
print(f"Sitekey: {sitekey}")
# Check if invisible
invisible_match = re.search(r'data-size=["\']invisible["\']', html)
is_invisible = bool(invisible_match)
print(f"Invisible: {is_invisible}")
# Find callback
callback_match = re.search(r'data-callback=["\'](\w+)["\']', html)
callback = callback_match.group(1) if callback_match else None
print(f"Callback: {callback}")
# Check for data-s (Google-owned sites)
data_s_match = re.search(r'data-s=["\']([^"\']+)["\']', html)
data_s = data_s_match.group(1) if data_s_match else None
print(f"data-s: {data_s}")
Con Puppeteer desde el navegador
const puppeteer = require('puppeteer');
const browser = await puppeteer.launch();
const page = await browser.newPage();
await page.goto('https://staging.example.com/qa-login', { waitUntil: 'networkidle2' });
const params = await page.evaluate(() => {
const widget = document.querySelector('.g-recaptcha');
if (!widget) return null;
return {
sitekey: widget.getAttribute('data-sitekey'),
size: widget.getAttribute('data-size'),
callback: widget.getAttribute('data-callback'),
dataS: widget.getAttribute('data-s'),
invisible: widget.getAttribute('data-size') === 'invisible',
};
});
console.log(params);
Método 2: extraer de las etiquetas script
Cuando no hay data-sitekey en el HTML, la clave suele estar en la etiqueta <script> que carga la API. Es el caso típico de v3 y Enterprise.
Sitekeys de reCAPTCHA v3 y Enterprise
En reCAPTCHA v3 y Enterprise el sitekey viaja dentro de la URL del script que carga la API:
# Find sitekey from script src
v3_match = re.search(
r'recaptcha/(?:api|enterprise)\.js\?.*?render=([A-Za-z0-9_-]+)',
html
)
if v3_match:
sitekey = v3_match.group(1)
print(f"v3 Sitekey: {sitekey}")
# Check enterprise
is_enterprise = 'enterprise.js' in html
print(f"Enterprise: {is_enterprise}")
Localizar el parámetro action
La acción no está en los atributos HTML: se pasa dentro del código JavaScript que dispara la verificación.
# Search for grecaptcha.execute calls
action_match = re.search(
r'grecaptcha\.execute\s*\([^,]+,\s*\{[^}]*action\s*:\s*["\']([^"\']+)',
html
)
if action_match:
action = action_match.group(1)
print(f"Action: {action}")
Método 3: extraer del src del iframe
Cuando reCAPTCHA se representa dentro de un iframe, el sitekey aparece como parámetro k= en la URL de ese iframe:
# Find reCAPTCHA iframe
iframe_match = re.search(
r'<iframe[^>]+src=["\']([^"\']*recaptcha/api2/anchor[^"\']*)["\']',
html
)
if iframe_match:
iframe_src = iframe_match.group(1)
sitekey_match = re.search(r'k=([A-Za-z0-9_-]+)', iframe_src)
if sitekey_match:
sitekey = sitekey_match.group(1)
print(f"Iframe sitekey: {sitekey}")
Método 4: cuando el widget se monta con JavaScript
Algunas páginas inyectan el widget con JavaScript después de cargar, y el sitekey vive en la llamada que lo construye.
Para páginas que representan reCAPTCHA de forma dinámica con grecaptcha.render():
# Find grecaptcha.render calls
render_match = re.search(
r'grecaptcha\.render\s*\([^,]*,\s*\{([^}]+)\}',
html
)
if render_match:
config = render_match.group(1)
sk = re.search(r'sitekey\s*:\s*["\']([A-Za-z0-9_-]+)', config)
cb = re.search(r'callback\s*:\s*["\']?(\w+)', config)
sz = re.search(r'size\s*:\s*["\'](\w+)', config)
print(f"Sitekey: {sk.group(1) if sk else 'not found'}")
print(f"Callback: {cb.group(1) if cb else 'not found'}")
print(f"Size: {sz.group(1) if sz else 'not found'}")
Una función que lo extrae todo
Cada método cubre un caso, pero en un scraper real conviene encadenarlos y quedarte con el primer acierto. El orden es:
- El atributo
data-sitekeydel HTML. - El parámetro
render=del script de v3 o Enterprise. - El parámetro
k=delsrcdel iframe. - La llamada a
grecaptcha.render()para los widgets dinámicos.
import re
import requests
def extract_recaptcha_params(url):
html = requests.get(url, timeout=15).text
params = {"pageurl": url}
# Sitekey from data-sitekey
sk = re.search(r'data-sitekey=["\']([A-Za-z0-9_-]+)', html)
if sk:
params["sitekey"] = sk.group(1)
# Sitekey from script render parameter (v3)
if "sitekey" not in params:
v3 = re.search(r'render=([A-Za-z0-9_-]{20,})', html)
if v3:
params["sitekey"] = v3.group(1)
# Sitekey from iframe
if "sitekey" not in params:
iframe = re.search(r'recaptcha.*?k=([A-Za-z0-9_-]+)', html)
if iframe:
params["sitekey"] = iframe.group(1)
# Sitekey from grecaptcha.render
if "sitekey" not in params:
render = re.search(r'sitekey\s*:\s*["\']([A-Za-z0-9_-]+)', html)
if render:
params["sitekey"] = render.group(1)
# Version detection
if re.search(r'data-size=["\']invisible', html):
params["invisible"] = True
if 'enterprise.js' in html:
params["enterprise"] = True
# Action (v3)
action = re.search(
r'action\s*:\s*["\']([^"\']+)',
html[html.find('grecaptcha.execute'):] if 'grecaptcha.execute' in html else ''
)
if action:
params["action"] = action.group(1)
# data-s
ds = re.search(r'data-s=["\']([^"\']+)', html)
if ds:
params["data_s"] = ds.group(1)
# Callback
cb = re.search(r'data-callback=["\'](\w+)', html)
if cb:
params["callback"] = cb.group(1)
return params
# Usage
params = extract_recaptcha_params("https://staging.example.com/qa-login")
for k, v in params.items():
print(f" {k}: {v}")
Salida esperada:
pageurl: https://staging.example.com/qa-login
sitekey: 6Le-SITEKEY-abc123
invisible: True
callback: onCaptchaComplete
Si algún campo sale vacío no es un fallo: ese sitio no usa ese parámetro. Solo sitekey y pageurl son obligatorios; el resto son opcionales según la versión.
Enviar los parámetros a CaptchaAI
Con el diccionario params ya montado, lo trasladas a la petición de resolución. CaptchaAI resuelve reCAPTCHA v2, v3 y Enterprise, así que añades cada bandera solo cuando el sitio la use:
data = {
"key": API_KEY,
"method": "userrecaptcha",
"googlekey": params["sitekey"],
"pageurl": params["pageurl"],
"json": "1",
}
if params.get("invisible"):
data["invisible"] = "1"
if params.get("enterprise"):
data["enterprise"] = "1"
if params.get("action"):
data["action"] = params["action"]
if params.get("data_s"):
data["data-s"] = params["data_s"]
resp = requests.post("https://ocr.captchaai.com/in.php", data=data).json()
Cada bandera opcional se corresponde con un parámetro de la petición:
invisible→1cuando el widget es de tipo invisible.enterprise→1para las claves de tipo Enterprise.action→ la acción de v3 que extrajiste del JavaScript.data-s→ el token dinámico de los sitios de Google.
Envía solo las banderas que el sitio usa de verdad: las que no aplican pueden hacer que la resolución falle.
Problemas frecuentes y cómo resolverlos
Estos son los tropiezos más habituales al extraer parámetros, y cómo salir de cada uno:
No se encontró ninguna clave de sitio
La página monta el widget con renderizado dinámico. Usa Puppeteer o Selenium para leer el DOM ya construido en lugar del HTML estático.
La clave de sitio es incorrecta
Hay varias instancias de reCAPTCHA en la página. Comprueba qué widget corresponde al formulario que vas a enviar.
La acción no aparece
Suele estar en un archivo JS externo. Descarga los archivos JavaScript enlazados y busca la llamada a grecaptcha.execute.
data-s cambia en cada solicitud
Google lo regenera, así que no puedes cachearlo. Extrae un data-s nuevo antes de cada resolución.
Preguntas frecuentes
¿Dónde busco el sitekey si la página no tiene data-sitekey?
Depende de la versión. En reCAPTCHA v3 y Enterprise el sitekey suele estar en el parámetro render= de la URL del script api.js o enterprise.js; si el widget vive en un iframe, aparece como k= en el src. La función completa de esta guía prueba las cuatro fuentes en orden.
¿Necesito el parámetro action en reCAPTCHA v2?
No. El action es exclusivo de reCAPTCHA v3 (y a veces de Enterprise). Para v2 estándar o invisible basta con el sitekey y la pageurl; añadir action no cambia nada.
¿Qué hago si hay varios reCAPTCHA en la misma página?
Comprueba a qué formulario pertenece cada uno antes de enviar. Un document.querySelectorAll('.g-recaptcha') te devuelve todos los widgets; quédate con el sitekey del que envuelve el formulario que realmente vas a resolver.
¿La clave del sitio es lo mismo que mi API key?
No. El sitekey es una clave pública que Google asigna al sitio web, es visible en el código fuente y se puede compartir sin riesgo. Tu API key de CaptchaAI es privada y nunca debe aparecer en el HTML del sitio.
¿Funciona igual con reCAPTCHA Enterprise?
Sí, con un matiz. El sitekey de Enterprise se extrae igual que el de v3 —normalmente del render= de enterprise.js—, pero al enviarlo a CaptchaAI debes añadir la bandera enterprise y, si el sitio la usa, también la action. El resto del flujo es idéntico.
Extrae los parámetros y resuélvelos con CaptchaAI
Consigue tu API key en captchaai.com y envía los parámetros extraídos a la API de resolución.