Menús en JavaScript: por qué Google puede no estar viendo tu navegación

Abres la web y el menú funciona. Despliegas categorías, pinchas y navegas, todo va fino. Luego entras en Search Console y te encuentras media tienda en “Descubierta: actualmente sin indexar”, categorías profundas que no aparecen por ningún lado y un informe de enlaces internos donde tus secciones importantes tienen cuatro enlaces contados.

Lo que ves tú y lo que ve un robot son dos cosas distintas. Tu navegador ejecuta JavaScript, reacciona a tus clics y monta el menú sobre la marcha. Googlebot llega, descarga el HTML, busca enlaces y se va. Si tu menú vive dentro de un onclick, de un <button> o de un componente que no inyecta nada en el DOM hasta que alguien toca el icono de hamburguesa, ahí no hay nada que rastrear.

Esta guía va de eso: qué considera Google un enlace de verdad, por qué el discurso de “tranquilo, Google ya renderiza JavaScript” se ha quedado corto justo cuando han llegado los bots de IA, cómo diagnosticar tu propia navegación en un cuarto de hora y qué hacer según trabajes con WordPress, con un framework moderno o con un ecommerce. Con código, con checklist y con las fuentes oficiales encima de la mesa.

Está escrita para quien ya sabe abrir DevTools. Si buscabas una introducción a qué es el SEO, este no es tu sitio.


1. Qué considera Google un enlace (y qué no)

Aquí no hay interpretación posible, porque la documentación de Google es de las pocas que se moja con ejemplos de código. La regla es literal: Google solo puede rastrear tu enlace si es un elemento HTML <a> con un atributo href. Y el valor de ese href tiene que resolver en una dirección web a la que sus rastreadores puedan mandar una petición.

Dos condiciones, las dos obligatorias. Fallar una basta para que la URL no exista para el robot.

Patrones de marcado que Google rastrea y patrones que no, con el motivo de cada caso

Usar JavaScript no es el error. El error es usarlo en lugar del enlace.

Código¿Lo rastrea Google?Por qué
<a href="/zapatillas/">Zapatillas</a>Elemento correcto y URL resoluble
<a href="./zapatillas/">Zapatillas</a>Las rutas relativas valen
<a href="/zapatillas/" onclick="track()">Zapatillas</a>El onclick no molesta mientras el href esté ahí
<a routerLink="/zapatillas">Zapatillas</a>NoNo hay atributo href
<span href="/zapatillas/">Zapatillas</span>NoNo es un elemento <a>
<a onclick="goto('/zapatillas')">Zapatillas</a>NoNo hay href
<a href="javascript:void(0)" onclick="...">Zapatillas</a>NoEl href no resuelve en ninguna URL
<button onclick="router.push('/zapatillas')">Zapatillas</button>NoNi es <a> ni hay href

Fíjate en la tercera fila, porque hay mucha confusión con esto. Un enlace con manejadores de eventos encima sí es rastreable. Puedes tener tu tracking, tu animación y tu router del framework colgando del onclick, y Google seguirá leyendo el href sin problema. Usar JavaScript no es el error. El error es usarlo en lugar del enlace.

Esa distinción es la que se pierde en la mayoría de auditorías. Se marca todo el menú como “problema de JavaScript” cuando en realidad hay un patrón concreto que se puede arreglar añadiendo un atributo.

Qué pasa con el PageRank interno

Un enlace que Google no ve no transmite nada. Ni descubrimiento, ni relevancia, ni fuerza. Tu home puede tener una autoridad estupenda y estar enlazando a doce categorías, pero si esos doce enlaces son botones, para Google tu home enlaza a cero categorías.

El efecto no es que las páginas desaparezcan de golpe. Si están en el sitemap, Google acabará entrando. El efecto es más sutil y más caro: llegan sin ningún respaldo interno, con textos ancla inexistentes y sin señal ninguna de que sean importantes dentro de tu web. Posicionan peor de lo que deberían y nadie sabe muy bien por qué.


2. Cómo se descubre y se renderiza (y por qué las “dos oleadas” ya no se cuentan bien)

Este es el bloque donde más contenido desactualizado vas a encontrar por ahí, así que vamos con lo que dice la documentación de Google hoy.

El proceso tiene tres fases: rastreo, renderizado e indexación. Googlebot descarga el HTML de respuesta y lo analiza en busca de enlaces, que encola para rastrear. Después la página entra en una cola de renderizado. Cuando hay recursos disponibles, un Chromium sin interfaz gráfica renderiza la página y ejecuta el JavaScript. Sobre ese HTML renderizado, Googlebot vuelve a buscar enlaces y encola los que encuentre.

Es decir, hay dos momentos de descubrimiento de enlaces. Eso sigue siendo verdad y está en la documentación oficial.

Proceso de rastreo, renderizado e indexación de Google y los dos momentos de descubrimiento de enlaces

Dos momentos de descubrimiento. Ninguno inventa un enlace que no esté en el marcado.

Lo que se cuenta mal

El modelo de “las dos oleadas de indexación” viene de 2018 y se popularizó con la idea de que la segunda podía tardar días o semanas. Esa cifra lleva años sin ser representativa.

Martin Splitt, de Google, dio el dato en el Chrome Dev Summit de noviembre de 2019: entre el rastreo y el renderizado, la mediana es de cinco segundos. Ese mismo año explicó que las dos oleadas juegan un papel cada vez menor, porque renderizar les sale más barato de lo que pensaban y cada vez mandan más páginas a render directamente, incluso las que no llevan JavaScript.

La documentación actual lo formula con prudencia: la página puede quedarse en la cola unos segundos, aunque puede tardar más.

Así que si alguien te vende una migración a SSR argumentando que “si no, Google tardará semanas en indexarte”, te está vendiendo con un dato de hace siete años. Los motivos buenos para hacer esa migración son otros, y los vemos en el bloque 7.

Entonces, ¿dónde está el problema de verdad?

En que la mediana esconde la cola. Cinco segundos es el caso central, no el peor. Una web con poca autoridad, con recursos pesados, con errores de JavaScript o con dependencias que fallan puede quedarse fuera de ese percentil cómodo sin enterarse.

Y sobre todo, en que el renderizado no arregla nada si el enlace tampoco existe después de renderizar. Esta es la parte que se pierde en la discusión sobre oleadas y colas: si tu menú se monta con <button>, da igual que Googlebot renderice en cinco segundos o en cinco días. Renderiza, mira, no encuentra ningún href y se va con las manos vacías.

El renderizado resuelve un problema de momento. No resuelve un problema de marcado.


3. Los cinco patrones que rompen la navegación

Estos son los que aparecen una y otra vez en auditorías reales, ordenados de más a menos frecuente.

3.1. El clásico: javascript:void(0)

<!-- MAL -->
<a href="javascript:void(0)" onclick="router.push('/zapatillas/')">
  Zapatillas
</a>

El usuario pincha y navega perfectamente. El robot lee el href, encuentra javascript:void(0), comprueba que eso no es una dirección a la que pueda mandar una petición y descarta el enlace. La URL de destino no aparece por ningún sitio del HTML.

<!-- BIEN -->
<a href="/zapatillas/" onclick="router.push('/zapatillas/'); return false;">
  Zapatillas
</a>

Mismo comportamiento para el usuario, y ahora hay una URL que rastrear. Si además prefieres no interceptar la navegación, quita el onclick y deja que el enlace haga su trabajo.

3.2. Botones y divs haciendo de enlaces

<!-- MAL -->
<button class="nav-item" onclick="goTo('/zapatillas/')">Zapatillas</button>
<div class="nav-item" data-url="/zapatillas/">Zapatillas</div>

Muy típico de maquetadores visuales y de librerías de componentes que ofrecen un “Button” con propiedad de enlace. También aparece cuando el diseño pedía algo que parecía un botón y alguien resolvió usando un botón de verdad.

La regla mental: si al pincharlo cambias de página, es un enlace y va con <a href>. Si al pincharlo pasa algo dentro de la misma página (abrir un modal, filtrar, enviar un formulario), es un botón y va con <button>. Esto vale igual para accesibilidad, que es la otra mitad del argumento.

3.3. El preventDefault sin red de seguridad

<!-- MAL -->
<a href="#" onclick="event.preventDefault(); cargarCategoria('zapatillas');">
  Zapatillas
</a>

Aquí el href existe pero apunta a la propia página. El destino real solo está dentro de la función JavaScript. Para el robot, ese enlace apunta a donde ya está.

3.4. El menú hamburguesa que no existe hasta que lo abres

Este merece sección propia porque es el que más silenciosamente hace daño en proyectos con React, Next, Vue o Angular.

Menú hamburguesa cuyos enlaces no existen en el DOM inicial hasta que el usuario hace clic

El patrón es este: el componente de navegación móvil mantiene un estado isOpen en false y renderiza los enlaces solo cuando pasa a true. En el DOM inicial hay un icono y nada más. Los quince enlaces del menú aparecen cuando el usuario toca el icono.

// MAL
function MobileNav() {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <nav>
      <button onClick={() => setIsOpen(!isOpen)} aria-label="Abrir menú">☰</button>
      {isOpen && (
        <ul>
          <li><a href="/zapatillas/">Zapatillas</a></li>
          <li><a href="/camisetas/">Camisetas</a></li>
        </ul>
      )}
    </nav>
  );
}

Los enlaces están bien escritos. El problema es que no están en la página hasta que alguien hace clic, y Googlebot no hace clic. La documentación de Google lo dice con estas palabras al hablar de carga diferida: los métodos recomendados no dependen de acciones del usuario como el desplazamiento o el clic, porque la Búsqueda de Google no interactúa con tu página.

La solución es renderizar siempre los enlaces y controlar la visibilidad con CSS:

// BIEN
function MobileNav() {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <nav>
      <button onClick={() => setIsOpen(!isOpen)} aria-expanded={isOpen} aria-label="Abrir menú">☰</button>
      <ul className={isOpen ? "nav-list is-open" : "nav-list"}>
        <li><a href="/zapatillas/">Zapatillas</a></li>
        <li><a href="/camisetas/">Camisetas</a></li>
      </ul>
    </nav>
  );
}

Los enlaces están en el DOM desde el primer momento y el CSS decide si se ven. Google lleva años tratando con normalidad el contenido oculto tras pestañas y acordeones siempre que esté en el HTML, así que esto no es cloaking ni te va a penalizar.

Ojo con un caso particular que se escapa mucho: la web que tiene un menú de escritorio server-side correcto y un menú móvil montado con este patrón. Con indexación mobile-first, el menú que cuenta es el segundo.

3.5. Paginación y scroll infinito solo con JavaScript

En un ecommerce con 400 productos por categoría, si las páginas 2, 3 y siguientes se cargan por scroll o con un botón “Ver más” que no cambia la URL, esos productos no tienen ninguna ruta de entrada.

Google es claro con esto: para que el scroll infinito sea indexable, cada bloque necesita su propia URL persistente y única, y esas URLs paginadas tienen que estar enlazadas con <a href> de verdad. Puedes mantener el scroll infinito para la experiencia de usuario y tener debajo una paginación real. No son incompatibles.


4. El agujero que casi nadie está cubriendo: los bots de IA no ejecutan JavaScript

Si solo te llevas una cosa de este artículo, que sea esta.

Todo el discurso tranquilizador de los últimos años (“Google ya renderiza JavaScript, no te preocupes”) se construyó cuando el único destino que importaba era Google. Ese supuesto ha dejado de valer.

El estudio de Vercel y MERJ, publicado en diciembre de 2024 a partir de los datos de rastreo de nextjs.org y de la red de Vercel, dejó una conclusión seca: ninguno de los grandes rastreadores de IA renderiza JavaScript en ese momento.

Rastreador¿Ejecuta JavaScript?Detalle del estudio
GPTBot (OpenAI)NoDescarga archivos JS en el 11,50 % de sus peticiones, pero no los ejecuta
ClaudeBot (Anthropic)NoDescarga archivos JS en el 23,84 % de sus peticiones, pero no los ejecuta
PerplexityBotNoSolo procesa el HTML de respuesta
Bytespider (ByteDance)NoSolo procesa el HTML de respuesta
Meta-ExternalAgentNoSolo procesa el HTML de respuesta
GeminiUsa la infraestructura de Googlebot
ApplebotRenderiza en un navegador, según la documentación de Apple

Descargar el archivo y ejecutarlo son cosas distintas. ClaudeBot se baja casi una cuarta parte de los JS que encuentra y no hace nada con ellos: los trata como texto.

Traducido a tu menú: si tu navegación se monta en cliente, para GPTBot, ClaudeBot o PerplexityBot tu web es la home y poco más. No hay categorías, no hay secciones, no hay estructura. Google acabará viéndolo tras el render, pero los índices que alimentan buena parte de las respuestas generativas se quedan con el HTML crudo.

Esto convierte un problema que hasta ahora era de velocidad de indexación en un problema de existencia, y va mucho más allá del menú: lo que ve ChatGPT de una web en React es exactamente lo mismo. Y es justo lo contrario de lo que repite la mayoría de guías de JavaScript SEO, que siguen ancladas en el debate de 2019.

Las dos excepciones importan

Applebot renderiza. Apple lo documenta y añade un aviso que conviene leer dos veces: si el JavaScript, el CSS y otros recursos están bloqueados en el robots.txt, puede que no consiga renderizar el contenido correctamente. Con Applebot alimentando las funciones de Siri y de Apple Intelligence, ese rastreador ha dejado de ser un detalle.

Gemini renderiza porque va montado sobre la infraestructura de Googlebot. Lo cual, dicho de otra forma, significa que tu visibilidad en las respuestas de Gemini hereda tus problemas de renderizado con Google, ni más ni menos.

El dato tiene fecha, y hay que decirlo

El estudio de Vercel y MERJ es de diciembre de 2024. Es la referencia pública más sólida que existe sobre esto y todos los análisis posteriores siguen apoyándose en ella, pero es una foto de un momento concreto y los rastreadores cambian sin avisar.

La conclusión práctica no depende de la cifra exacta: la única navegación que funciona con todos los rastreadores, renderizen o no, es la que ya está en el HTML de respuesta. Es el mínimo común denominador y sale gratis.


5. Diagnóstico: comprueba tu navegación en 15 minutos

Seis pruebas, de la más rápida a la más laboriosa. Con las tres primeras ya sabes si tienes un problema.

Prueba 1 – Desactiva JavaScript (2 minutos)

En Chrome, abre DevTools, pulsa Ctrl+Shift+P (o Cmd+Shift+P en Mac), escribe “JavaScript” y elige Disable JavaScript. Recarga.

Mira el menú principal, el menú móvil (activa la vista de dispositivo), el footer, la paginación de una categoría y los filtros.

Lo que siga viéndose y siga siendo pinchable existe en el HTML de respuesta. Lo que desaparezca depende por completo de scripts.

Esta prueba es un poco más severa que la realidad de Googlebot, porque él sí ejecuta JavaScript. Pero es exactamente lo que ven GPTBot, ClaudeBot y PerplexityBot, así que sigue siendo la prueba que más te interesa pasar.

Prueba 2 – Cuenta enlaces en el código fuente (3 minutos)

Abre view-source:https://tudominio.es/ y busca la URL de una categoría importante. Si no aparece, no está en el HTML de respuesta.

Para hacerlo a lo bruto sobre toda la home, desde terminal:

curl -s https://tudominio.es/ | grep -o 'href="[^"]*"' | sort -u | wc -l

Compáralo con lo que cuenta el DOM ya renderizado. Pega esto en la consola de DevTools:

console.log(document.querySelectorAll('a[href]').length);

Si el HTML de respuesta tiene 12 enlaces y el DOM renderizado tiene 90, tienes 78 enlaces que solo existen después de ejecutar JavaScript. Ese número es tu problema, medido.

Y para ver cuáles son exactamente los que faltan, en la consola:

[...document.querySelectorAll('nav a')].map(a => a.getAttribute('href'))

Los que devuelvan null, #, javascript:void(0) o cadena vacía son enlaces rotos a efectos de rastreo.

Prueba 3 – Inspección de URL en Search Console (5 minutos)

Inspecciona tu home y lanza la prueba en directo, que rastrea la página en ese momento, a diferencia de la versión indexada, que te enseña la última instantánea guardada.

Ve a Ver página probada y revisa tres pestañas:

  • HTML: es el HTML renderizado, después de ejecutar JavaScript. Busca ahí las URLs de tus categorías principales.
  • Captura de pantalla: mira si el menú aparece dibujado. Si ves la página descuadrada o sin estilos, tienes recursos bloqueados.
  • Más información: aquí salen los recursos que no se han podido cargar y los mensajes de la consola. Los errores de JavaScript de esta lista son los que te están rompiendo el render.

Repite la prueba con la URL de una categoría profunda, no solo con la home.

Prueba 4 – Rastreo con y sin renderizado (5 minutos de configuración)

Con Screaming Frog, lanza dos rastreos del mismo sitio y compara:

  1. Configuration > Spider > Rendering > Text Only
  2. Configuration > Spider > Rendering > JavaScript

Después mira el informe de JavaScript y, sobre todo, el aviso “Contains JavaScript Links”, que te marca las URLs descubiertas únicamente tras renderizar. Esa lista es tu inventario de enlaces invisibles para cualquier bot que no ejecute scripts.

Si trabajas con Sitebulb, la comparación equivalente es Response vs Rendered.

Compara también el total de URLs encontradas en cada modo. La diferencia es la parte de tu web que no existe sin JavaScript.

Prueba 5 – Revisa el robots.txt (1 minuto)

Busca reglas que bloqueen recursos:

Disallow: /wp-includes/
Disallow: /*.js$
Disallow: /assets/
Disallow: /_next/

Cualquiera de esas líneas puede impedir que Google y Applebot rendericen tu página. Es un error de 2015 que sigue apareciendo en plantillas heredadas y en migraciones mal cerradas.

Prueba 6 – Cruza con los datos que ya tienes

En Search Console, mira el informe de Indexación de páginas y fíjate en cuántas URLs están en “Descubierta: actualmente sin indexar”. Si esa cifra es alta y tus URLs solo se conocen por sitemap, tienes un problema de descubrimiento por navegación.

Y si tienes acceso al servidor, los logs te dicen si Googlebot ha pedido siquiera esas URLs. En el informe de Enlaces, ordena por enlaces internos entrantes. Si tus categorías principales aparecen con dos o tres enlaces cuando deberían estar enlazadas desde todo el sitio a través del menú, ahí tienes la confirmación.

Tabla resumen del diagnóstico

PruebaHerramientaQué confirmaTiempo
JS desactivadoDevToolsSi la navegación existe sin scripts2 min
Fuente vs DOMview-source + consolaCuántos enlaces solo existen tras renderizar3 min
Inspección de URLSearch ConsoleQué ve Google después de renderizar5 min
Text Only vs JavaScriptScreaming Frog o SitebulbInventario completo de enlaces inyectados5 min
Recursos bloqueadosrobots.txtSi impides el renderizado tú mismo1 min
Cobertura y enlaces internosSearch ConsoleImpacto real en indexación4 min

6. Un matiz honesto sobre el crawl budget

Se dice mucho que una navegación en JavaScript te destroza el presupuesto de rastreo. Conviene poner esto en su sitio, porque la documentación de Google es bastante concreta sobre a quién le afecta el crawl budget.

Google dice que deben preocuparse los sitios grandes, de más de un millón de páginas únicas con contenido que cambia una vez por semana, y los sitios medianos o grandes, de más de diez mil páginas únicas, con contenido que cambia a diario. Y añade una frase que casi nadie cita: si tu sitio no tiene un montón de páginas que cambien deprisa, o si tus páginas se rastrean el mismo día que las publicas, no necesitas leer esa guía.

O sea, que si llevas un blog de 300 URLs y tu menú es un desastre de botones, tu problema no es el crawl budget. Tu problema es que no hay enlaces.

Donde sí encaja el argumento es en ecommerce grandes. Cuando el descubrimiento por navegación no funciona, todo el peso recae en el sitemap. Y un sitemap es una lista plana: le dice a Google qué URLs existen, pero no le dice cuáles son importantes, cómo se relacionan entre sí ni con qué textos ancla. Esa jerarquía la construyen los enlaces internos, y si no existen, Google se la inventa como puede.

Lo digo así de claro porque es la diferencia entre un argumento técnico y un argumento de vendedor: el problema de una navegación invisible no es tanto de presupuesto como de jerarquía y de contexto.


7. Soluciones por escenario

7.1. WordPress con maquetador

El caso más frecuente y el más fácil de arreglar. Elementor, Divi, WPBakery y compañía tienen widgets de navegación que a veces montan el menú sobre <div> con manejadores de clic, sobre todo en los menús “off-canvas” para móvil.

Qué hacer, por orden:

  1. Comprueba con la prueba 1 si el menú del tema sobrevive sin JavaScript.
  2. Si no sobrevive, usa el menú nativo de WordPress (wp_nav_menu()) en lugar del widget del maquetador. Genera <nav> con <ul> y <a href> de serie.
  3. Revisa el megamenú. Muchos plugins cargan los submenús por AJAX al pasar el ratón. Si es tu caso, busca la opción de precargar o cambia de plugin.
  4. Mira el robots.txt heredado. Los bloqueos a /wp-includes/ y /wp-content/plugins/ siguen apareciendo en instalaciones antiguas y ahí viven scripts que hacen falta para renderizar.
  5. Si usas caché con optimización agresiva de JS, comprueba que la versión cacheada que sirve a los bots no rompe el menú. Se ve en la prueba en directo de Search Console.

7.2. SPA con React, Next, Vue o Angular

Si tu HTML de respuesta es esto, tienes trabajo:

<body>
  <div id="root"></div>
  <script src="/static/js/bundle.js"></script>
</body>

Las opciones, de mejor a peor:

Renderizado en servidor (SSR) o generación estática (SSG). Con Next, Nuxt, Astro o SvelteKit, el HTML sale del servidor con la navegación dentro y el JavaScript se encarga después de hacerla interactiva. Es lo que recomienda Google de forma explícita.

Hidratación. También en la lista de recomendaciones de Google. Sirves HTML completo y el cliente le añade comportamiento encima.

Renderizado dinámico. Servir HTML pre-renderizado solo a los bots. Esto conviene aclararlo, porque sigue apareciendo como consejo: Google lo ha degradado en su propia documentación y dice literalmente que fue una solución provisional, no una solución a largo plazo, porque añade complejidad y consumo de recursos. Si lo tienes montado, funciona; si estás empezando de cero, no vayas por ahí.

Un detalle específico de Next: el componente <Link> genera un <a href> real en el HTML, así que ahí no hay problema. Los problemas llegan cuando alguien sustituye la navegación por router.push() dentro de un onClick, o cuando el componente de menú se renderiza solo en cliente.

Comprobación rápida para cualquier SPA:

curl -s https://tudominio.es/ | grep -c '<a href="/'

Si eso devuelve 0 o un número ridículamente bajo, tu navegación no está en el HTML de respuesta.

7.3. Ecommerce

Tres frentes, por orden de impacto:

Paginación. Cada página de categoría necesita URL propia (/zapatillas/?page=2 o /zapatillas/pagina-2/) enlazada con <a href>. Mantén el “Ver más” si te gusta, pero deja los enlaces debajo.

Filtros y facetas. Aquí la decisión es de arquitectura, no solo de marcado, y tiene artículo propio. Las combinaciones de filtros que tengan demanda de búsqueda propia merecen URL indexable y enlace real. El resto, mejor sin enlazar y sin generar URLs rastreables, o te montas una explosión de combinaciones que sí acaba comiéndose el rastreo.

Menú de categorías. Todas las categorías de primer y segundo nivel deben salir en el HTML de respuesta. En una auditoría SEO para ecommerce esto es de lo primero que se mira. Las de tercer nivel pueden vivir en el megamenú siempre que estén en el DOM inicial, aunque el CSS las mantenga ocultas hasta el hover.

7.4. El patrón que sirve para todos: mejora progresiva

La idea es vieja y sigue funcionando. Escribe primero la versión que funciona sin JavaScript, y luego añade JavaScript encima para mejorarla.

<nav aria-label="Navegación principal">
  <ul>
    <li>
      <a href="/zapatillas/">Zapatillas</a>
      <ul>
        <li><a href="/zapatillas/running/">Running</a></li>
        <li><a href="/zapatillas/trail/">Trail</a></li>
      </ul>
    </li>
    <li><a href="/camisetas/">Camisetas</a></li>
  </ul>
</nav>

Ese HTML funciona con JavaScript desactivado, con lector de pantalla, con Googlebot, con GPTBot y con ClaudeBot. A partir de ahí métele las animaciones, el megamenú, el hover con retardo y lo que quieras.


8. La otra mitad del trabajo: arquitectura y textos ancla

Arreglar el marcado hace que Google vea tus enlaces. Que además le sirvan de algo depende de dos cosas más.

Profundidad de clics

La regla de las tres clics desde la home es una heurística del oficio, no una norma de Google. Lo que sí es cierto y está bastante contrastado es que las páginas que quedan a muchos saltos de la home reciben menos rastreo y menos fuerza interna.

Con un menú roto la profundidad se dispara sin que te enteres, porque el camino corto que tú ves (home → menú → categoría) para el robot no existe, y su único camino real puede ser home → blog → post → enlace contextual → categoría.

Es la mitad del trabajo de una auditoría de arquitectura web e indexación. Mide esto con Screaming Frog en la columna Crawl Depth, y hazlo en modo Text Only para ver la profundidad real sin ayuda del JavaScript.

Textos ancla del menú

Dos errores que se repiten en menús que por lo demás están bien montados:

Enlaces sin texto. Muy típico en el logo y en los iconos de categoría:

<!-- MAL -->
<a href="/"><svg>...</svg></a>

<!-- BIEN -->
<a href="/" aria-label="Inicio - Nombre de la tienda"><svg aria-hidden="true">...</svg></a>

Anclas genéricas. “Ver más”, “Productos”, “Aquí”. El texto del enlace es una de las señales más directas que le das a Google sobre el contenido de destino, y en el menú tienes ese texto repetido en todas las páginas del sitio. Aprovéchalo: “Zapatillas de running” describe mejor que “Running”, y “Guía de tallas” mejor que “Ayuda”.

En el footer pasa lo mismo y con menos atención encima. Es un sitio estupendo para reforzar con anclas descriptivas las secciones que en el menú principal se quedan con texto corto por razones de diseño.


9. Checklist de auditoría de navegación JavaScript

Para copiar y pegar en tu plantilla de auditoría.

Marcado

  • Todos los elementos del menú principal son <a> con href resoluble
  • No hay ningún href="javascript:void(0)", href="#" ni href="" en la navegación
  • No hay <button>, <div> ni <span> haciendo de enlace de navegación
  • La navegación está dentro de un elemento <nav> con aria-label
  • Todos los enlaces tienen texto o aria-label descriptivo, incluidos los de icono

Presencia en el HTML de respuesta

  • La navegación se ve y es pinchable con JavaScript desactivado
  • Las URLs de las categorías principales aparecen en view-source
  • El menú móvil tiene sus enlaces en el DOM inicial, no tras el clic en la hamburguesa
  • El megamenú entrega los submenús en el HTML, sin AJAX al pasar el ratón
  • El número de enlaces en el HTML de respuesta y en el DOM renderizado es parecido

Paginación y listados

  • Cada página de un listado paginado tiene URL propia y persistente
  • Las páginas 2 y siguientes están enlazadas con <a href>
  • El scroll infinito convive con una paginación rastreable
  • Los filtros con demanda de búsqueda tienen URL indexable y enlace real

Renderizado y recursos

  • El robots.txt no bloquea archivos .js ni .css necesarios para renderizar
  • La inspección de URL muestra el menú completo en el HTML renderizado
  • La captura de pantalla de la prueba en directo se ve con estilos
  • No hay errores de JavaScript en la pestaña “Más información” de la prueba en directo

Arquitectura

  • Ninguna categoría relevante queda a más de tres saltos de la home en modo Text Only
  • Las categorías principales reciben enlaces internos desde toda la web
  • Los textos ancla del menú y del footer son descriptivos
  • El informe de Enlaces de Search Console refleja la jerarquía que esperas

Si marcas menos de dieciocho de estas veinticuatro casillas, tienes trabajo de navegación antes que de contenido.


10. Preguntas frecuentes

¿Google no renderizaba ya JavaScript? ¿Por qué sigue siendo un problema?

Renderiza, y bastante rápido: la mediana entre rastreo y renderizado que dio Google en 2019 era de cinco segundos. Pero renderizar no crea enlaces que no existen. Si tu menú son botones, Google renderiza, mira, no encuentra ningún href y se queda igual. El renderizado resuelve un problema de tiempo, no de marcado.

¿Y si mis páginas están en el sitemap? ¿No basta con eso?

Google acabará rastreándolas, sí. Lo que pierdes es todo lo demás: el contexto de jerarquía, los textos ancla, el reparto de fuerza interna y la señal de qué páginas consideras importantes. Un sitemap es un listado, no una arquitectura.

¿Un <a href> con onclick es rastreable?

Sí. La documentación de Google recoge ese caso de forma explícita: los atributos adicionales no molestan mientras el href esté presente y resuelva en una URL real. El problema aparece cuando el onclick sustituye al href, no cuando lo acompaña.

¿Los bots de IA renderizan JavaScript?

Según el estudio de Vercel y MERJ de diciembre de 2024, los grandes rastreadores de IA no lo ejecutan. GPTBot y ClaudeBot llegan a descargar archivos JavaScript, pero no los ejecutan. Las excepciones documentadas son Gemini, que va sobre la infraestructura de Googlebot, y Applebot, que sí renderiza en un navegador según la documentación de Apple.

¿Ocultar el menú con CSS cuenta como cloaking?

No. Google trata con normalidad el contenido que está en el HTML aunque el CSS lo mantenga oculto hasta que el usuario interactúe. Es exactamente lo que quieres hacer con el menú móvil: los enlaces siempre presentes en el DOM y la visibilidad controlada por CSS. Cloaking sería servir contenido distinto a los bots y a los usuarios, que es otra cosa.

¿Merece la pena montar renderizado dinámico solo para los bots?

Si ya lo tienes funcionando, déjalo. Si empiezas de cero, no. Google lo describe en su propia documentación como una solución provisional y no como una solución a largo plazo, y recomienda renderizado en servidor, renderizado estático o hidratación en su lugar.

Tengo el menú de escritorio bien y el móvil montado en JavaScript. ¿Es grave?

Sí, y es de los casos que más se escapan. Con indexación mobile-first, la versión que Google usa para indexar y posicionar es la móvil. Si los enlaces solo existen en el menú de escritorio, para Google no existen.

¿Cómo mido el impacto de arreglar esto?

Antes de tocar nada, guarda tres cifras: URLs en “Descubierta: actualmente sin indexar”, enlaces internos entrantes de tus cinco categorías principales y número de URLs que encuentra un rastreo en modo Text Only. Repite la medición a las cuatro y a las ocho semanas del cambio. Lo primero que suele moverse es el número de enlaces internos y la profundidad de rastreo, y algo después la cobertura.


11. Qué hacer con todo esto

El resumen operativo cabe en cuatro pasos. Desactiva JavaScript y mira tu menú. Cuenta los enlaces del HTML de respuesta y compáralos con los del DOM renderizado. Si la diferencia es grande, empieza por el menú móvil, que es el que Google usa para indexarte. Y sustituye botones por enlaces antes de plantearte ninguna migración.

Lo bueno de este problema es que casi siempre se arregla con cambios pequeños y muy localizados. Poner un href donde había un onclick no requiere replantearse el stack.

Cuándo te compensa pedir ayuda

Hazlo tú si tienes una web mediana, control sobre la plantilla y alguien que sepa tocar el tema o los componentes. Las pruebas de este artículo las puede ejecutar cualquier perfil técnico en una mañana.

Busca ayuda cuando la navegación esté enredada con el framework y no sepas dónde acaba el problema de marcado y dónde empieza el de renderizado, cuando tengas un ecommerce grande con filtros y facetas generando URLs sin control, o cuando lleves meses viendo crecer el bloque de “Descubierta: actualmente sin indexar” sin saber por qué.

El siguiente paso

En Consultoría SEO Sevilla auditamos exactamente esto: qué ve un robot de tu web frente a lo que ves tú, dónde se está perdiendo el rastreo y qué hay que tocar en tu plantilla o en tu framework para arreglarlo, con las tareas priorizadas por impacto y ordenadas para que tu equipo de desarrollo las pueda ejecutar.

Si sospechas que tu navegación tiene este problema, mira en qué consiste la auditoría de arquitectura web e indexación o escríbenos y le echamos un vistazo.

Y si quieres seguir por aquí: renderizado y SEO: por qué ChatGPT no ve tu web en React y análisis de logs: qué hace Googlebot de verdad en tu servidor.