DEV Community

Cover image for Prove you are a robot: CAPTCHAs invertidos para agentes IA
Juan Torchia
Juan Torchia

Posted on • Originally published at juanchi.dev

Prove you are a robot: CAPTCHAs invertidos para agentes IA

Hay una creencia instalada en la comunidad dev sobre identidad en la web que está, con todo respeto, bastante equivocada. La creencia es: los CAPTCHAs son un problema resuelto para software legítimo. La realidad que estoy midiendo en producción es la opuesta: el software legítimo más sofisticado que estamos construyendo hoy —los agentes IA— está siendo bloqueado exactamente porque funciona demasiado bien como bot.

El CAPTCHA nació en 2000 con una premisa elegante: los humanos pueden leer texto distorsionado, las máquinas no. Dos décadas después, las máquinas leen ese texto mejor que los humanos. Entonces inventamos puzzles más difíciles. Después semáforos y bicicletas. Después análisis de comportamiento. Todo el ecosistema de verificación web se construyó sobre un axioma: bot = malo, humano = bueno.

Ese axioma se rompió. Y mis logs de retry me están mostrando exactamente cómo.

El problema de captcha agentes IA identidad en producción

Estoy corriendo agentes que hacen scraping legítimo, llamadas a APIs públicas, y flujos de automatización reales. No es nada exótico: un agente que verifica precios, otro que monitorea disponibilidad, otro que llena formularios de manera programática para testing. Cosas que cualquier empresa mediana necesita.

El problema es que estos agentes, cuando chocan contra heurísticas anti-bot modernas, no tienen forma de decir "soy un agente legítimo, operado por Juan Torchia, con estos permisos". No existe ese canal. El único canal disponible es fingir ser humano —lo cual es técnicamente mentira y éticamente incómodo— o fallar.

Estos son mis números reales de la semana pasada:

// Logs de retry de mi agente de monitoreo
// Período: 7 días, 3 sitios distintos

const retryStats = {
  // Sitio con Cloudflare básico
  sitioA: {
    totalRequests: 1240,
    blockedByBot: 47,        // 3.8% de bloqueo
    retriesNeeded: 89,       // algunos pidieron 2+ retries
    avgRetryDelay: '4.2s',
    tokenOverhead: '~1200 tokens extra por sesión bloqueada'
  },
  // Sitio con hCaptcha en flujo de login
  sitioB: {
    totalRequests: 340,
    blockedByBot: 112,       // 32.9% — casi 1 de cada 3
    retriesNeeded: 198,
    avgRetryDelay: '12.8s',
    tokenOverhead: '~4800 tokens extra por sesión bloqueada'
  },
  // API pública con rate limiting agresivo
  sitioC: {
    totalRequests: 890,
    blockedByBot: 23,        // 2.6%
    retriesNeeded: 31,
    avgRetryDelay: '2.1s',
    tokenOverhead: '~600 tokens extra por sesión bloqueada'
  }
}

// El número que me molesta:
// sitioB tiene 32.9% de bloqueo porque el agente
// hace el flujo de login perfectamente — sin errores,
// sin hesitaciones — y eso es exactamente lo que
// dispara la heurística 'comportamiento no humano'
Enter fullscreen mode Exit fullscreen mode

El sitio B me bloquea el 33% de las veces no porque mi agente haga algo malo. Me bloquea porque lo hace demasiado bien. Velocidad consistente, sin movimientos aleatorios de mouse, sin micro-pausas entre campos. Perfección == sospecha. Eso es el mundo al revés.

Ya escribí sobre el overhead de tokens en contextos distintos —medí cuánto cuestan los retries en mi infraestructura de agentes— pero el overhead por bloqueo de bot es una categoría nueva. No es compresión de prompts. Es latencia pura y costo de reintentos que no deberían existir.

La inversión de décadas de supuestos sobre identidad

Veamos el código que necesito escribir hoy para que mi agente sobreviva en la web:

// Lo que no debería tener que hacer
// pero tengo que hacer porque no existe
// un mecanismo de identidad para agentes

class AgentWithHumanMimicry {
  private addHumanNoise(action: () => Promise<void>): Promise<void> {
    return new Promise(async (resolve) => {
      // Espera aleatoria entre 800ms y 2400ms
      // porque los humanos no son consistentes
      const humanDelay = 800 + Math.random() * 1600
      await sleep(humanDelay)

      // Simulo movimiento de mouse antes de cada click
      // aunque no haya browser visible
      await this.simulateMousePath()

      await action()
      resolve()
    })
  }

  private async simulateMousePath(): Promise<void> {
    // Genero curva de Bézier para que el movimiento
    // no sea perfecto — tiene que parecer humano
    const points = this.generateBezierPath(
      this.currentPosition,
      this.targetPosition,
      { jitter: 0.15, speed: 'human-average' }
    )
    // ... implementación que me hace sentir mal
  }

  async fillForm(data: FormData): Promise<void> {
    for (const [field, value] of Object.entries(data)) {
      // Escribo letra por letra con delays variables
      // para imitar typing humano
      for (const char of String(value)) {
        await this.typeChar(char)
        await sleep(50 + Math.random() * 150) // 50-200ms por caracter
      }
      // Pausa entre campos — también variable
      await sleep(400 + Math.random() * 800)
    }
  }
}

// Este código existe porque no hay alternativa.
// Estoy mintiéndole a la web sobre quién soy.
// Y esa mentira es el estado del arte actual.
Enter fullscreen mode Exit fullscreen mode

Esto es lo que me incomoda profundamente. Tengo que hacer que mi agente mienta sobre su naturaleza para poder operar. No hay un protocolo para decir la verdad.

La web se construyó con HTTP, con cookies, con OAuth, con JWT. Hay formas estandarizadas de decir "soy el usuario X" o "tengo el permiso Y". Pero no hay ninguna forma estandarizada de decir "soy el agente Z, operado por el usuario X, con estos permisos delegados, y podés verificarlo".

Esa capa no existe.

Recordé esta semana algo que escribí sobre por qué los sistemas confiables necesitan diseño institucional, no solo código bueno. El problema del CAPTCHA para agentes es exactamente eso: no es un problema técnico, es un problema de protocolo y de consenso. Necesitamos que el ecosistema acuerde un mecanismo de identidad para agentes, y eso no lo resuelve ningún framework de Python.

Lo que está emergiendo (y por qué es un caos)

Hay intentos. Robots.txt tiene User-Agent pero es un honor system que nadie respeta. Hay propuestas para Agent Identity en el espacio de AI APIs. Anthropic, OpenAI y Google tienen sus propios mecanismos de identificación de agentes, pero son silos. No hay nada interoperable.

Mientras tanto, los sitios están tomando decisiones unilaterales:

// Lo que veo en los headers de respuesta cuando me bloquean
const blockingPatterns = {
  cloudflare: {
    header: 'cf-mitigated: challenge',
    cfRay: 'presente',
    // Cloudflare tiene un programa para bots verificados
    // pero el onboarding es manual y tarda semanas
  },

  datadome: {
    header: 'X-DataDome-*',
    // DataDome ofrece API para bots legítimos
    // costo: $$$, proceso de verificación opaco
  },

  imperva: {
    // Similar — tienen programa de bots buenos
    // pero es enterprise, no hay self-service
  }
}

// La ironía: para demostrar que soy un agente legítimo
// tengo que pasar por un proceso manual, humano,
// burocrático, que puede tardar semanas.
// Para demostrar que soy un bot confiable
// necesito que un humano avale mi bot.
Enter fullscreen mode Exit fullscreen mode

También me acuerdo de algo que planteé cuando estaba diseñando la arquitectura de confianza de mis propios agentes: el problema no es la herramienta, es quién configura el entorno y cómo. El CAPTCHA invertido es la misma pregunta desde el otro lado: ¿cómo le demostrás al entorno que tu configuración es confiable?

Los errores que cometí (y vas a cometer vos)

Error 1: Confiar en User-Agent spoofing como solución

// Esto funciona por 48 horas y después te bloquean igual
const naiveAgent = {
  headers: {
    'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64)...',
    // Spoofear el UA es la primera cosa que todo el mundo prueba
    // y es la primera cosa que los sistemas anti-bot esperan
  }
}
// Los sistemas modernos miran TLS fingerprinting,
// timing entre requests, patrones de navegación.
// El UA es casi irrelevante.
Enter fullscreen mode Exit fullscreen mode

Error 2: No modelar los retries como costo real

Estuve semanas tratando los bloqueos como "errores transitorios" y reintentando agresivamente. Eso empeoró mi reputación de IP y aumentó el bloqueo. El problema no es técnico, es de identidad. Más retries no resuelven un problema de identidad.

Error 3: Asumir que los tests pasan en CI pero fallan en producción

Mis tests de integración corrían contra endpoints propios o mocks. Todo verde. En producción, el primer deploy real contra sitios con Cloudflare fue un desastre. Es el mismo patrón que los agentes que pasan tus tests pero fallan en lo que importa — los tests no modelaban la fricción de identidad real.

Error 4: No tener telemetría de bloqueos desde el día uno

// Esto tendría que haber tenido desde el primer deploy
interface BlockEvent {
  timestamp: Date
  targetDomain: string
  blockType: 'captcha' | 'rate-limit' | 'ip-block' | 'behavior'
  requestSignature: string  // para detectar patrones
  retryCount: number
  tokenCost: number         // cuánto costó este bloqueo en tokens
}

// Sin esto, estuve volando a ciegas por semanas
// y no tenía data para argumentar que el problema
// era sistémico, no un bug en mi código
Enter fullscreen mode Exit fullscreen mode

FAQ: captcha agentes IA identidad

¿Por qué los CAPTCHAs modernos bloquean agentes legítimos?

Los sistemas anti-bot modernos no analizan el User-Agent —eso es trivial de spoofear— sino patrones de comportamiento: velocidad de typing, movimientos de mouse, timing entre acciones, TLS fingerprinting, y reputación de IP. Un agente bien implementado tiene comportamiento demasiado consistente para parecer humano, lo que dispara exactamente las mismas heurísticas que usa un bot malicioso. La legitimidad del propósito es irrelevante para estos sistemas; solo ven el patrón de comportamiento.

¿Existe algún estándar para que los agentes IA se identifiquen legítimamente?

Todavía no hay un estándar consolidado. Hay propuestas en el W3C para credenciales verificables para agentes, y algunos proveedores grandes (Cloudflare, DataDome, Imperva) tienen programas de "bot partners" pero son enterprise, manuales y no interoperables. El espacio de identidad para agentes está donde estaba OAuth en 2007: todos hacen algo diferente y nadie habla con nadie.

¿Cuánto overhead real generan los bloqueos de CAPTCHA en un agente en producción?

Depende del sitio y la agresividad de sus heurísticas. En mis mediciones: entre 600 y 4800 tokens extra por sesión bloqueada, más latencias de 2 a 13 segundos por retry. Para un agente que hace 300-400 requests por día, eso puede representar 15-25% de overhead de tokens solo en manejo de bloqueos. No es trivial ni en costo ni en latencia.

¿Es legal/ético hacer que un agente imite comportamiento humano para evitar CAPTCHAs?

Es una zona gris que se está definiendo en tiempo real. Técnicamente, los ToS de la mayoría de los sitios prohíben acceso automatizado sin permiso explícito. Éticamente, hay una diferencia entre un agente legítimo que accede a información pública para un propósito válido y un scraper malicioso. El problema es que la web no tiene mecanismo para distinguirlos, entonces la solución actual —imitar comportamiento humano— implica ocultar la naturaleza del agente, lo cual es incómodo como postura por defecto.

¿Qué debería implementar hoy para manejar esta fricción sin volver loco al agente?

Tres cosas concretas: (1) telemetría de bloqueos desde el día uno para tener números reales, (2) backoff exponencial con jitter en vez de retries agresivos —más retries empeoran la reputación de IP—, y (3) si el sitio objetivo lo permite, registrarse en programas de bots verificados de Cloudflare o el proveedor que usen. No es una solución elegante, pero es lo que hay.

¿Cómo va a evolucionar esto? ¿Los agentes van a poder identificarse formalmente?

Creo que sí, pero va a tardar. El vector más probable es que los proveedores de identidad grandes (Google, Microsoft, o los mismos vendors de AI) ofrezcan algún tipo de certificado o token de identidad para agentes que los sitios puedan verificar. Ya hay movimiento en esa dirección con las Verifiable Credentials del W3C y con propuestas específicas para AI agents. Pero entre propuesta y adopción masiva hay años. Mientras tanto, el caos es el estado del arte.

La inversión que nadie pidió pero ya llegó

Hay algo que me resulta fascinante de esto desde un ángulo que va más allá del código. El CAPTCHA fue durante 25 años la metáfora de la división digital: humanos de un lado, bots del otro. Ahora esa metáfora se rompió en dos sentidos. Primero, los bots resuelven CAPTCHAs mejor que los humanos. Segundo, necesitamos bots que puedan demostrar que son bots para acceder a cosas que los bots legítimos necesitan acceder.

Me acuerdo de cuando escribía sobre Brunost y quién decide qué es legible. Hay una pregunta de poder detrás de esto: ¿quién tiene el derecho de definir qué es un agente legítimo? Hoy esa decisión la toman Cloudflare, DataDome y tres o cuatro empresas más, de manera unilateral, sin protocolo abierto. Eso me preocupa tanto como los retries.

Mi agente más simple —el que verifica precios para comparar proveedores— hace algo que cualquier humano haría manualmente con veinte tabs abiertas. La única diferencia es que lo hace consistentemente y sin aburrirse. Que eso sea suficiente para que un sistema lo trate como amenaza dice algo sobre cuán mal está diseñada la capa de identidad de la web para el mundo que ya estamos viviendo.

Mientras tanto, sigo midiendo retries, ajustando delays, y esperando que alguien proponga un RFC que valga la pena implementar. Si estás construyendo agentes que tocan la web real, instrumentá los bloqueos desde el primer deploy. Los números te van a decir cosas que no querés escuchar, pero es mejor saber que volar a ciegas.

Y si tenés métricas propias de esto, me interesa compararlas. Los datos agregados de muchos agentes distintos son lo único que va a convencer a los vendors de que necesitan un protocolo abierto.


Este artículo fue publicado originalmente en juanchi.dev

Top comments (0)