Nuestra reserva de derechos frente al entrenamiento de IA estaba escrita para nadie.
La línea Content-Signal: search=yes, ai-input=yes, ai-train=no aparecía en el robots.txt de wppoland.com exactamente una vez, dentro del grupo User-agent: *, y debajo de ella había veinte grupos de rastreadores con nombre.
Según RFC 9309, ninguno de esos veinte grupos hereda nada del grupo del asterisco. GPTBot, ClaudeBot, PerplexityBot, Google-Extended y el resto de la lista leían solo su propia sección, y en ella esa línea no estaba.
Cada rastreador que nos habíamos molestado en nombrar a mano era justo el que no podía leer lo que habíamos escrito para él.
Escribimos sobre esto porque es nuestro fichero y nuestro fallo. Revisábamos el robots.txt para ver si bloqueaba algo por accidente, y nunca para ver si la declaración llegaba siquiera a su destinatario. Son dos preguntas distintas y solo la primera tiene una herramienta que la responda.
Qué había exactamente en el fichero
La estructura era la misma que vemos en la mayoría de ficheros: un grupo general arriba y debajo una lista de bots con nombre con reglas Allow ampliadas para los endpoints pensados para máquinas.
User-agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
Disallow: /cdn-cgi/
Sitemap: https://wppoland.com/sitemap-index.xml
Agentmap: https://wppoland.com/.well-known/ai-catalog.json
User-agent: GPTBot
Allow: /
Allow: /llms.txt
Allow: /facts.json
User-agent: ClaudeBot
Allow: /
User-agent: PerplexityBot
Allow: /Tiene buen aspecto. La señal está, los grupos con nombre están, los endpoints para agentes aparecen listados aparte.
El problema es que esas dos cosas no se tocan entre sí. Quien lee el fichero como documento ve una política arriba y unos permisos debajo, y añade mentalmente una relación entre ambas partes que el analizador no conoce.
El analizador no lee documentos: compara un token con una lista de nombres, se queda con el bloque que gana y tira el resto del fichero antes de haber leído una sola directiva.
Por qué una sola línea no cubre el fichero entero
El cliente compara su product token con los nombres de las líneas User-agent, sin distinguir mayúsculas de minúsculas, y aplica un grupo: el que lo nombra. El asterisco no es el patrón menos específico, es el recurso de reserva, y el RFC 9309 solo acude a él cuando ningún grupo nombra al cliente. Cuando existe un grupo con nombre, el cliente aplica solo sus directivas y el grupo del asterisco deja de afectarle por entero.
Esa última frase es el fallo completo. Se lee como evidente en la especificación y deja de serlo en cuanto la pones al lado de un fichero escrito por ti, porque un fichero escrito por ti lleva dentro tu intención, y la intención es invisible para el único lector que importa aquí.
Esto no es una excepción de Content Signals. La misma regla rige desde siempre para Allow y Disallow, y justo por eso un fichero en el que alguien añadió Disallow: /wp-admin/ solo al grupo del asterisco no protege nada frente a un bot que tiene su sección más abajo.
La diferencia está en lo que viene después. Con Disallow la consecuencia se ve: la página aparece en el índice o no aparece, y una semana de datos de indexación te dice cuál de las dos cosas pasó. Con Content-Signal no se ve nada, ni en un sentido ni en otro. Una declaración de derechos no tiene realimentación, así que una equivocada y una correcta producen el mismo historial observable durante todo el tiempo que quieras mirar.
Content Signals es una propuesta de Cloudflare, no parte de RFC 9309, y Cloudflare activa esa política por defecto en su robots.txt gestionado. El mecanismo de grupos donde vive esa línea, en cambio, es por completo el mecanismo de RFC 9309, de modo que la regla del grupo único le aplica igual que a todo lo demás en ese fichero. Una directiva nueva dentro de un contenedor viejo hereda las reglas del contenedor, incluidas las que nadie consultó al añadirla.
Tres señales y lo que no prometen
La especificación define tres señales, cada una con valor yes o no:
| Señal | A qué se refiere |
|---|---|
search | construir el índice de un buscador y devolver resultados, es decir enlaces y fragmentos breves |
ai-input | pasar el contenido a la entrada de un modelo de IA mientras responde, es decir RAG y fundamentación de la respuesta |
ai-train | entrenar y ajustar modelos |
Nuestro conjunto search=yes, ai-input=yes, ai-train=no es una elección consciente, y conviene decir en voz alta el compromiso que hay dentro. Queremos que se nos cite en respuestas generativas, porque hoy es uno de los canales por los que alguien nos encuentra. No queremos ceder el corpus para entrenamiento, porque un modelo entrenado se lleva el texto sin dejar camino de vuelta al sitio del que salió.
Decir que sí a lo primero y que no a lo segundo es aceptar que el mismo rastreador puede hacer los dos trabajos en días distintos, y fiarse de que distingue los días. La ausencia de señal significa algo distinto de no: quien opera el sitio ni concede permiso ni lo deniega por esa vía. El silencio, aquí, no es una negativa, y por eso existe la línea.
Ninguna de estas señales bloquea nada. Es una línea de texto en un fichero que el cliente puede descargar o no, leer o no y respetar o no. El servidor responde a la petición al margen de lo que ponga ahí.
El bloqueo es una capa aparte, evaluada antes de la aplicación, y se hace con reglas WAF, límites de peticiones o verificación de identidad del bot. Esa capa cuesta algo: corre en cada petición, puede equivocarse con una persona y hay que mantenerla según cambian las señales de identidad.
Una declaración no cuesta nada y no impone nada, lo cual es un intercambio razonable siempre que sepas cuál de las dos acabas de publicar. La señal vale exactamente lo que vale un mensaje inequívoco enviado a la dirección correcta. El nuestro era inequívoco y estaba enviado a la dirección equivocada.
Comprueba tu propio fichero con un comando
Lleva unos segundos y funciona con cualquier dominio:
curl -s https://tudominio.es/robots.txt \
| awk 'tolower($0) ~ /^user-agent:/ {ua++} tolower($0) ~ /^content-signal:/ {cs++} END {print "grupos User-agent: " ua "\nlineas Content-Signal: " cs}'Una advertencia antes de actuar sobre la salida: lo que cuenta son líneas User-agent y no grupos, y la ABNF de RFC 9309 permite varias líneas User-agent al abrir un mismo grupo, así que un fichero que apile nombres de esa forma acusará un desfase que no tiene.
Si el tuyo los apila, hazle caso a la lista del segundo comando y no a la aritmética del primero.
Si el número de grupos es mayor que el de señales, la diferencia dice cuántos grupos no ven tu reserva. En nuestro caso el resultado fue veintiuno contra uno.
La variante más precisa imprime los nombres de los grupos donde falta la señal:
curl -s https://tudominio.es/robots.txt \
| awk '/^[Uu]ser-agent:/ {if (name != "" && !sig) print "sin senal: " name; name=$2; sig=0} /^[Cc]ontent-[Ss]ignal:/ {sig=1} END {if (name != "" && !sig) print "sin senal: " name}'El segundo comando es el que conviene meter en el pipeline, porque su salida es una lista que arreglar y no un número que interpretar.
Cómo se arregla
La corrección es aburrida: repetir la línea Content-Signal en cada grupo al que deba aplicarse. No hay atajo, ni forma abreviada, ni herencia que se pueda activar.
User-agent: *
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
Disallow: /cdn-cgi/
User-agent: GPTBot
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
Allow: /llms.txt
Allow: /facts.json
User-agent: ClaudeBot
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /
User-agent: PerplexityBot
Content-Signal: search=yes, ai-input=yes, ai-train=no
Allow: /Ese cambio lo desplegamos el 18 de septiembre de 2026, el mismo día de publicación de este artículo. La señal está ahora en 18 grupos de 23, y los cinco que quedaron fuera son scrapers que ya tienen un Disallow por nuestra parte, donde un permiso solo enturbiaría lo que les estamos diciendo.
Al hacer la corrección hay que resolver una cosa que un fichero con la línea repetida no resuelve solo: si el mismo conjunto de señales encaja en todos los grupos. Para un rastreador que indexa y para uno que recoge corpus de entrenamiento la respuesta es distinta, y un fichero con veinte líneas idénticas sugiere que nadie se lo planteó.
El grupo donde search=yes no tiene sentido, porque el cliente no construye ningún índice, debería llevar su propia redacción, y es al escribirla cuando el fichero deja de ser una copia y pasa a ser una política.
Lo segundo que nos faltaba: grupos por rol
En esa misma lectura del fichero salió que teníamos solo el grupo ClaudeBot y no los otros dos: Claude-User, para las descargas que inicia una persona, y Claude-SearchBot, para la fundamentación de búsqueda. Son tres roles distintos y tres intenciones distintas del lado del cliente. Un bot que descarga una página porque alguien acaba de pegar su dirección en una conversación hace algo distinto que un bot que construye corpus, y tiene sentido responderle otra cosa.
El efecto de no tener esos grupos es el mismo de antes, solo que por el otro lado: un cliente sin sección propia cae en el grupo del asterisco. En nuestro caso eso significaba que Claude-User sí veía la señal correcta, porque en el asterisco estaba.
Es decir, en un fichero donde la señal no llegaba a veinte bots con nombre, sí llegaba a los que no tenían nombre. Justo lo contrario de lo que pretendíamos, y producido por la misma regla funcionando tal como está escrita.
Por qué este fallo sobrevive tan bien a una revisión
Tres razones, todas estructurales, ninguna es un descuido.
El robots.txt se lee de arriba abajo y la sección general parece la principal. Poner algo dentro de ella activa la intuición de CSS o de la configuración de un servidor, donde el ajuste general es el valor por defecto y el específico lo sobrescribe. En RFC 9309 no hay sobrescritura. Hay elección de un grupo y descarte del resto del fichero.
Segunda razón: no existe herramienta que avise. Los validadores de robots.txt comprueban si una URL está permitida para un bot dado, y de Content-Signal no saben nada, porque no es una directiva del RFC. La línea pasa como comentario a ojos del validador y como política a ojos de una persona, y cada lectura es coherente por separado.
Tercera, y la más importante: una declaración de derechos no tiene señal de retorno. Si pones mal un Disallow, en una semana lo ves en el informe de indexación.
Si pones mal un Content-Signal, no ocurre nada observable, y la ausencia de evento tiene el mismo aspecto en los dos casos. Esta clase de defectos hay que encontrarla leyendo el fichero, no mirando los efectos, y eso es incómodo de planificar, porque leer no tiene disparador.
Las líneas fuera de grupo confunden, porque esas sí valen globalmente
Hay en este fichero algo que empuja directamente hacia la intuición equivocada. Junto a los grupos User-agent, robots.txt admite registros independientes de grupo, y Sitemap es uno de ellos. En nuestro fichero está justo después del grupo del asterisco:
Sitemap: https://wppoland.com/sitemap-index.xml
Agentmap: https://wppoland.com/.well-known/ai-catalog.jsonSitemap rige todo el fichero al margen de dónde lo pongas y de cuántos grupos haya debajo. Nadie lo repite veinte veces y nadie tiene que hacerlo.
Quien sabe cómo se comporta Sitemap y ve un Content-Signal puesto en la misma zona del fichero, dos líneas más arriba, tiene todo el derecho a suponer que esa línea se comporta igual. No se comporta igual. Una es un registro global, la otra una directiva dentro de un grupo, y nada en la sintaxis lo indica. Ambas son una línea de dos partes con dos puntos, puestas una al lado de la otra.
Conclusión práctica al leer el fichero de otra persona: la sangría y el orden no significan nada, lo único que significa es si la directiva está definida como directiva de grupo. Allow, Disallow y Content-Signal lo son. Sitemap no.
Lo que este artículo no resuelve
Dejamos dos cosas fuera de alcance a propósito, porque no son nuestras.
La primera es el efecto jurídico de la reserva. Content Signals se apoya en una reserva de derechos expresada en derecho de autor, y ese texto está de hecho en un comentario en la cabecera de nuestro fichero.
Si esa reserva es eficaz, y cuándo, lo decide un abogado y no quien edita el robots.txt. Nuestra aportación es solo técnica: si la declaración ha de tener algún peso, al menos debe llegar al cliente al que va dirigida, y la nuestra no llegaba.
La segunda es el comportamiento de cada operador concreto. No medimos qué rastreador lee Content-Signal, cuál lo respeta y qué hace con señales incoherentes en grupos distintos. Sin medición propia no tenemos nada que decir aquí y no vamos a repetir cifras ajenas.
La corrección que describimos merece la pena al margen de ese conocimiento, porque arregla un fichero que dice algo distinto de lo que su autor pretendía, y eso ya es un defecto por sí mismo.
Qué hacer con esto en el proceso
Comprobar el alcance de la señal es un trabajo de unos minutos que se hace una vez, pero mantenerlo no es cosa de una sola vez. Cada grupo nuevo que se añade al fichero, y se añaden con regularidad porque la lista de rastreadores de IA crece mes a mes, es un grupo sin señal hasta que alguien se acuerda de ella.
Por eso el segundo de los comandos de arriba tiene que acabar en los tests y no en una nota. Una regla que se comprueba sola sobrevive; una regla escrita en un documento sobrevive hasta la siguiente edición del fichero por alguien que no leyó ese documento.
Conviene recordar también de qué parte del tráfico estamos hablando. En nuestra medición de agosto de 2026, descrita en el artículo sobre tráfico de bots en un sitio pequeño, el 72% de las peticiones no venía de un navegador. El robots.txt es el único sitio donde hablamos con esa mayoría, y lo único que esa mayoría sabe de nuestras condiciones. Si la frase que contiene va dirigida al grupo equivocado, no es un fallo blando, es silencio.
Quien sale ganando con este arreglo no somos en primer lugar nosotros. Es quien edita el sitio y tiene que poder responder qué se permite en él, quien lo asesora legalmente y necesita leer una declaración sin ambigüedad, y quien añada mañana un grupo nuevo de rastreador y necesite que el fichero diga lo que parece decir.
Lista de comprobación corta
- Cuenta los grupos
User-agenty las líneasContent-Signalde tu fichero. Si los números no cuadran, la diferencia son grupos sin reserva. - Repite la línea en cada grupo al que deba aplicarse. La repetición es aquí la forma correcta, no un duplicado.
- Decide de forma consciente si cada grupo recibe el mismo conjunto de señales. Veinte líneas idénticas suelen indicar que nadie decidió nada.
- Comprueba si tienes grupos separados para los roles de un mismo proveedor, por ejemplo para la descarga que inicia una persona y para la recogida de corpus.
- Mete la comprobación en el pipeline. La lista de rastreadores crece y cada grupo añadido arranca sin señal.
- No te cuentes que la señal bloquea algo. El bloqueo es una capa anterior a la aplicación, y esto es una declaración.







