Casi todo lo que se escribe sobre tráfico de bots es o un argumentario de proveedor o una batallita de un sitio lo bastante grande como para ser atacado a propósito. Esto no es ni una cosa ni la otra. Es el sitio de una agencia pequeña, una cuenta de Cloudflare y los números que encontramos cuando por fin miramos en serio.
La versión corta: el 72,4% de las peticiones a nuestro sitio durante 23 horas no llevaba ningún user agent de navegador reconocible. Chrome supuso el 19,7%. Todos los rastreadores de búsqueda conocidos juntos, Googlebot y Bingbot y Applebot, sumaron el 3,5%.
Ese último número es el que reorganizó nuestra forma de pensar. Casi todos los argumentos que uno lee sobre gestión de rastreadores hablan de la minoría conocida, y esa minoría es un error de redondeo al lado de todo lo demás que llama a la puerta.
Qué medimos en realidad
Todas las cifras vienen de la analítica GraphQL de Cloudflare para nuestra propia zona, en una ventana de 23 horas de agosto de 2026. Aquí no hay nada modelado ni extrapolado.
| Cliente | Peticiones | Cuota |
|---|---|---|
| No reconocido | 42 700 | 72,4% |
| Chrome | 11 628 | 19,7% |
| Bingbot | 1 523 | 2,6% |
| Edge | 1 064 | 1,8% |
| Firefox | 523 | 0,9% |
| Googlebot | 362 | 0,6% |
| Chrome Mobile | 318 | 0,5% |
| Safari | 301 | 0,5% |
| Applebot | 172 | 0,3% |
| curl | 118 | 0,2% |
A lo largo de dos días completos, la proporción entre peticiones y visitantes únicos se situó en 6,5 y 6,6. Una persona que lee dos o tres páginas no genera seis peticiones y media una vez excluidos los recursos, que es la misma historia vista desde otro ángulo.
Ya habíamos visto una versión extrema de esto a principios de mes. Un día las peticiones se triplicaron hasta 173 093 mientras los visitantes únicos se quedaban planos en 7 527. Peticiones triplicadas con una audiencia plana no es crecimiento, es un barrido, y la distribución por rutas lo confirmó: la URL individual más visitada se llevó solo 677 peticiones de ese total. Algo recorrió el corpus entero.
La palabra “bots” carga aquí con demasiado
Podemos demostrar que esos clientes no se presentan como navegadores. No podemos demostrar qué son, y nadie que ejecute la misma consulta puede hacerlo.
Esa categoría contiene monitores de disponibilidad que pagamos, verificadores de enlaces, librerías HTTP dentro del script de alguien, escáneres de seguridad, lectores de feeds, rastreadores de IA construyendo conjuntos de entrenamiento y agentes que traen una página en nombre de una persona que hizo una pregunta. Parte de ese tráfico nos resulta útil. Parte es indiferente. Una pequeña parte es hostil.
Así que el titular honesto no es “el 72% de nuestro tráfico son bots atacándonos”. Es el 72% de nuestro tráfico no ejecuta un navegador, y esa distinción cambia lo que conviene hacer al respecto.
Lo que no encontramos
Primero fuimos a buscar un problema en robots.txt, porque es lo más barato de comprobar y es un defecto realmente común: robots.txt se sirve por protocolo y por subdominio, así que http, www y el ápex pueden contradecirse sin que nadie lo note. Los nuestros eran idénticos, byte a byte, todos redirigiendo a una única dirección canónica.
Vale la pena decirlo con claridad, porque un resultado limpio también es un resultado. Si hubiéramos publicado solo lo que arreglamos, te llevarías una idea distorsionada de con qué frecuencia este trabajo encuentra algo.
Lo otro que conviene afirmar: robots.txt no reduce la carga. Es una petición de cooperación dirigida a los clientes que lo leen. Todo lo que lo ignora sigue llegando a tu servidor y sigue consumiendo lo que se ejecute en la ruta de la petición. Las capas que de verdad reducen carga son las que se evalúan antes de que corra el código de tu aplicación.
Este texto trata de lo que llega al servidor, es decir, la capa que un desarrollador WordPress tiene que diseñar.
El hallazgo que no esperábamos: nuestra caché nunca había funcionado
Mientras sacábamos estos números nos fijamos en la tasa de aciertos de la caché de borde: alrededor del 4%, en un sitio donde cada página se pregenera en tiempo de compilación. Debería ser casi lo contrario.
Cada página envía esto:
cache-control: public, max-age=60, s-maxage=3600, stale-while-revalidate=86400
Y cada página volvía con cf-cache-status: DYNAMIC. Pedíamos una hora de caché en el borde y no la habíamos recibido ni una sola vez.
Dos causas, y solo juntas lo explican.
Cloudflare no cachea HTML por defecto. El nivel de caché predeterminado cubre una lista de extensiones estáticas, y HTML no está en ella, diga lo que diga tu origen. Enviar s-maxage no vuelve cacheable el HTML; lo hace una regla de caché.
Nuestra propia funcionalidad bloqueó el resto. Servimos una representación en Markdown de cada página a los agentes que la piden con Accept: text/markdown. Eso significa que una URL tiene dos representaciones. Para que una caché sea segura, la clave de caché debe incluir Accept, y la clave de caché estándar de Cloudflare solo incluye Vary: Accept-Encoding. Activar la caché de forma ingenua acabaría entregando a un agente una página HTML cacheada, o entregando a una persona Markdown cacheado, que es peor que no tener caché.
Esta es la parte que merece generalizarse: el coste era invisible porque pertenecía a una funcionalidad de la que estábamos orgullosos. Nadie audita el precio de su propia buena idea.
El arreglo fue una regla de caché condicionada a la cabecera de la petición: cachear páginas, pero solo cuando Accept no pide Markdown. Así la clave de caché nunca necesita llevar Accept, porque las peticiones que negocian quedan excluidas por completo de la caché. Son alrededor de cien al día frente a decenas de miles de vistas de página normales.
Viene con una segunda mitad que no es opcional: purgar la caché en cada despliegue. Sin eso, cada despliegue deja hasta una hora de páginas obsoletas para parte de la audiencia, y lo siguiente que oyes es que un cambio no se ve. Una regla de caché sin paso de purga es una trampa que te pones a ti mismo.
Por qué esto va de resiliencia y no de velocidad
Con max-age=60, la caché de borde cambia poco para una persona que vuelve. Lo que cambia es lo que ocurre cuando algo barre tu sitio entero.
Nuestras páginas pasan por una función de borde en cada petición HTML, y el plan gratuito permite 100 000 invocaciones de función al día. El día mediano ronda las 30 000. El día de aquel barrido llegó a 131 255, que está por encima del techo.
Así que la caché nunca fue un lujo de rendimiento. Era la diferencia entre que un rastreo sea invisible y que un rastreo tire el sitio. Ese cambio de encuadre solo estuvo disponible cuando la cuota de bots y la tasa de caché quedaron en la misma página.
El endpoint que estuvo roto durante semanas
Mantenemos un contador aparte para la superficie legible por máquinas, porque la analítica de navegador no la ve: un agente que descarga un fichero JSON no ejecuta JavaScript, así que una herramienta de analítica basada en un beacon no reporta absolutamente nada.
Ese contador dice unas 102 peticiones de agentes al día. La distribución nos sorprendió: dos tercios van a nuestro endpoint MCP, no a las tarjetas declarativas como agent.json o llms.txt, que se llevan toda la atención en la conversación sobre visibilidad ante la IA.
Luego nos dijo algo peor. La dirección sin barra final estaba respondiendo 301. Una redirección convierte un POST en un GET y descarta el cuerpo de la petición, así que un cliente JSON-RPC o no recibe nada o recibe un error de análisis. Medido a lo largo de un día: 29 llamadas rotas frente a 2 que funcionaron.
Teníamos un endpoint público para agentes que estaba, para una buena parte de los clientes, sencillamente roto, y no nos habríamos enterado. No aparece en ningún panel que mire un responsable de marketing. No generó ningún error que nadie viera, porque a quienes les falló no eran personas.
Tres intentos de arreglarlo en la aplicación fracasaron, porque la normalización de la barra final que hace la plataforma ocurre antes de que corra el código de la aplicación. El arreglo tenía que ir por encima de la causa, como regla de reescritura en el borde de la red. Al día siguiente: 12 respuestas POST correctas donde no había habido ninguna.
Cómo hacer esta medición tú mismo
Nada de esto necesitó una herramienta de pago. El endpoint de analítica GraphQL de Cloudflare responde a todo, y el ejercicio entero se reduce a un token de API y un puñado de consultas.
Dos trampas nos costaron tiempo, así que merecen nombre.
El permiso del token no es el obvio. Nuestro token de API de siempre podía desplegar, purgar y gestionar reglas, y devolvía un error de permisos en cada consulta de analítica. La analítica necesita Zone / Analytics / Read en concreto, y un token puede ser perfectamente capaz de cambiar tu sitio sin poder contarte nada sobre él. Peor aún, un token con ámbito de cuenta puede fallar la comprobación habitual en /user/tokens/verify mientras funciona correctamente con GraphQL, así que pruébalo con una consulta real en lugar de con el endpoint de verificación.
La ventana temporal tiene tope. En nuestro plan, el conjunto de datos de peticiones adaptativas rechaza cualquier consulta que abarque más de un día y guarda alrededor de tres días de historial. Pide treinta días y no obtienes una respuesta parcial, obtienes un error. Recorre día a día y agrega en el cliente.
La forma de consulta que produjo la tabla de user agents es pequeña:
{ viewer { zones(filter: {zoneTag: "YOUR_ZONE_ID"}) {
httpRequestsAdaptiveGroups(
limit: 12,
filter: {datetime_geq: "2026-08-19T15:00:00Z"},
orderBy: [count_DESC]
) { count dimensions { userAgentBrowser } }
} } }
Cambia userAgentBrowser por cacheStatus, edgeResponseStatus, clientRequestPath o clientCountryName y tienes el resto del cuadro. Para peticiones frente a visitantes únicos, httpRequests1dGroups lleva ambas cosas en una misma fila.
Una advertencia que importa al leer tus propios resultados: userAgentBrowser es la clasificación de Cloudflare, no la verdad de campo. “No reconocido” significa que su analizador no encontró una firma de navegador conocida. Un rastreador que envía una cadena de user agent de Chrome se cuenta como Chrome, así que la cuota real de tráfico sin navegador es un suelo, no un techo.
Qué decidimos no hacer, y por qué
El siguiente movimiento obvio después de encontrar un 72% es empezar a bloquear. No lo hicimos, y el razonamiento vale más que la decisión.
No añadimos reglas de WAF ni limitación de tasa. Ambas funcionarían y ambas están en la capa correcta, antes del código de la aplicación. Pero no teníamos pruebas de daño. Nada estaba caído, nada iba lento para las personas y no se estaba pagando ningún coste que una regla de caché no pudiera quitar más barato. Bloquear tráfico que no has demostrado dañino cambia un riesgo real, dejar fuera algo de lo que dependes, por uno hipotético.
No perseguimos un error que se estaba arreglando solo. A mitad de este trabajo encontramos 9 956 tiempos de espera agotados de pasarela en un día, repartidos por todo el sitio, incluidas las páginas de contacto en todos los idiomas. Parecía una emergencia. Después el desglose mostró que todos y cada uno llevaban un user agent no reconocido: cero de Chrome, Safari, Googlebot o Bingbot. Ninguna persona y ningún motor de búsqueda vio uno solo. Lo anotamos y lo dejamos en paz. Un día después la misma ventana mostraba tres. Si lo hubiéramos “arreglado”, habríamos arreglado el rastreador de otro y enviado a nuestro propio código un cambio que no curaba nada.
No financiamos el trabajo caro sobre agentes. El mismo contador que encontró el endpoint roto también nos puso precio a una lista de pendientes. Documentos de identidad firmados, atestaciones de terceros, un entorno aislado, un contrato legible por máquinas: cada uno son semanas de trabajo, y cada uno se justifica por el supuesto de que los agentes que compran leen nuestros ficheros declarativos. Con 26 peticiones al día a agent.json, ese supuesto no sobrevive al contacto con el contador. Dos mediciones independientes con un día de diferencia coincidieron, así que la decisión descansa ahora sobre una medición y no sobre una lectura única.
El patrón en los tres casos es el mismo. Medir da derecho a no hacer nada, y es un uso de los datos que recibe mucho menos crédito del que merece. La mayor parte del valor que sacamos de este ejercicio no fueron los dos arreglos. Fue saber cuál de los números alarmantes merecía nuestra semana.
Qué le diríamos a quien haga esto en su propio sitio
Mide antes de bloquear nada. Saca el desglose por user agent de un día completo. La proporción entre peticiones y visitantes únicos es la comprobación de cordura más rápida, y si está muy por encima de dos o tres, mira más de cerca.
Comprueba el estado de tu caché, no tus cabeceras de caché. cache-control es una petición. cf-cache-status, o el equivalente de tu CDN, es la respuesta. Pasamos mucho tiempo creyendo en una cabecera que no había surtido efecto ni una sola vez.
Cuenta el tráfico que tu analítica no puede ver. Si tu visibilidad ante los agentes de IA te importa algo, el único sitio donde aparece ese tráfico son los registros del servidor o del borde. Los nuestros revelaron un endpoint roto que llevaba semanas fallando en silencio.
Ten cuidado con lo que llamas ataque. La mayor parte de lo que encontramos no era ni malicioso ni útil. Era indiferente. La respuesta útil al tráfico indiferente es hacerlo barato de servir, no pelearse con él.
Audita el coste de tus propias funcionalidades. Lo más caro que encontramos no fue un bot. Fue una funcionalidad que construimos a propósito, valorada en cero, que nos estaba costando la totalidad de la caché de borde del HTML.







