Un agente de IA acaba de visitar tu sitio. ¿Cómo sabes si es real?
Un User-Agent que dice GPTBot no prueba nada. Así se verifica de verdad un agente de IA, con rangos de IP publicados, DNS inverso y comprobación de ASN, y así se clasifica todo lo que no pasa el control.
Un agente de IA acaba de pedir una página y la línea de log dice GPTBot/1.2. Esa cadena no es
prueba de nada. El User-Agent lo escribe el propio cliente, así que puede enviarlo cualquiera, y la
única forma fiable de verificar un agente de IA es mirar la dirección desde la que se conectó. Tres
comprobaciones hacen el trabajo real: cotejar la IP de origen con el fichero de rangos publicado
por el operador, hacer una consulta de DNS inverso confirmada en ambos sentidos, o confirmar que la
IP la anuncia el propio ASN del operador.
Cuál de las tres se aplica depende por completo del operador, y ahí está la parte incómoda. OpenAI publica ficheros JSON de rangos por bot. Anthropic publica un único fichero de prefijos que cubre a la vez ClaudeBot, Claude-User y Claude-SearchBot. Apple admite tanto DNS inverso como fichero de rangos. Meta no publica ninguno de los dos y espera que compruebes AS32934. Muchos crawlers no publican nada, y entonces el nombre de la cabecera es decoración: decides por origen y comportamiento.
La afirmación es gratis, la comprobación no
Piensa en lo que dice realmente una regla de allowlist del tipo "si el User-Agent contiene GPTBot, salta las reglas antibot". Dice: cualquier cliente dispuesto a teclear nueve caracteres recibe el trato que reservabas a un crawler de confianza. Los scrapers leen tu robots.txt, ven qué agentes son bienvenidos y se visten en consecuencia. La suplantación no es ingeniosa, simplemente es barata, y funciona en cualquier sitio que nunca mire más allá de la cabecera.
La comprobación cuesta más. Necesitas los rangos actuales del operador, un resolutor DNS o datos de enrutado, operador por operador, actualizados cada vez que cambian. Ya se ha documentado tráfico que se presentaba como PerplexityBot desde direcciones fuera de los rangos publicados por Perplexity. Ese es exactamente el fallo: el nombre estaba prestado, la red no.
Comprueba de qué red vino realmente una petición de agente
Cada operador lo documenta de otra manera
No hay un estándar común, así que verificar es una consulta por operador. Una muestra del directorio de crawlers de IA, que sigue a 150 agentes:
| Agente | Operador | Qué publica | Cómo se verifica |
|---|---|---|---|
| GPTBot | OpenAI | openai.com/gptbot.json | Coincidencia de rangos IP, sin convención de DNS inverso |
| ClaudeBot | Anthropic | claude.com/crawling/bots.json | Coincidencia de prefijos, un fichero para todos los bots de Anthropic |
| PerplexityBot | Perplexity | perplexitybot.json | Coincidencia de rangos, suplantación ya documentada |
| Applebot | Apple | Fichero de rangos y rDNS | DNS inverso bajo applebot.apple.com, confirmado en ambos sentidos |
| Amazonbot | Amazon | Convención de DNS inverso | DNS inverso confirmado, sin fichero de rangos |
| Meta-ExternalAgent | Meta | Nada por bot | Confirmar que la IP la anuncia AS32934 |
| Bytespider | ByteDance | Nada | No verificable, e ignora robots.txt |
| CCBot | Common Crawl | Nada aprovechable | No verificable, corre sobre capacidad cloud alquilada |
| Google-Extended | Solo token de robots | Nada que verificar, nunca aparece como User-Agent |
Google-Extended merece una segunda mirada porque rompe el modelo mental habitual. Es una directiva de robots.txt para excluirse del entrenamiento de Gemini, no un crawler. Si llega una petición que dice ser Google-Extended, es falsa por definición. No existe una versión auténtica.
De los 150 agentes del directorio, 33 ofrecen una comprobación aprovechable mediante rangos publicados, DNS inverso o un ASN. Nueve están documentados como agentes que ignoran robots.txt sin más. El resto queda en medio: un nombre y nada que lo respalde.
Así se ve la suplantación en tus logs
Dos peticiones, la misma cabecera, con minutos de diferencia:
198.51.100.7 "Mozilla/5.0 ...; compatible; GPTBot/1.2; +https://openai.com/gptbot"
203.0.113.44 "Mozilla/5.0 ...; compatible; GPTBot/1.2; +https://openai.com/gptbot"
Nada en la línea las distingue. Resuelve las direcciones y la diferencia salta a la vista: una cae dentro de los rangos de salida publicados por OpenAI, la otra la anuncia un proveedor de hosting que alquila servidores por horas. La segunda, además, pidió 400 páginas de producto en noventa segundos y nunca cargó una hoja de estilos, algo que no hace ningún crawler que respete su propio presupuesto de rastreo publicado.
El patrón se repite en todos los operadores. Un ClaudeBot falso desde un rango de VPS. Un Applebot falso con un registro PTR que apunta al dominio de un hoster, o sin PTR alguno. Un Amazonbot falso cuyo PTR parece plausible hasta que la resolución directa devuelve otra dirección, que es precisamente para lo que existe el paso de confirmación. En todos los casos la cabecera encajaba a la perfección y la red no.
Verificado, no verificable y hostil son tres respuestas distintas
En cuanto dejas de tratar la cabecera como prueba, el tráfico se separa en grupos que piden tratamientos distintos, y una bandera binaria de bot no sabe expresar eso.
Un crawler de IA verificado es una decisión de política: permitirlo, cobrarlo, o bloquearlo por nombre porque no quieres tu contenido en ese corpus. Una petición que reclama un nombre y falla la comprobación de IP no es una decisión de política, es una falsificación, y nunca debería heredar el acceso que recibe el agente real. Un crawler sin nada publicado no se puede verificar y pide límites de tasa en lugar de un veredicto. Y un navegador headless desde un rango de centro de datos que no reclama ningún nombre de bot es justo el caso que tu allowlist nunca estuvo mirando.
Por eso Agentscan devuelve una clase en vez de un booleano. Cada petición vuelve como
human, known_bot, ai_agent o malicious_automation, con un valor de confianza y las señales
que produjeron el veredicto.
Las señales que sobreviven a un User-Agent falso
El origen de la IP responde a la mayor parte de la pregunta, pero no a toda. Un agente puede correr desde una dirección residencial, y un scraper puede alquilar una IP limpia sin historial. Otras tres señales aguantan cuando la cabecera miente:
Huella TLS JA4. El cliente revela cómo habla TLS antes de enviar una sola cabecera: orden de cifrados, extensiones, ALPN, versión. Un script de Python que se presenta como Chrome 124 produce un handshake que ninguna versión de Chrome ha producido jamás. La cabecera es una afirmación, el handshake es conducta.
Rastros de headless. La bandera webdriver, superficies del navegador ausentes y marcadores de
automatización de Playwright, Puppeteer o una build pelada de HeadlessChrome. Por separado cada uno
es débil. Junto a un origen de centro de datos, el cuadro deja de ser ambiguo.
Coherencia de cabeceras. Los navegadores reales envían Accept, Accept-Language y Accept-Encoding como conjunto, en orden estable y acorde con la versión que declaran. Los objetos de petición construidos a mano suelen enviar solo una parte, y esos huecos son lo bastante regulares como para servir de señal.
Ninguna señal decide por sí sola, y ese es el punto. Solo su combinación separa a un crawler verificado de un imitador competente, y a ambos de un visitante corriente. La misma lógica sirve para crawlers más antiguos, explicada en cómo verificar Googlebot.
Una política que aguanta el contacto con tráfico real
Verificar solo sirve si después pasa algo. Un punto de partida razonable:
- Contrasta la afirmación con el método del operador antes de que se dispare ninguna regla de allowlist. Fichero de rangos, DNS inverso o ASN, según lo que publique ese operador.
- Una verificación fallida no es una señal blanda. Una petición que dice ser ClaudeBot desde fuera de los prefijos de Anthropic es suplantación. Trátala como a cualquier scraper sin identificar, no como un quizá.
- Separa la decisión de permitir según la finalidad. Crawlers de entrenamiento, de búsqueda con IA y recolectores de asistentes merecen reglas propias. Bloquear un crawler de búsqueda te saca de las respuestas que ese motor cita, y eso es una decisión de tráfico, no de seguridad.
- Limita la tasa de lo no verificable. Con Bytespider, CCBot y todo lo demás sin comprobación publicada, el nombre no dice nada. El ritmo de peticiones, el patrón de rutas y el origen dicen bastante.
- Registra la clase, no solo el bloqueo. Saber que el tráfico de agentes de IA se triplicó el mes pasado vale más que un contador de peticiones bloqueadas, sobre todo cuando aún estás decidiendo qué monetizar.
Agentscan hace todo esto con un POST a /v1/agentscan/check: allowlist verificada por DNS inverso,
cotejo con rangos publicados, origen de la IP, banderas de headless y JA4 en una sola llamada, con
caché para que las consultas repetidas vuelvan en menos de 50 ms. Lo bastante rápido para vivir en
el middleware y no en una revisión nocturna de logs.
En resumen
No puedes verificar un agente de IA por cómo se llama a sí mismo. Contrasta la IP de origen con lo que el operador publica de verdad, trata una comprobación fallida como una falsificación, y usa JA4, los rastros de headless y el origen de la IP para todo aquello por lo que la allowlist no puede responder. La pregunta nunca fue "¿esto es un bot?". Es cuál de los cuatro tipos de tráfico acaba de llegar, y qué quieres hacer con cada uno.