Si tienes un ecommerce, te interesa esta historia 🙂
Es enero 2027. Rebajas.
Un agente de compra abre una ficha de producto para cerrar un pedido en nombre de alguien. Ese alguien lo ha pedido desde un SERP de Google.
Encuentra el botón “Añadir al carrito”: fondo de color, esquinas redondeadas, cursor de mano al pasar por encima. En el código es un <div class=”btn-add” onclick=”addToCart()”>.
Para el árbol de accesibilidad, que es la capa que ese agente consulta antes de decidir dónde actuar, ahí no hay ningún botón. Hay un bloque de texto con estilos, sin rol interactivo y sin nombre.
El agente no tiene con qué tratarlo como una acción disponible y, por lo tanto, solo le quedan cuatro caminos por seguir:
Saltarse el paso.
Reintentar por una vía de ejecución más cara (visión, posición en pantalla del elemento y otros que consumen muchos tokens y energía).
Irse a un marketplace competidor. Después de todo, el usuario ha pedido de manera explícita comprar ese contenido, así que algo tendrá que inventarse.
Abandonar el flujo.
El pedido no se cierra y nadie en la empresa se entera, porque en el navegador de un humano ese botón funciona perfectamente.
EL HTML que se está usando ya no sirve solo para mostrar la página en el navegador: también lo interpreta como interfaz un software que actúa. Y un agente que tiene que pararse a pensar en cada botón gasta tokens y latencia que no gasta cuando la semántica está bien puesta.
La diferencia está en órdenes de magnitud.
Esto es un tutorial en tres partes:
Cómo percibe un agente una página.
Cinco fallos concretos con su arreglo mínimo en HTML.
Un test de cinco minutos que puedes correr hoy en DevTools sobre la página que más dinero te trae.
Y os dejo una batallita de esas de persona que peina canas (casi todas en la barba, por ahora): hay más scripts de Javascript que fallan de los que podáis pensar. Basta que un recurso cargue mal, un navegador tenga el día torcido o una conexion vaya más lenta de lo esperado para que pierdas una venta. Así, hacer que toda la experiencia del usuario dependa de llamadas Javascript no es siempre ni sabio ni recomendable. Así, un botón de añadir a carrito que es esclavo de cómo sople el viento ese día deja tus ingresos en peligro.
Con lo caro que está adquirir tráfico ya no digamos usuarios cualificados, el coste de convertir las microconversiones de tu web en algo que no dependa de JS es irrisorio.
Un agente que navega y actúa combina tres fuentes de información, no una.
Lo describen igual la documentación de Google sobre Google-Agent, el fetcher que Google usa cuando actúa en nombre de un usuario y la guía de UX para agentes que ha publicado el equipo de Chrome en web.dev.
Los problemas empiezan cuando una de las tres capas falta o miente. Aquí os presento el orden estratigráfico de estas capas:
Capa 1, el DOM renderizado. El árbol HTML tal como queda después de ejecutarse el JavaScript. En una aplicación de página única (SPA o Single Page Application para los amigos), el HTML inicial puede llegar prácticamente vacío (un <div id=”root”> y poco más hasta que React o Vue montan la interfaz, proceso conocido como hidratación).
Un agente con navegador headless puede esperar ese render, pero si tarda dos o tres segundos, o si el JavaScript falla, trabaja con lo que tenga en ese instante. Cómo tratan esto Googlebot y compañía ya lo he desarrollado en la entrega sobre renderizado del 23 de julio y que seguramente te perdiste porque estabas en la playa.
En este post solo me interesa el efecto sobre un agente que está trabajando en tiempo real.
Capa 2, el árbol de accesibilidad. El navegador genera, en paralelo al DOM visual, una representación pensada para lectores de pantalla, control por voz y conmutadores. Es una herramienta que mucha gente piensa que solo es usada para personas con problemas de vista que requieren una adaptación. Esta es una presunción anticuada y poco adaptada a la era de la IA.
Esta es la estructura que consultan los agentes que operan con herramientas tipo Playwright MCP:
Roles ARIA
role=”button”,role=”dialog”).Nombres accesibles
aria-label).Semántica HTML nativa
<button>,<nav>,<h1>) son los datos con los que el agente decide qué es cada elemento.
Sin rol ni semántica, ese nodo aparece como genérico y sin nombre, indistinguible de “aquí no hay nada que hacer”.
Si te preguntas psorel coste, Tianpan Cai lo ha medido y lo resume en una frase: el árbol de accesibilidad es tu nueva API pública. Un volcado completo del DOM de una página comercial rondaba, en sus pruebas, los quince mil tokens o más serializado como texto.
El snapshot del árbol de accesibilidad de esa misma página, en el YAML compacto con referencias que usa Playwright MCP ref=12, role=button, name=”Añadir al carrito”), se queda entre doscientos y cuatrocientos. En un sistema que paga por token y por latencia en cada paso, esa diferencia decide qué fuente se usa por defecto y cuál queda como último recurso.
Capa 3, la captura visual. Cuando las dos anteriores no bastan, un modelo multimodal procesa el viewport como imagen y deduce por aspecto qué es un botón o un precio. Es la vía más cara (MÁS CARA, con diferencia... en mayúsculas, negrita y con tono de voz gutural) y la más susceptible de llevar a errores y conclusiones falsas.
La guía de web.dev documenta sus puntos más flacos:
Overlays semitransparentes que el análisis visual no distingue como bloqueos a la interacción. Por ejemplo, un aviso de que no hay stock preparado por un diseñador que se ha puesto original.
Carruseles que cambian justo al interactuar. Por ejemplo, un zoom sobre imagen al hacer clic.
CTAs que se mueven de sitio según la categoría. Un claro ejemplo es el comportamiento desigual entre productos físicos y virtuales o entre aquellos para compra B2B vs B2C en un mismo ecommerce.
Objetivos de clic tan pequeños que el propio pipeline de detección los descarta por ruido. Los típicos botones para elegir las unidades en un ecommerce son un caso habitual.
El análisis visual agrupa y prioriza, pero solo si el árbol del DOM está pensado de manera lógica. Si esta lógica noexiste, la semántica no se puede inferir y mucho menos deducir (que no es lo mismo en este contexto).
Cuando falla la capa 2, el agente no compensa volviéndose más listo. Se vuelve más lento, más caro y menos fiable. Y tú pierdes tu venta, claro.
Os dejo los problemas más comunes que he visto estos últimos meses:
El síntoma. Elementos interactivos construidos sobre <div>, <span> o <a href=”#”> sin destino real, estilizados para parecer botones pero sin rol ARIA ni elemento nativo detrás. Es el caso del principio. Pasa también con botones de icono sin texto visible (el carrito, el corazón de favoritos) que se quedan sin aria-label.
Por qué falla. El árbol de accesibilidad no los registra como objetivos válidos. Aparecen como contenedor genérico o, peor, como button: “”, un botón sin nombre. El agente sabe que hay algo pulsable y no sabe qué hace, así que no arriesga la acción en una página de compra real.
El arreglo. <button> para cualquier acción que no navegue, <a href> con URL real para lo que sí navega. Si no puedes cambiar el elemento, añade role=”button”, tabindex=”0” y gestiona click y keydown para Enter y Espacio (un div con onclick no responde a teclado, y eso también deja la semántica a medias). En un listado con veinte tarjetas de producto, el aria-label tiene que nombrar el producto concreto: si está escrito a mano en la plantilla, las veinte tarjetas dicen “Añadir al carrito” y el agente vuelve a estar donde estaba.
Si tu botón necesita CSS para parecer un botón, necesita <button> para serlo de verdad.
El síntoma. Campos de email, nombre o teléfono con solo placeholder, sin <label> asociada por forid ni aria-label. Habitual en checkouts minimalistas y en formularios de captación donde el diseño prioriza el espacio. Y en mucho código de front generado mediante vibe-coding sin criterio real detrás. Sí, hablo de ti 😉.
Por qué falla. El árbol muestra el campo como textbox sin nombre. El plaeholder no cuenta como nombre accesible y encima desaparece en cuanto el campo recibe foco o contenido, así que el agente que ya ha empezado a rellenar pierde la referencia. Entonces adivina. Un lector de pantalla confunde el código postal con el teléfono exactamente por lo mismo.
El arreglo. <label> visible siempre que el diseño lo permita, aria-label cuando no. El for debe coincidir con el id. Añadir autocomplete con el tipo correcto email, telp, postal-code) reduce la inferencia tanto para el agente como para el autorrelleno del navegador.
Entras en la ficha, salta el aviso de cookies a pantalla completa y la equis de cerrar es un <span> con onclick y cursor: pointer. El foco del teclado sigue donde estaba, detrás de la capa.
Por qué falla. El agente detecta que ha aparecido algo nuevo en el DOM, pero sin foco movido ni role=”dialog” no tiene forma de saber que eso es lo primero que hay que resolver. En el peor caso, el agente actuará sobre el contenido bloqueado de debajo y gastará un intento en descubrir que no pasa nada. Desperdiciar pruebas y tokens te va a costar usuarios agénticos en nada.
El arreglo. Al abrir la capa, el foco debe estar en el primer elemento interactivo del modal; al cerrar, foco de vuelta al elemento que lo abrió. role=”dialog” y aria-modal=”true” en el contenedor. Y el botón de cierre como <button> real con aria-label”Cerrar”, no una equis decorativa. Entre un agente que despacha el aviso de cookies en un paso y uno que se atasca antes de ver el contenido, la distancia son esas tres líneas.
El síntoma. Varios <h1> en la misma página, saltos de <h2> a <h4>, headings elegidos por tamaño visual en lugar de por jerarquía.
Por qué falla. Los agentes usan los headings como mapa antes de decidir por dónde navegar, igual que un humano hojea títulos antes de leer. Sin un <h1> claro, se pierde una señal barata de “estoy en la página correcta” y hacen falta más pasos para confirmarlo.
El arreglo. Un único <h1> con el nombre del producto o el título principal, <h2> para las secciones de primer nivel, <h3> en adelante para subsecciones. Si el diseño pide texto grande que no es un heading, <p class=”display-title”> y tamaño por CSS. Es el más barato de los cinco.
El síntoma. El precio, el título, la disponibilidad o el CTA principal llegan por una llamada a la API después del primer render. Típico de aplicaciones de página única sin renderizado en servidor.
Por qué falla. Un agente que está operando en tiempo real no siempre puede esperar a la hidratación completa. Si lee el HTML inicial antes de que responda la API, ve una página sin precio, sin stock y a veces sin el propio botón de compra. Si además el schema declarado dice una cosa y lo que llega primero dice otra, se suma una razón para desconfiar de la fuente. Es el único punto donde esta entrega roza la del 6 de agosto sobre frescura, y la diferencia importa: allí había un precio caducado, aquí hay un precio que todavía no existe en el HTML que el agente puede leer sin esperar.
El arreglo. Renderizado en servidor o prerenderizado en las páginas de mayor valor comercial: fichas de producto, landings de captación, categorías con intención de compra. No hace falta rehacer la arquitectura entera. Basta con que los datos críticos vayan en el HTML servido y el resto de la interactividad se quede en cliente. Next.js y Nuxt tienen SSR maduro para React y Vue. En WordPress o en cualquier CMS en PHP el servidor ya renderiza por defecto, y ahí el riesgo suele ser otro: un script de terceros que reescribe ese HTML antes de que nadie lo lea.
Abre Chrome DevTools en la página de tu negocio con más valor comercial, ve a la pestaña Accessibility y activa el árbol completo. Si ya trabajas con Playwright MCP, el snapshot en YAML hace el mismo trabajo y se lee más rápido.
Con esa vista abierta, cinco preguntas cerradas:
¿El CTA principal tiene rol de botón (o un
hrefreal) y un nombre descriptivo, no genérico?¿Los campos del formulario tienen etiqueta asociada, visible o
aria-label?¿Hay un único
<h1>y describe con claridad la página?¿El modal que bloquea el contenido tiene
role=”dialog”, mueve el foco y se cierra con un botón nombrado?Si usas snapshots de agente: ¿el YAML nombra las acciones reales del recorrido, sin nodos genéricos vacíos?
Cada “no” es un ticket que debes crear en tu backlog de front-end. Los equipos con más proceso pueden dar un paso más e incluir el diff del snapshot de accesibilidad en cada pull request de interfaz. El árbol es la interfaz estable que el agente lee. Ningún test visual avisa de que se ha roto.
No puedes seguir dependiendo de la idea que llevamos usando desde finales del siglo XX: no todo es la parte visual de página. El diseño es importante, pero ya no lo es todo. Es solo una parte más. Ya no debes pensar solo en humanos: debes pensar también en máquinas.
Los agentes leen semántica, no diseño.
Mientras tanto, una pregunta con la que salir de aquí: de las cinco del test, ¿cuántas responderías con un “no” en tu ficha de producto principal ahora mismo?
Sin posts

Comments
Nothing yet. Say the first thing.
Sign in to join the conversation.