Solución de Problemas

Diagnóstico cuando cae la tasa de éxito al resolver CAPTCHA

Cuando la tasa de éxito cae de un día para otro, la causa está casi siempre en una de tres capas: la API no devuelve token, lo devuelve y el sitio lo rechaza, o el sitio cambió y sigues enviando parámetros que ya no existen. Distinguirlas toma quince minutos, porque cada capa deja una huella distinta en tus logs.

El error clásico es reaccionar antes de medir: subes reintentos, cambias de plan y la tasa sigue igual, porque el problema era un sitekey que el equipo de frontend rotó. El orden aquí es el inverso: mide, clasifica y corrige.


Antes de tocar nada: separa el síntoma de la causa

Tareas enviadas frente a tokens recibidos mide tu integración con la API; tokens recibidos frente a formularios aceptados mide la compatibilidad con el sitio. La mayoría de los reportes de soporte confunden la segunda con la primera: si llegan tokens con normalidad, ningún cambio de plan moverá nada.

Caso frecuente en equipos de habla hispana: un flujo de QA sobre el formulario de un portal de cita previa funciona meses y de golpe falla por las tardes. Hay tokens sin errores, así que no es la API. Había cambiado el pageurl: el portal empezó a redirigir a un subdominio regional y el token se resolvía contra un dominio pero se enviaba a otro.


Diagrama de flujo de diagnóstico

Recórrelo de arriba abajo y detente en la primera rama que coincida con tus logs.

Success rate dropped
│
├── Are tokens being generated?
│   ├── NO → Check API errors
│   │   ├── ERROR_WRONG_GOOGLEKEY → Sitekey changed. Re-extract.
│   │   ├── ERROR_BAD_PARAMETERS → Check required params
│   │   ├── ERROR_NO_SLOT → Retry with backoff
│   │   └── Other errors → See error decision tree
│   │
│   └── YES → Tokens generated but rejected by target site
│       │
│       ├── Token expired before use?
│       │   └── YES → Submit token faster (< 60-120s)
│       │
│       ├── Token used for wrong domain?
│       │   └── YES → Check pageurl matches submission domain
│       │
│       ├── reCAPTCHA v3 score too low?
│       │   └── YES → Check action parameter, attach cookies/UA/proxy
│       │
│       ├── Site changed CAPTCHA type?
│       │   └── YES → Re-detect CAPTCHA type
│       │
│       └── Site added additional checks?
│           └── YES → Check for fingerprinting, cookies, headers

Paso 1: mide tu tasa real antes de cambiar nada

Instrumenta el flujo y deja correr una hora de tráfico normal, separando el resultado por método. Una caída que afecta solo a userrecaptcha y deja intacto turnstile ya reduce el espacio de búsqueda.

import requests
import time
from collections import defaultdict

class SuccessTracker:
    """Track solve success rates over time."""

    def __init__(self):
        self.stats = defaultdict(lambda: {"attempts": 0, "success": 0, "errors": defaultdict(int)})

    def record(self, method, success, error_code=None):
        self.stats[method]["attempts"] += 1
        if success:
            self.stats[method]["success"] += 1
        elif error_code:
            self.stats[method]["errors"][error_code] += 1

    def report(self):
        for method, data in self.stats.items():
            rate = data["success"] / data["attempts"] * 100 if data["attempts"] > 0 else 0
            print(f"\n{method}:")
            print(f"  Attempts: {data['attempts']}")
            print(f"  Success: {data['success']} ({rate:.1f}%)")
            if data["errors"]:
                print("  Errors:")
                for err, count in sorted(data["errors"].items(), key=lambda x: -x[1]):
                    print(f"    {err}: {count}")

tracker = SuccessTracker()

Guarda el reporte antes y después de cada corrección: sin línea base no sabrás si el cambio ayudó o si coincidió con menos carga.


Paso 2: clasifica el fallo en una de las dos categorías

Categoría A: fallos a nivel de la API

La API de CaptchaAI devuelve un error en lugar de un token. El código nombra la causa: ERROR_WRONG_GOOGLEKEY es un sitekey cambiado, ERROR_BAD_PARAMETERS un campo obligatorio ausente y ERROR_NO_SLOT una señal de reintentar con retroceso exponencial. Lanza una tanda corta de pruebas y cuenta patrones en vez de mirar errores sueltos:

def diagnose_api_failures(api_key, method, params, attempts=10):
    """Run test solves and collect error patterns."""
    errors = defaultdict(int)
    successes = 0

    for i in range(attempts):
        try:
            resp = requests.post("https://ocr.captchaai.com/in.php", data={
                "key": api_key, "method": method, "json": 1, **params,
            }, timeout=30)
            result = resp.json()

            if result.get("status") != 1:
                errors[result.get("request", "UNKNOWN")] += 1
                continue

            task_id = result["request"]
            # Quick poll
            time.sleep(15)
            resp = requests.get("https://ocr.captchaai.com/res.php", params={
                "key": api_key, "action": "get",
                "id": task_id, "json": 1,
            }, timeout=15)
            data = resp.json()

            if data.get("status") == 1:
                successes += 1
            else:
                errors[data.get("request", "POLL_ERROR")] += 1

        except Exception as e:
            errors[f"EXCEPTION:{type(e).__name__}"] += 1

        time.sleep(2)

    print(f"\nResults: {successes}/{attempts} success")
    for err, count in sorted(errors.items(), key=lambda x: -x[1]):
        print(f"  {err}: {count}")

Si ocho de diez intentos devuelven el mismo código, ya tienes la causa raíz. Si se reparten entre cinco, sospecha de tu capa de red antes que del servicio.

Categoría B: rechazo del token

CaptchaAI devuelve un token válido y el sitio lo rechaza. Es la categoría que más tiempo consume porque no genera errores visibles: todo parece bien hasta que falla la validación. Causas comunes:

Causa Qué comprobar
El token caducó Se usó más de 120 s tras generarlo
El dominio no coincide pageurl distinto del dominio de envío
Puntuación v3 baja El sitio exige 0.7 y obtienes 0.3
Falta action reCAPTCHA v3 exige acción coincidente
El sitio cambió Cambió el sitekey o la estructura

Paso 3: aplica la corrección que corresponde

Corrección: caducidad del token

Un token no es almacenable. Resuélvelo y úsalo en la misma ejecución, sin colas ni caché intermedias.

def solve_and_use_immediately(api_key, sitekey, pageurl):
    """Solve and use token as fast as possible."""
    # Submit
    resp = requests.post("https://ocr.captchaai.com/in.php", data={
        "key": api_key,
        "method": "userrecaptcha",
        "googlekey": sitekey,
        "pageurl": pageurl,
        "json": 1,
    }, timeout=30)
    task_id = resp.json()["request"]

    # Poll aggressively
    for _ in range(24):
        time.sleep(5)
        resp = requests.get("https://ocr.captchaai.com/res.php", params={
            "key": api_key, "action": "get",
            "id": task_id, "json": 1,
        }, timeout=15)
        data = resp.json()
        if data.get("status") == 1:
            token = data["request"]
            # USE IMMEDIATELY — don't store for later
            submit_form(token)
            return True

    return False

Corrección: sitekey obsoleto

Si el sitio rota su sitekey, cualquier valor fijo en tu configuración caduca en silencio. Extráelo en cada ejecución.

def solve_with_fresh_params(api_key, pageurl):
    """Re-extract sitekey before each solve."""
    import re

    resp = requests.get(pageurl, timeout=15)
    match = re.search(r'data-sitekey="([^"]+)"', resp.text)
    if not match:
        raise RuntimeError("Could not find sitekey")

    sitekey = match.group(1)
    # Now solve with fresh sitekey
    # ...

Corrección: parámetro action en reCAPTCHA v3

En reCAPTCHA v3 la acción forma parte de la validación: si el sitio usa submit y tú envías otra, el token se genera pero el sitio lo descarta.

# Check what action the site uses
# Look for: grecaptcha.execute('sitekey', {action: 'submit'})

data = {
    "key": api_key,
    "method": "userrecaptcha",
    "googlekey": sitekey,
    "pageurl": pageurl,
    "version": "v3",
    "action": "submit",  # Must match site's action
    "json": 1,
}

Umbrales de alerta por tipo de CAPTCHA

CaptchaAI mantiene una alta tasa de éxito en los tipos compatibles y sus velocidades publicadas son techos de servicio, no promedios. Vigila la desviación frente a tu línea base:

Tipo CAPTCHA Velocidad de referencia Cuándo investigar
reCAPTCHA v2 <60 s Caída sostenida frente a tu base
reCAPTCHA v3 <4 s Rechazos en una sola action
Cloudflare Turnstile <10 s Más tiempo y más rechazos
GeeTest v3 <12 s Cambio tras un despliegue
BLS <1 s Fallos por franja horaria
Imagen/OCR <0.5 s Cambio en la imagen origen

CaptchaFox (beta), Friendly Captcha (beta) y Lemin (beta) no tienen métricas publicadas: compáralas solo contra tus mediciones. hCaptcha y FunCaptcha (Arkose Labs) no son compatibles y GeeTest v4 figura como próximamente; si tu flujo se topa con alguno, es un cambio de tipo en el sitio, no de configuración.

Síntomas frecuentes y su corrección

Síntoma Causa probable Qué hacer
La tasa cayó del 98% al 70% de golpe Cambió el sitekey o la página Reextrae los parámetros
Todos los tokens v3 rechazados action incorrecta Cópiala del código de la página
Los tokens llegan pero caducan Demasiado tiempo hasta el envío Envía antes de 60 segundos
La tasa varía según la hora Límite de solicitudes del sitio Separa más los envíos
Solo falla un método Cambio en ese tipo de CAPTCHA Vuelve a detectar el tipo

Cuánta capacidad necesitas mientras diagnosticas

Cada tanda de prueba ocupa capacidad que tu flujo en producción también quiere. Como CaptchaAI factura por thread concurrente y no por resolución, diagnosticar no mueve la factura: lo que compites es la concurrencia. Con BASIC ($15/mes, 5 threads) conviene pausar el flujo mientras mides; desde ADVANCE ($90/mes, 50 threads) puedes reservar threads para pruebas. Los precios siguen en USD, un costo predecible para equipos que facturan en monedas volátiles.


Preguntas frecuentes

¿Cómo sé si el problema es de CaptchaAI o del sitio de destino?

Mira si recibes token. Si llega y el formulario falla igual, el problema está en cómo lo usas o en algo que cambió el sitio. Si llega un código de error, ve a la categoría A.

¿Cuánto tiempo debo medir antes de concluir que hay una caída real?

Al menos una hora de tráfico normal, comparando contra tu línea base por método. Veinte resoluciones no separan una caída del ruido.

¿Sirve de algo subir de plan cuando cae la tasa de éxito?

Solo si el patrón apunta a falta de threads: colas largas, reintentos por saturación. Un plan mayor añade concurrencia; no corrige un sitekey obsoleto.

¿Debo reportar las resoluciones incorrectas?

Sí. Usa el endpoint reportbad para marcarlas: alimenta la mejora de precisión y te deja un registro fechado de la degradación.

¿Por qué la tasa empeora siempre a la misma hora?

Suele ser límite de solicitudes del sitio de destino, no del solver. Reparte los envíos, añade retroceso exponencial y compara la misma franja de dos días antes de tocar nada.


Guías relacionadas


Mide primero, corrige después. Empieza con CaptchaAI.

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