Cómo bloquear (o dejar pasar) agentes de IA en tu web: robots.txt, nginx y firmas
El agente de IA no pide permiso: o le escribes las reglas, o tu web las decide por defecto. Estas son las cuatro capas que existen hoy para bloquear agentes de IA sin romper el tráfico que sí quieres, con código y con lo que cada capa no puede hacer.
El caso de United y sus reservas puso el tema en los titulares, pero la decisión de fondo es la misma para un blog, una tienda o una API: quién puede actuar en tu web y con qué prueba. Y la mayoría de los sitios sigue sin tener nada escrito al respecto.
Qué es (y qué no es) un agente para tu servidor
Desde el servidor, tres cosas distintas llegan pareciéndose mucho, y la respuesta técnica cambia según cuál sea.
El primero es el crawler de entrenamiento: lee tu contenido para alimentar un modelo. No le importa tu negocio ni tu sesión; solo quiere el texto. Al segundo, el buscador con IA, le interesa citar tu página en una respuesta: si lo bloqueas, desapareces de esa superficie. El tercero es el agente que actúa: entra con una sesión, rellena formularios, cambia una reserva, paga. Ese no es un lector, es un usuario automatizado.
Lee también
La regla práctica es simple: al que lee se le pone una política, al que busca se le identifica, y al que actúa se le da una API. Mezclar los tres en un solo bloqueo es el error más común, y es el que después rompe el tráfico de búsqueda.
Los user-agents que importan en 2026
Estos son los que conviene conocer por nombre, empresa y función:
- GPTBot (OpenAI): entrenamiento.
- OAI-SearchBot (OpenAI): indexación para respuestas de búsqueda.
- ChatGPT-User (OpenAI): visita lanzada por una persona desde el chat.
- ClaudeBot y anthropic-ai (Anthropic): entrenamiento.
- Claude-SearchBot (Anthropic): búsqueda.
- Google-Extended (Google): uso del contenido para entrenamiento y grounding de Gemini.
- PerplexityBot (Perplexity): indexación para su buscador.
- CCBot (Common Crawl): corpus abierto que muchos modelos usan después.
- Bytespider (ByteDance): rastreo masivo, históricamente poco respetuoso con los límites.
Un detalle que se malinterpreta mucho: bloquear Google-Extended no saca tu web de Google ni cambia la indexación de Googlebot. Solo afecta al uso del contenido para entrenar y para fundamentar respuestas de Gemini. Son dos permisos distintos y se gestionan por separado.
Capa 1: robots.txt, la regla que nadie está obligado a cumplir
robots.txt es el estándar RFC 9309 y funciona por acuerdo voluntario. Un bot puede ignorarlo sin consecuencias técnicas: no hay autenticación ni sanción. Sirve para declarar intención y para que los proveedores serios la respeten, no para impedir el acceso.
Aun así es la primera capa porque es la única que ve todo el mundo, incluidos los auditores de SEO. Y permite algo valioso: separar entrenamiento de búsqueda. Bloquear GPTBot y permitir OAI-SearchBot es una decisión perfectamente válida y bastante habitual.
# Entrenamiento fuera, busqueda con IA dentro
User-agent: GPTBot
Disallow: /
User-agent: ClaudeBot
Disallow: /
User-agent: Google-Extended
Disallow: /
User-agent: CCBot
Disallow: /
User-agent: ByteSpider
Disallow: /
User-agent: OAI-SearchBot
Allow: /
User-agent: Claude-SearchBot
Allow: /
User-agent: PerplexityBot
Allow: /
Sitemap: https://tuweb.com/sitemap.xml
Cada bloque User-agent abre un grupo con sus propias reglas, así que no hay que mezclar directivas de bots distintos en el mismo grupo. El archivo va en la raíz del dominio, se sirve como text/plain y tiene que responder 200: un 404 o una redirección lo dejan sin efecto.
Cómo comprobar que tus reglas hacen algo
Primero, que el archivo se sirva como esperas:
curl -sI https://tuweb.com/robots.txt
curl -s https://tuweb.com/robots.txt | head -20
Segundo, que no lo tape una caché, una CDN o un rewrite del framework. Si el 200 llega con el HTML de la portada, tienes un problema de rutas y no de contenido. Y tercero, la prueba de verdad: mirar los logs. Si el bot vuelve igual de seguido después de la regla, la regla es decorativa.
Capa 2: nginx y el user-agent que miente
Aquí ya se corta de verdad, con una advertencia: el user-agent es un comentario, no una credencial. Cualquiera puede escribir "GPTBot" en su cliente, y cualquier bot puede escribir el user-agent de Chrome. Sirve para filtrar lo declarado y para frenar scrapers simples, no para distinguir actores.
El bloque va en el contexto http, no dentro de server. Ese es el error típico: map solo se declara una vez en http {}.
http {
map $http_user_agent $agent_block {
default 0;
"~*GPTBot" 1;
"~*ClaudeBot" 1;
"~*CCBot" 1;
"~*Bytespider" 1;
}
limit_req_zone $binary_remote_addr zone=agents:10m rate=10r/s;
}
Y en el servidor del sitio, la consecuencia:
server {
server_name tuweb.com;
if ($agent_block) {
return 403;
}
location / {
limit_req zone=agents burst=20 nodelay;
try_files $uri $uri/ /index.php?$query_string;
}
}
El bloque, línea por línea
map compara el user-agent con patrones y devuelve un valor: ~* significa coincidencia con expresiones regulares sin distinguir mayúsculas. La variable $agent_block queda en 1 para los bots listados y en 0 para el resto.
if ($agent_block) { return 403; } es una excepción aceptable a la famosa norma de no usar if en nginx: return es una de las directivas que se comportan bien dentro de un bloque condicional. Lo que no conviene es meter proxy_pass o rewrite ahí.
limit_req_zone define una zona compartida por IP con un límite de diez peticiones por segundo; limit_req la aplica con una ráfaga de veinte y sin cola. Es la parte que de verdad protege el servidor cuando alguien decide ignorar el 403, y por eso conviene que exista incluso si no bloqueas a nadie.
El coste de bloquear de más es real: si tu patrón es demasiado amplio, te llevas por delante navegadores legítimos, herramientas de monitorización o el tráfico de buscadores con IA que te mandaba visitas. El de bloquear de menos también: ancho de banda, base de datos y factura.
Capa 3: Laravel 13, middleware y rate limit
La aplicación es el único sitio donde sabes si hay una sesión detrás. Eso la convierte en la mejor barrera: un agente que actúa en nombre de un usuario necesita esa sesión, y ahí puedes exigir login, verificación en dos pasos o permisos.
El middleware corta por user-agent declarado. Es la misma lógica que nginx, pero con contexto: puedes registrar el intento, responder con un JSON distinto o dejar pasar solo las rutas públicas.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;
class BlockDeclaredAgents
{
private const BLOCKED = ['GPTBot', 'ClaudeBot', 'CCBot', 'Bytespider'];
public function handle(Request $request, Closure $next): Response
{
$agent = $request->userAgent() ?? '';
foreach (self::BLOCKED as $needle) {
if (stripos($agent, $needle) !== false) {
abort(403, 'Automated access not allowed');
}
}
return $next($request);
}
}
Se registra en bootstrap/app.php, dentro de withMiddleware(), con $middleware->append(...) si quieres que corra en todas las peticiones o con $middleware->alias(['agents' => ...]) para aplicarlo solo donde toca.
Y para el volumen, el limitador de Laravel:
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\RateLimiter;
public function boot(): void
{
RateLimiter::for('agents', function (Request $request) {
return Limit::perMinute(30)
->by($request->ip())
->response(fn () => response('Too many requests', 429));
});
}
Con eso, la ruta queda protegida con Route::middleware('throttle:agents'). Si ya tienes límites por usuario, este es el complemento por IP, no el reemplazo. Y una cosa que no hay que hacer: bloquear rangos de IP de datacenter completos. Rompes servicios legítimos, te rompes a ti mismo detrás de una VPN y el bot pasa por otro proveedor en diez minutos.
Código: middleware y RateLimiter trabajando juntos
El orden recomendado es middleware propio primero, limitador después. Así el bot declarado recibe un 403 barato, sin tocar la base de datos, y el tráfico anónimo excesivo cae en el 429 del limitador. Si quieres profundizar en el limitador, el blog ya tiene una guía de rate limiting en Laravel 13 con más ejemplos por ruta y por usuario.
Capa 4: agentes firmados (Web Bot Auth)
Ninguna de las tres capas anteriores responde a la pregunta importante: ¿este agente es quien dice ser? Web Bot Auth lo intenta con firmas criptográficas sobre HTTP Message Signatures, el RFC 9421, y un par de claves Ed25519.
El agente firma cada petición y envía las cabeceras Signature-Input y Signature; de forma opcional, Signature-Agent indica al sitio dónde publica su clave pública para que pueda verificarla. El borrador es de Cloudflare (draft-cloudflare-web-bot-auth) y la compañía ya trata a los agentes firmados como verificados en su red. Del lado del servidor, lo que puedes hacer hoy es verificar la firma y marcar la petición como identificada, sin depender de un tercero: en PHP, la extensión sodium ofrece sodium_crypto_sign_verify_detached(), que es exactamente la operación que necesitas cuando ya tienes la clave pública del agente.
Esto no bloquea a nadie. Cambia la conversación: pasas de "qué dice ser" a "qué puede demostrar". Un agente firmado con clave verificada merece un límite distinto, y uno que se declara GPTBot sin firma merece el mismo trato que un desconocido.
Antes de bloquear, mide
Dos comandos sobre el log de acceso te dicen más que cualquier lista:
awk -F'"' '{print $6}' access.log | sort | uniq -c | sort -rn | head -20
grep -c "GPTBot" access.log
El primero agrupa peticiones por user-agent (en formato combinado, el agente es el campo posterior a las comillas del referer). El segundo cuenta cuántas veces apareció un bot concreto. Con eso respondes tres preguntas antes de tocar nada: cuánto tráfico aporta cada agente, qué rutas toca y si ese tráfico convierte o solo consume.
La decisión cambia según el tipo de contenido. En páginas con anuncios, el crawler de entrenamiento no te paga nada y sí cuesta ancho de banda. En un catálogo, el agente de búsqueda puede ser tu mejor canal de descubrimiento. En un área privada, la respuesta no es una regla de servidor: es login. Y en una API, la respuesta es una clave, no un user-agent.
Conclusión
robots.txt es la política, el servidor es la puerta, la aplicación es el portero y la firma es el documento de identidad. Cada capa resuelve una parte y ninguna resuelve todo: por eso se suman en vez de sustituirse. Y si algo hay que llevarse de todo esto, es que el agente ya no es un experimento: es un cliente con reglas, y las reglas se escriben antes de que llegue.
En el blog seguimos con esta línea: cómo se conectan las herramientas a un modelo con MCP, cómo se apaga un agente descontrolado con el kill switch de CrowdStrike, y qué se puede medir del tráfico de servidores con HTTP/3 en nginx.

