Los agentes de Inteligencia Artificial que navegan la web —desde asistentes que rellenan formularios hasta automatizaciones con navegadores headless— se están topando con una realidad incómoda: la mayoría de interfaces modernas están diseñadas para ojos humanos, no para sistemas que “leen” estructura. Y, en ese choque, el HTML semántico y la accesibilidad han dejado de ser solo un tema de inclusión o cumplimiento: empiezan a comportarse como una capa de compatibilidad operativa.
La industria académica lleva tiempo midiendo el problema. En WebArena, por ejemplo, incluso un agente basado en GPT-4 se queda en un 14,41 % de éxito end-to-end frente a un 78,24 % humano en tareas web realistas. Es decir: no es “que los agentes sean tontos”, es que la web real está llena de ruido, ambigüedad y patrones que rompen la comprensión. Y cuando una página no está bien estructurada, un agente falla igual que lo haría un lector de pantalla: botones sin nombre, formularios sin etiquetas, componentes que parecen interactivos pero no lo son, estados dinámicos que nunca se anuncian.
A continuación, una versión práctica (y pensada para equipos de desarrollo y de sistemas) de cómo preparar sitios para esta nueva clase de visitantes.
Tres árboles que importan (más de lo que parece)
En la práctica, muchos agentes acaban apoyándose —directa o indirectamente— en tres representaciones:
- DOM: lo que el servidor entrega y el navegador construye.
- Árbol de accesibilidad: roles, nombres accesibles, relaciones y estados que consumen tecnologías asistivas (y que también pueden inspeccionarse en automatización).
- Extracción/simplificación: “reader mode”, conversión a texto/Markdown o resúmenes estructurados para reducir tokens y ruido.
La tendencia es clara: cuanto más “legible” sea el HTML para el árbol de accesibilidad, menos fricción hay para los agentes basados en DOM (y para pruebas automáticas), y menos ambiguo es el contenido cuando se simplifica.
1) Semántica nativa primero: menos ARIA, más HTML
La regla práctica es conocida: si existe un elemento HTML nativo que ya expresa lo que se necesita, se usa ese elemento. Incluso documentación divulgativa en MDN lo resume como “la primera regla de ARIA”.
Bien:
<button type="button" class="btn" aria-pressed="false">
Reproducir
</button>
Lenguaje del código: HTML, XML (xml)
Mal (patrón frecuente en SPAs):
<div class="btn" onclick="play()" role="button" tabindex="0">
Reproducir
</div>
Lenguaje del código: HTML, XML (xml)
¿Por qué falla lo segundo?
- Suele romper navegación por teclado (Enter/Espacio), foco, estados y expectativas del árbol de accesibilidad.
- Obliga a “parchear” con ARIA cosas que el navegador ya resuelve con un
<button>real. - Hace más frágil la automatización: el agente detecta un “button” a medias, pero no siempre puede activarlo de forma fiable.
Y además, ARIA en HTML tiene reglas de conformidad: no todo vale en cualquier elemento.
2) Nombres accesibles: el agente no puede clicar lo que no puede nombrar
Para un agente basado en DOM/Accesibilidad, el concepto clave es el nombre accesible. Si un control no tiene un nombre claro, es casi “invisible” o ambiguo.
Formularios: <label> como opción por defecto
<label for="email">Correo electrónico</label>
<input id="email" name="email" type="email" autocomplete="email" required>
Lenguaje del código: HTML, XML (xml)
Iconos: aria-label y ocultar el decorado
<button type="submit" aria-label="Buscar">
<svg aria-hidden="true" focusable="false" viewBox="0 0 24 24">
<!-- lupa -->
</svg>
</button>
Lenguaje del código: HTML, XML (xml)
Componer nombres con aria-labelledby
Ideal cuando se quiere que el botón “herede” contexto (precio, plan, artículo…):
<p id="plan">Plan Pro</p>
<p id="precio">29,99 € al mes</p>
<button aria-labelledby="plan precio">
Contratar
</button>
Lenguaje del código: HTML, XML (xml)
La propia guía de prácticas de WAI-ARIA dedica secciones completas a “names and descriptions” porque es uno de los puntos donde más se rompe la web para tecnologías asistivas… y, por extensión, para agentes.
3) Estados y cambios dinámicos: si no se anuncia, no existe
Las interfaces modernas viven de estados: “cargando”, “sin resultados”, “error”, “añadido al carrito”. Para humanos, el cambio visual basta. Para accesibilidad y agentes, hay que exponer el cambio.
Ejemplo típico de resultados de búsqueda:
<div id="status" aria-live="polite" aria-atomic="true"></div>
<ul id="results" aria-busy="true"></ul>
<script>
async function load() {
document.getElementById("results").setAttribute("aria-busy", "true");
document.getElementById("status").textContent = "Cargando resultados…";
// fetch...
document.getElementById("results").setAttribute("aria-busy", "false");
document.getElementById("status").textContent = "42 resultados";
}
</script>
Lenguaje del código: HTML, XML (xml)
Esto ayuda a:
- lectores de pantalla,
- pruebas E2E,
- agentes que esperan señales explícitas en el árbol de accesibilidad.
4) Diálogos y modales: el gran punto de fallo en automatización
Los modales mal implementados son uno de los motivos más comunes de “bloqueo” en agentes (y también en usuarios). La guía oficial de patrones para dialog modal marca requisitos como aria-modal, foco inicial, y control del contenido de fondo.
Ejemplo base:
<div role="dialog" aria-modal="true" aria-labelledby="title" id="subscribe">
<h2 id="title">Suscripción</h2>
<p>Acceso completo a la plataforma.</p>
<button type="button" aria-label="Cerrar">×</button>
<button type="button">Continuar</button>
</div>
Lenguaje del código: HTML, XML (xml)
“Bloquear” el fondo: inert (y por qué también interesa a sistemas)
inert permite hacer no interactiva una región completa mientras el modal está activo. Está documentado tanto en MDN como en el propio estándar HTML, y web.dev lo explica con ejemplos operativos.
<main id="app">…</main>
<div id="modal" role="dialog" aria-modal="true">…</div>
<script>
document.getElementById("app").setAttribute("inert", "");
// al cerrar modal:
document.getElementById("app").removeAttribute("inert");
</script>
Lenguaje del código: HTML, XML (xml)
Para agentes, esto reduce “acciones ilegales” (clicar detrás del modal). Para sistemas, reduce fallos de tests y tickets de “a veces no funciona”.
5) Tablas y datos: no reinventar <table> con divs
En web corporativa es habitual “maquetar” tablas con grids de <div>. El resultado: semántica rota y extracción pobre.
La recomendación es la misma: usar <table>, <thead>, <th>, <caption> cuando toca.
<table>
<caption>Consumo mensual por servicio</caption>
<thead>
<tr>
<th scope="col">Servicio</th>
<th scope="col">Coste</th>
<th scope="col">Variación</th>
</tr>
</thead>
<tbody>
<tr>
<td>CDN</td>
<td>1.240,50 €</td>
<td>+8 %</td>
</tr>
</tbody>
</table>
Lenguaje del código: HTML, XML (xml)
Esto mejora:
- lectura por tecnologías asistivas,
- extracción por agentes,
- y reduce heurísticas “adivinatorias”.
6) Para equipos de sistemas: contenido alternativo, caché y “Vary” con tráfico agéntico
Aquí aparece un giro interesante: la web empieza a negociarse por cabeceras.
Cloudflare, por ejemplo, ha presentado “Markdown for Agents”: el cliente envía Accept: text/markdown y la conversión se hace en el edge, devolviendo Markdown en lugar de HTML. La propia propuesta se apoya en reducción de tokens (y coste) y en el hecho de que algunos agentes ya envían ese Accept por defecto.
Esto, para sistemas, tiene implicaciones muy concretas:
- Caché: si se sirven dos representaciones (HTML y Markdown), hay que asegurarse de que el caché diferencia por cabecera. El patrón habitual es
Vary: Accept. - Observabilidad: conviene segmentar logs por
Accepty por user-agent/bot para ver cuánto “tráfico agéntico” entra realmente. - Seguridad: no todo bot que pide Markdown es “bueno”. Rate limiting, WAF y control de scraping siguen siendo necesarios.
- Integridad de contenido: cualquier conversión basada en heurísticas puede “perder” información si el HTML no es semántico (el problema original vuelve a aparecer con otra forma).
En resumen: la operativa no es solo “hacer la web bonita”, también es servir representaciones coherentes y cacheables para humanos y para agentes.
7) Pruebas en CI: de “best effort” a contrato verificable
La diferencia entre “creer que es accesible” y “operarlo” está en automatizar.
Dos aproximaciones útiles:
Aria snapshots con Playwright
Playwright permite generar snapshots del árbol de accesibilidad para detectar regresiones (por ejemplo, un botón que pierde su nombre accesible tras un refactor).
Auditoría automática: axe-core y Pa11y CI
- axe-core es uno de los motores más usados para testing automatizado de accesibilidad.
- Pa11y CI está pensado específicamente para ejecutarse en integración continua.
Ejemplo mínimo de Pa11y en pipeline:
npx pa11y-ci --config .pa11yci.json
Lenguaje del código: CSS (css)
Esto no “garantiza” que un agente vaya a completar una tarea compleja, pero sí evita errores básicos que hunden a cualquiera: labels ausentes, contrastes extremos, controles sin nombre, jerarquías rotas.
8) Lo que dice la investigación: la web real sigue siendo difícil
Los benchmarks ayudan a aterrizar expectativas:
- WebArena evidencia que el éxito end-to-end sigue lejos de lo humano, incluso con modelos potentes.
- Mind2Web pone números al reto del “agente generalista”: miles de tareas reales en cientos de webs.
- MiniWoB++ se consolidó como banco de pruebas para tareas web (clics, formularios, flujos) y ha sido base para muchos avances posteriores.
- Y trabajos como Understanding HTML with Large Language Models muestran mejoras al entrenar/fine-tunear modelos para entender HTML y navegar, con métricas concretas sobre eficiencia de datos y tareas completadas.
La lectura práctica para un medio de desarrolladores y sistemas es directa: no hay atajos mágicos. Si el HTML está mal, la accesibilidad cae; y si la accesibilidad cae, el agente se equivoca más, la automatización es más frágil y la extracción de contenido se vuelve más heurística y menos fiable.
Conclusión: accesibilidad como “SRE” de la experiencia agéntica
Durante años, el HTML semántico y la accesibilidad se defendieron por razones éticas, legales y de calidad. En 2026 se suma otra razón, menos filosófica y más operativa: la web ya no la consumen solo humanos.
Un sitio que:
- usa controles nativos,
- nombra bien sus acciones,
- anuncia estados,
- y mantiene estructura estable…
es más fácil de usar para personas, más fácil de testear, más fácil de automatizar y, cada vez más, más fácil de “entender” para agentes.
Preguntas frecuentes
¿Cómo saber si una web es “amigable” para agentes de IA que navegan formularios?
Si los campos tienen <label> real, los botones tienen nombre accesible, los estados de carga y error se anuncian (por ejemplo con aria-live), y los flujos no dependen de hover o elementos visuales sin semántica, la web suele ser mucho más automatizable.
¿Qué errores de HTML rompen más a agentes y a pruebas E2E?
Los más habituales son botones hechos con <div> sin soporte completo de teclado, controles sin nombre accesible, modales sin aria-modal ni foco correcto, y contenido clave que solo aparece vía animaciones o renderizado tardío sin estados explícitos.
¿Cómo se puede detectar en CI que un refactor ha “roto” accesibilidad sin darse cuenta?
Con tests automatizados (axe-core, Pa11y CI) y snapshots del árbol de accesibilidad (por ejemplo, aria snapshots en Playwright) para detectar cambios en roles y nombres accesibles.
¿Servir Markdown a agentes mejora algo si el HTML ya es bueno?
Puede reducir ruido y coste de procesamiento, pero no sustituye un HTML semántico: si el contenido está mal estructurado, la conversión también puede perder contexto. Además, a nivel de sistemas exige cuidar caché y cabeceras (por ejemplo, Vary: Accept) para no mezclar representaciones.