Mi servidor ya distingue entre dos tipos de visitantes. Cuando un agente de IA pide una página con Accept: text/markdown, recibe Markdown limpio sin navegación ni scripts. Cuando un humano la pide con un navegador, recibe HTML completo con layout, imágenes y estilos. Mismo URL, dos versiones diferentes del mismo contenido.
Eso funciona. Pero tiene una limitación obvia: trata a todos los humanos como si fueran el mismo tipo de lector. Un desarrollador que llega desde Dev.to quiere ver código. Un diseñador que llega desde Dribbble quiere ver decisiones de UX. Un founder que llega desde Indie Hackers quiere ver implicaciones de negocio. Los tres reciben exactamente lo mismo.
Decidí experimentar con algo que nadie está documentando con código real: contenido que se adapta según señales disponibles en el request, sin frameworks de personalización, sin cookies de tracking, sin machine learning. Solo PHP leyendo lo que el navegador ya le dice.
Qué señales tiene un servidor PHP sin agregar nada
Antes de escribir una línea de código, hice inventario de las señales disponibles en un request HTTP estándar. Sin JavaScript, sin cookies, sin login. Solo lo que llega en los headers.
HTTP_ACCEPT_LANGUAGE revela el idioma preferido del navegador. Mi blog ya usa esto para redirigir a la versión correcta del contenido. Pero también revela la región: es-CO no es lo mismo que es-ES.
HTTP_REFERER muestra de dónde viene el visitante. Si viene de dev.to, probablemente es developer. Si viene de medium.com, probablemente es lector general. Si viene de google.com con una query técnica, quiere respuestas específicas.
HTTP_USER_AGENT identifica el navegador y el dispositivo. Mobile versus desktop cambia las prioridades de contenido. Un lector en móvil probablemente quiere la conclusión rápido. Un lector en desktop probablemente está dispuesto a leer el artículo completo.
La hora local del servidor da contexto temporal. No es lo mismo servir contenido a las 9 AM (modo trabajo, quiero eficiencia) que a las 11 PM (modo exploración, tengo tiempo).
El experimento: secciones colapsables por contexto
No cambié el contenido del artículo. Lo que hice fue cambiar qué secciones se muestran expandidas y cuáles colapsadas, usando la etiqueta HTML details que ya funciona sin JavaScript.
La lógica es simple. Si el referer contiene dev.to, github.com o stackoverflow.com, las secciones con bloques de código se renderizan expandidas y las secciones narrativas se colapsan. Si el referer contiene medium.com, linkedin.com o un dominio de noticias, las secciones narrativas se expanden y el código se colapsa. Si no hay referer o es directo, todo se muestra expandido como siempre.
function getReaderProfile(): string {
$referer = $_SERVER['HTTP_REFERER'] ?? '';
$devSources = ['dev.to', 'github.com', 'stackoverflow.com', 'hashnode.com', 'qiita.com'];
$generalSources = ['medium.com', 'linkedin.com', 'twitter.com', 'facebook.com'];
foreach ($devSources as $source) {
if (stripos($referer, $source) !== false) return 'developer';
}
foreach ($generalSources as $source) {
if (stripos($referer, $source) !== false) return 'general';
}
return 'default';
}
El contenido es idéntico. La jerarquía visual cambia. Un developer ve el código primero. Un lector general ve la narrativa primero. Nadie pierde información. La diferencia es qué se presenta como prioritario.
El problema del SEO y cómo lo resolví
El riesgo obvio es que Google vea contenido diferente al que ve el usuario. Eso es cloaking y Google lo penaliza. Pero lo que hago no es cloaking. Todo el contenido está en el HTML. Solo cambio el estado por defecto de los elementos details: abierto o cerrado. Google renderiza JavaScript y ve todo el contenido. La etiqueta details con o sin el atributo open no oculta contenido del indexador.
Para asegurarme, verifiqué con Google Search Console que todas las secciones siguen indexadas. Lo están. El contenido colapsado con details sigue siendo rastreable e indexable.
Lo que aprendí de este experimento
Tres observaciones después de dos semanas con este sistema activo.
Primera: el tiempo en página aumentó un 12% para visitantes que llegan desde plataformas de desarrollo. Ver código expandido primero reduce la fricción de decidir si el artículo es relevante para ellos.
Segunda: la tasa de rebote no cambió significativamente para ningún grupo. Esto confirma que colapsar secciones no se percibe como contenido faltante.
Tercera: la implementación completa tomó 45 minutos. No necesité ninguna librería, framework o servicio externo. PHP vanilla con una función de 20 líneas y un ajuste en el template.
El paso siguiente que aún no implementé
Lo que describí es el nivel más básico de contenido adaptativo. El nivel siguiente sería usar el Markdown for Agents que ya tengo para servir versiones semánticamente diferentes a agentes de IA. No solo Markdown versus HTML sino contenido reorganizado por prioridad para diferentes modelos.
ChatGPT absorbe contenido profundo con definiciones y evidencia. Perplexity prefiere contenido modular que puede descomponer en fragmentos. Google prioriza alineación semántica con la pregunta del usuario. Los datos del estudio de 602 prompts lo confirman.
La pregunta es si vale la pena servir versiones diferentes del mismo artículo a diferentes modelos de IA. Todavía no tengo respuesta. Pero la infraestructura para hacerlo ya existe en este blog.
El contenido más valioso no es estático. Es infraestructura que se adapta. Y la forma más honesta de hacerlo es con señales que el visitante ya está enviando, sin tracking invasivo, sin cookies, sin login obligatorio. Solo leyendo lo que el navegador ya dice.