Primeros Pasos

Migrar de CapMonster Cloud a CaptchaAI

Cambiar de CapMonster Cloud a CaptchaAI es un trabajo de tarde: tocas la URL base, el parámetro de la clave y la forma en que lees la respuesta. Abajo tienes el mapa de equivalencias, el punto donde casi todos se tropiezan y una checklist de corte.

El motivo rara vez es técnico: es de presupuesto. CapMonster Cloud cobra por resolución, así que la factura sube justo cuando el proyecto empieza a funcionar. CaptchaAI cobra por thread concurrente, con resoluciones ilimitadas dentro del plan. Para una agencia que factura en moneda local y paga en USD, pasar de coste variable a cuota fija (BASIC, $15/mes, 5 threads) es lo que permite presupuestar.


Los tres cambios que importan de verdad

Casi toda la migración cabe en esta tabla.

Componente CapMonster Cloud CaptchaAI
URL de envío https://api.capmonster.cloud/createTask https://ocr.captchaai.com/in.php
URL de resultado https://api.capmonster.cloud/getTaskResult https://ocr.captchaai.com/res.php
Parámetro de la clave clientKey key
Formato cuerpo JSON codificado en formulario (o JSON)
ID de tarea taskId request
Resultado objeto solution request (token)

Lo esencial: cambia el endpoint, el parámetro de la clave y dónde vive el token. Lo demás se deriva de ahí.


La ruta rápida: dos constantes y a probar

Si tus llamadas pasan por un wrapper o un SDK, empieza por aquí: cambia las constantes y ejecuta tu suite.

# Before (CapMonster Cloud)
API_URL = "https://api.capmonster.cloud"
CLIENT_KEY = "your_capmonster_key"

# After (CaptchaAI)
SUBMIT_URL = "https://ocr.captchaai.com/in.php"
RESULT_URL = "https://ocr.captchaai.com/res.php"
API_KEY = "your_captchaai_key"

Si arranca y tu wrapper ya normalizaba la respuesta, has terminado. Si no, la diferencia está en el parseo.


Migración completa de reCAPTCHA v2

Compara los dos bloques línea por línea: la lógica de sondeo es la misma, cambia el vocabulario.

Cómo lo hacías con CapMonster Cloud

import requests
import time

resp = requests.post("https://api.capmonster.cloud/createTask", json={
    "clientKey": "CAPMONSTER_KEY",
    "task": {
        "type": "RecaptchaV2TaskProxyless",
        "websiteURL": "https://example.com",
        "websiteKey": "6Le-SITEKEY",
    }
}).json()
task_id = resp["taskId"]

while True:
    time.sleep(5)
    result = requests.post("https://api.capmonster.cloud/getTaskResult", json={
        "clientKey": "CAPMONSTER_KEY",
        "taskId": task_id,
    }).json()
    if result["status"] == "ready":
        token = result["solution"]["gRecaptchaResponse"]
        break

Cómo queda con CaptchaAI

import requests
import time

resp = requests.post("https://ocr.captchaai.com/in.php", data={
    "key": "YOUR_API_KEY",
    "method": "userrecaptcha",
    "googlekey": "6Le-SITEKEY",
    "pageurl": "https://example.com",
    "json": "1",
}).json()
task_id = resp["request"]

while True:
    time.sleep(5)
    result = requests.get("https://ocr.captchaai.com/res.php", params={
        "key": "YOUR_API_KEY",
        "action": "get",
        "id": task_id,
        "json": "1",
    }).json()
    if result["status"] == 1:
        token = result["request"]
        break
    if result["request"] != "CAPCHA_NOT_READY":
        raise Exception(result["request"])

Fíjate en el final: CaptchaAI devuelve CAPCHA_NOT_READY mientras la tarea sigue en cola, y cualquier otro valor en request es un error que debes propagar. Esa comprobación evita bucles infinitos con la clave mal puesta o el saldo a cero.


Migración en Node.js

En JavaScript pasas de un cuerpo JSON a parámetros de query.

Cómo lo hacías con CapMonster Cloud

const axios = require('axios');

const resp = await axios.post('https://api.capmonster.cloud/createTask', {
  clientKey: 'CAPMONSTER_KEY',
  task: {
    type: 'RecaptchaV2TaskProxyless',
    websiteURL: 'https://example.com',
    websiteKey: '6Le-SITEKEY',
  }
});
const taskId = resp.data.taskId;

Cómo queda con CaptchaAI

const axios = require('axios');

const resp = await axios.post('https://ocr.captchaai.com/in.php', null, {
  params: {
    key: 'YOUR_API_KEY',
    method: 'userrecaptcha',
    googlekey: '6Le-SITEKEY',
    pageurl: 'https://example.com',
    json: 1,
  }
});
const taskId = resp.data.request;

El único ajuste conceptual es que resp.data.taskId pasa a ser resp.data.request. Si tipas la respuesta en TypeScript, ahí te avisará el compilador.


Consultar el saldo

Detalle fácil de olvidar: tus alertas de saldo bajo apuntan a otro endpoint. En CaptchaAI la consulta reutiliza res.php con action=getbalance.

CapMonster Cloud

resp = requests.post("https://api.capmonster.cloud/getBalance", json={
    "clientKey": "CAPMONSTER_KEY"
}).json()
balance = resp["balance"]

CaptchaAI

resp = requests.get("https://ocr.captchaai.com/res.php", params={
    "key": "YOUR_API_KEY",
    "action": "getbalance",
    "json": "1",
}).json()
balance = float(resp["request"])

Envuélvelo en float(): la API devuelve el saldo como cadena en request.


Equivalencias de parámetros por tipo de CAPTCHA

Comprobación del primer día: CaptchaAI resuelve reCAPTCHA v2 y v3 (invisible, callback y Enterprise), Cloudflare Turnstile y Challenge, GeeTest v3, imagen/OCR, grid y BLS, más CaptchaFox, Friendly Captcha y Lemin en beta. hCaptcha y FunCaptcha (Arkose Labs) no son compatibles; GeeTest v4 figura como próximamente.

reCAPTCHA v2

CapMonster Cloud CaptchaAI
task.type: "RecaptchaV2TaskProxyless" method: "userrecaptcha"
task.websiteKey googlekey
task.websiteURL pageurl
task.isInvisible: true invisible: "1"

Cloudflare Turnstile

CapMonster Cloud CaptchaAI
task.type: "TurnstileTaskProxyless" method: "turnstile"
task.websiteKey sitekey
task.websiteURL pageurl

CAPTCHA de imagen

CapMonster Cloud CaptchaAI
task.type: "ImageToTextTask" method: "base64"
task.body body

Para GeeTest v3 o grid el patrón es idéntico: cambia method y los parámetros del widget. La estructura de envío y sondeo no varía entre tipos.


Códigos de error: donde falla la mitad de las migraciones

CapMonster Cloud Equivalente en CaptchaAI
ERROR_KEY_DOES_NOT_EXIST ERROR_KEY_DOES_NOT_EXIST
ERROR_ZERO_BALANCE ERROR_ZERO_BALANCE
ERROR_RECAPTCHA_TIMEOUT ERROR_CAPTCHA_UNSOLVABLE
ERROR_NO_SLOT_AVAILABLE ERROR_NO_SLOT_AVAILABLE
CAPTCHA_NOT_READY CAPCHA_NOT_READY

Mira la última fila: CaptchaAI escribe CAPCHA_NOT_READY, sin la T. No es una errata de este artículo, es el valor literal de la API. Si mantienes la comparación contra CAPTCHA_NOT_READY, tu código leerá "todavía no está lista" como error fatal y abortará cada tarea a los cinco segundos.

ERROR_NO_SLOT_AVAILABLE tampoco es una caída: has agotado los threads del plan. Si es constante, sube de tier (BASIC $15/mes con 5 threads, STANDARD $30/mes con 15, ADVANCE $90/mes con 50).


Checklist de corte

Los ocho pasos, en este orden, antes de mover tráfico real:

  • [] Obtén tu clave API en captchaai.com
  • [] URL de envío: createTask por ocr.captchaai.com/in.php
  • [] URL de resultado: getTaskResult por ocr.captchaai.com/res.php
  • [] Autenticación: clientKey por key
  • [] Formato: del objeto JSON task a parámetros codificados en formulario
  • [] Parseo: taskId por request y solution.gRecaptchaResponse por request
  • [] Errores: CAPTCHA_NOT_READY por CAPCHA_NOT_READY
  • [] Prueba una sola resolución antes de tocar producción

El último punto no es decorativo: una resolución real contra staging valida clave, endpoint, parseo y verificación de backend de una pasada.


Un corte progresivo, con números

Caso frecuente en agencias de la región: un portal de trámites propio con reCAPTCHA v2 en el alta y una suite nocturna de QA que hace unas 400 resoluciones contra staging. Con precio por resolución esa cifra es una línea variable; con planes por thread caben de sobra en BASIC ($15/mes, 5 threads), porque el límite es cuántas tareas tienes en vuelo a la vez, no cuántas resuelves al mes.

Corta por porcentaje: una semana con el 10% de las tareas de QA en CaptchaAI y, si cuadran los números, sube al 50% y luego al 100%. Usa la misma configuración de navegador en QA, staging y CI.

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, idioma y user-agent idénticos desaparece el clásico "en local pasa, en CI falla". Durante el corte mide en tu endpoint: tiempo de resolución, tasa de éxito de la verificación de backend, errores por código y latencia extremo a extremo. Usa una clave API separada para QA y respeta los términos de servicio y la normativa de protección de datos aplicable (GDPR y LOPDGDD en España, LFPDPPP en México).


Solución de problemas

Síntoma Acción recomendada
Cada tarea aborta a los 5 segundos Compara contra CAPCHA_NOT_READY, sin la T
ERROR_KEY_DOES_NOT_EXIST con la clave correcta Envías clientKey en lugar de key
El token llega vacío Lee request, no solution.gRecaptchaResponse
ERROR_NO_SLOT_AVAILABLE recurrente Threads del plan agotados: sube de tier
El test pasa en local y falla en CI Iguala viewport, idioma y user-agent

Preguntas frecuentes

¿Cuánto tiempo real tarda la migración?

Entre 15 y 30 minutos si tus llamadas están encapsuladas en un módulo. Si están repartidas, lo que tarda es encontrarlas: haz un grep de capmonster sobre el repositorio.

¿Puedo mantener los dos servicios a la vez?

Sí, y es la forma recomendada de cortar. Nada impide tener ambos clientes activos mientras validas resultados.

¿Cambia el coste si mi volumen sube de golpe?

No dentro del mismo plan. Al facturar por thread concurrente con resoluciones ilimitadas, un pico se traduce en tareas encoladas, no en una factura sorpresa.

¿Qué pasa con los tipos que CaptchaAI no resuelve?

hCaptcha y FunCaptcha (Arkose Labs) no son compatibles y GeeTest v4 figura como próximamente. Si tu flujo depende de alguno, una migración parcial es más realista.


Empieza con una sola resolución de prueba

Crea tu cuenta en captchaai.com y lanza una resolución contra tu formulario de staging. Si el token pasa la verificación del backend, ya has migrado.


Guías relacionadas

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