Solución de Problemas

ERROR_PROXY_NOT_AUTHORIZED: Correcciones de autenticación de proxy

Si la API te devuelve ERROR_PROXY_NOT_AUTHORIZED, el CAPTCHA no tiene nada que ver: CaptchaAI intentó abrir la página de destino a través del proxy que le pasaste y esa conexión no se estableció. Casi siempre es una de cinco cosas: string mal formado, proxytype que no coincide con el protocolo real, credenciales caducadas, contraseña con símbolos sin codificar, o lista blanca de IP en la que la IP que llega no es la tuya.

Qué comprueba la API antes de fallar

CaptchaAI recibe proxy y proxytype, abre la página de pageurl saliendo por ese proxy y resuelve el desafío desde ahí. Si el túnel no se abre, la tarea ni empieza y in.php responde el error. El fallo es anterior a la resolución: no hay res.php que consultar ni sirve cambiar de tipo de CAPTCHA. Todo está en dos campos.

Causa Cómo comprobarla
Formato del string incorrecto Contrasta contra host:port:usuario:password
proxytype equivocado Confirma si es HTTP, HTTPS, SOCKS4 o SOCKS5
Credenciales caducadas Prueba el proxy fuera de CaptchaAI
Contraseña con caracteres especiales Codifícala con URL-encoding
El proveedor exige lista blanca de IP Revisa su panel de control
El host del proxy no responde Comprueba la conectividad TCP al puerto

El formato exacto que espera CaptchaAI

Dos campos, sin variantes. proxytype va en mayúsculas y proxy usa dos puntos como separador, sin http:// delante ni @ entre usuario y host:

proxytype: HTTP | HTTPS | SOCKS4 | SOCKS5
proxy: host:port:username:password

Así queda dentro de un envío completo de reCAPTCHA v2:

import requests

# Correct format
data = {
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": "SITE_KEY",
    "pageurl": "https://example.com",
    "proxytype": "HTTP",
    "proxy": "192.168.1.1:8080:myuser:mypass",
    "json": 1,
}

resp = requests.post("https://ocr.captchaai.com/in.php", data=data)

El fallo más habitual es pegar el proxy en formato URL (http://usuario:pass@host:puerto), como lo entrega el proveedor. Ese string sirve para requests, pero no aquí: reordénalo a host:puerto:usuario:password.

Variantes admitidas del string

Los proxies sin autenticación y los SOCKS también valen, siempre que el proxytype acompañe:

# With authentication
proxy = "192.168.1.1:8080:username:password"

# Without authentication (rare — most captcha proxies need auth)
proxy = "192.168.1.1:8080"

# SOCKS5
proxytype = "SOCKS5"
proxy = "192.168.1.1:1080:user:pass"

Si tu proveedor da acceso solo por lista blanca de IP, el string sin credenciales es correcto de forma, pero fallará igual por el motivo de más abajo.

Valida el proxy antes de enviar la tarea

Enviar una tarea para descubrir que el proxy no funcionaba es la forma lenta de depurar. Estas funciones separan sintaxis de red:

import re
import requests


def validate_proxy(proxy_str, proxy_type="HTTP"):
    """Validate proxy format and connectivity."""
    # Check format
    parts = proxy_str.split(":")
    if len(parts) < 2:
        raise ValueError(f"Invalid proxy format: {proxy_str}")

    host = parts[0]
    port = parts[1]

    if not port.isdigit():
        raise ValueError(f"Invalid port: {port}")

    # Check proxy type
    valid_types = {"HTTP", "HTTPS", "SOCKS4", "SOCKS5"}
    if proxy_type not in valid_types:
        raise ValueError(f"Invalid proxy type: {proxy_type}")

    return True


def test_proxy(proxy_str, proxy_type="HTTP"):
    """Test if proxy is working."""
    parts = proxy_str.split(":")
    host = parts[0]
    port = parts[1]

    if len(parts) == 4:
        user, password = parts[2], parts[3]
        proxy_url = f"{proxy_type.lower()}://{user}:{password}@{host}:{port}"
    else:
        proxy_url = f"{proxy_type.lower()}://{host}:{port}"

    proxies = {"http": proxy_url, "https": proxy_url}

    try:
        resp = requests.get(
            "https://httpbin.org/ip",
            proxies=proxies,
            timeout=10,
        )
        print(f"Proxy working. IP: {resp.json()['origin']}")
        return True
    except Exception as e:
        print(f"Proxy failed: {e}")
        return False


# Test before using con CaptchaAI
proxy = "192.168.1.1:8080:user:pass"
if test_proxy(proxy, "HTTP"):
    print("Proxy is ready to use")

Si test_proxy imprime una IP y la tarea sigue fallando, el problema ya no es el string sino el origen de la conexión.

Contraseñas con símbolos: el caso de los dos puntos

El separador son los dos puntos, así que cualquier : dentro de la contraseña rompe el parseo y añade un campo de más. Igual con @, # o %. Codifícala antes de armar el string:

from urllib.parse import quote


def format_proxy(host, port, username, password):
    """Format proxy string, handling special characters."""
    # URL-encode password if it contains special characters
    safe_password = quote(password, safe="")
    return f"{host}:{port}:{username}:{safe_password}"


# Password with special characters
proxy = format_proxy("192.168.1.1", "8080", "user", "p@ss:word!")

Es frecuente cuando el gestor de secretos genera la contraseña: sale sólida y el pipeline la rompe al concatenarla.

Cuando no sabes qué protocolo habla el proxy

Algunos proveedores dan el mismo host con un puerto por protocolo. Antes de probar proxytype a ciegas, mira qué puerto acepta conexión:

def detect_proxy_type(host, port):
    """Try to detect which proxy protocol works."""
    import socket

    for proxy_type in ["HTTP", "SOCKS5", "SOCKS4"]:
        try:
            # Basic TCP connection test
            sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
            sock.settimeout(5)
            result = sock.connect_ex((host, int(port)))
            sock.close()

            if result == 0:
                return proxy_type  # Port is open, try this type
        except Exception:
            continue

    return None

Es una comprobación de puerto abierto, no un handshake: úsala como primer filtro y confirma con un envío real.

Funciona en local y falla vía CaptchaAI: el caso de la lista blanca

Este es el escenario que más tickets genera y el que menos se parece a un bug. Piensa en un equipo que monitoriza precios de marketplaces regionales desde un servidor en Madrid o en Ciudad de México: dieron de alta la IP de ese servidor en la lista blanca del proveedor y desde ahí todo funciona. Pero cuando CaptchaAI abre la página de destino, quien se conecta al proxy es la infraestructura de CaptchaAI, no tu servidor, y esa IP no está autorizada. La solución no está en el código: pide credenciales en lugar de acceso por IP.

Síntoma Causa probable Corrección
Falla con credenciales que sabes correctas El proveedor exige lista blanca de IP Cambia a autenticación por usuario y contraseña
Funciona en local, falla vía CaptchaAI La IP que conecta al proxy no es la tuya Mismo cambio: credenciales en lugar de IP
El proxy SOCKS no conecta nunca proxytype equivocado Prueba SOCKS5, luego SOCKS4
Fallos intermitentes de autenticación Límite de solicitudes del proveedor Usa proxies dedicados en lugar de compartidos
El string se parte en campos de más Contraseña con : sin codificar Codifica la contraseña con URL-encoding

Preguntas frecuentes

¿Necesito un proxy para resolver un CAPTCHA con CaptchaAI?

No. Es opcional y muchos flujos funcionan sin él. Tiene sentido cuando el destino comprueba que la IP donde se generó el token coincide con la que después lo envía.

¿Este error consume saldo o threads de mi plan?

No. La tarea se rechaza antes de resolverse, así que no ocupa un thread. Los planes van de BASIC ($15/mes, 5 threads) a VIP-3 ($7,500/mes, 5.000 threads) y se facturan por threads concurrentes, con resoluciones ilimitadas.

¿HTTP o SOCKS5 para la mayoría de los casos?

HTTP o HTTPS cubre casi todo. Elige SOCKS5 solo si tu proveedor lo entrega así o el destino lo exige; SOCKS4 rara vez hace falta.

¿Puedo reutilizar el mismo proxy en varias tareas en paralelo?

Sí, pero mide antes: los proxies compartidos aplican límite de solicitudes por credencial, y eso aparece como fallos intermitentes al subir la concurrencia.

¿Sirve el mismo formato para reCAPTCHA v2, v3 y Turnstile?

Sí. Los campos proxy y proxytype son idénticos en todos los tipos que CaptchaAI resuelve, incluidos reCAPTCHA v2/v3, Cloudflare Turnstile y GeeTest v3. Solo cambia el method.

Guías relacionadas

Deja el entorno igual en local, staging y CI

Buena parte de los "falla solo en CI" no viene del proxy sino del navegador. Fija la misma configuración en tus runners antes de culpar a la red:

from selenium import webdriver

def make_driver(headless: bool = True) -> webdriver.Chrome:
    options = webdriver.ChromeOptions()
    if headless:
        options.add_argument('--headless=new')
    options.add_argument('--window-size=1280,800')
    options.add_argument('--lang=es-ES')
    return webdriver.Chrome(options=options)

Con viewport e idioma idénticos, un fallo que solo aparece en CI apunta al proxy. Registra los errores por código (ERROR_*, tiempos de espera, red): son intermitentes y sin traza no se reproducen.

¿Sigues bloqueado con el proxy? Resuélvelo con CaptchaAI.

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