Las últimas semanas me he enfrentado a uno de esos proyectos que te quitan el sueño. Una tienda online con un problema de visibilidad al que no conseguía darle la vuelta. Semanas rompiéndome la cabeza. Ninguna LLM supo orientarme. Al final, todo era un problema de usabilidad y de renderizado.

Te cuento qué pasó y, sobre todo, el concepto que lo explica todo y que cualquier SEO técnico debería dominar: el DOM. Para ilustrarlo uso capturas reales de DevTools y de la herramienta de pruebas de Google sobre otra web mía, lasapaixa.com.

El caso: un ecommerce que Google veía vacío

El 5 de julio se lanzó la migración de la tienda online a un tema nuevo de WordPress, Impreza. Para un usuario, todo estaba perfecto: las fichas de producto se veían completas y bien. Pero a partir de esa semana, las impresiones empezaron a caer y no paraban.

En Sistrix, el índice de visibilidad móvil pasó de 0,026 a 0,0026 en una sola semana, y siguió bajando hasta 0,0002 a mediados de octubre.

Gráfico del índice de visibilidad móvil de Sistrix del último año: tras un pico de 0,026 a finales de junio, cae a 0,0026 la semana del 6 de julio y sigue bajando hasta 0,0002 en octubre
Índice de visibilidad móvil en Sistrix, último año. La migración se lanzó el 5 de julio: la semana siguiente el índice ya había caído un 90 %.

En Search Console, las 14 fichas que analicé en detalle pasaron de unas 1.300 impresiones semanales a unas 300 desde la semana del 12 de julio. Lo curioso es cómo caían:

  • Las búsquedas de un modelo concreto (marca y referencia) aguantaban: una de ellas pasó de 254 a 239 impresiones.
  • Las genéricas desaparecían: «sonda de temperatura» pasó de 290 impresiones a 0, y «medidor de humedad» cayó de la posición 1,2 a no aparecer.

Tiene lógica, aunque entonces no lo veía. Las fichas seguían indexadas y Google las posicionaba con lo que podía leer sin ver la página: la URL, el title y los datos estructurados.

Para una búsqueda de modelo exacta, eso basta. Para competir por una búsqueda genérica, Google necesita el contenido. Y ese contenido, para él, no existía.

Por eso la posición media despistaba tanto: Search Console solo la calcula con las búsquedas en las que apareces. Si desaparecen las genéricas y quedan las de modelo, que siguen bien posicionadas, la media apenas se mueve mientras las impresiones se hunden.

Desde SEO lo revisé todo y no encontraba nada. Desde desarrollo parecía que tampoco había ningún problema. Hasta que miré la página con los ojos de Google.

Lo que veía Google

Esta es la prueba en tiempo real de la Inspección de URLs de Search Console sobre una ficha de producto el 17 de octubre, el día que lo detectamos. Solo se ve la cabecera y una franja gris. El resto, en blanco: ni el H1, ni el precio, ni la foto, ni la descripción.

Inspección de URLs de Search Console con la prueba en tiempo real del 17 de octubre de 2026: el panel dice que la URL está disponible para Google y detecta fragmentos de productos válidos, pero la captura de pantalla solo muestra la cabecera de la web y el resto en blanco
Antes del arreglo: «La URL está disponible para Google» y fragmentos de productos válidos, pero la captura solo muestra la cabecera. Datos de la web anonimizados.

Fíjate en lo engañoso del panel: «La URL está disponible para Google» y «Fragmentos de productos: se ha detectado 1 elemento válido». Todo en verde, porque el schema sí estaba en el HTML. Si no abres la captura, no te enteras.

La causa: tres piezas que por separado no fallaban

  1. Las animaciones de entrada del tema. En Impreza, los bloques de contenido llevaban la clase us_animate_this: el H1, el precio, la descripción y las migas. El CSS del tema los deja con opacity: 0 hasta que su JavaScript (us.core) les añade la clase start y los anima. Sin ese JavaScript, el contenido está en el HTML, pero es invisible. En una ficha había unos 20 bloques así, con unas 645 palabras ocultas.
  2. LiteSpeed Cache retrasando el JavaScript. Con «Optimización para invitados» activada, la opción «Deferir carga de JS» estaba en «Retrasado». Unos 25 scripts se servían como type="litespeed/javascript" y no se ejecutaban hasta que había un evento de usuario: mouseover, click, keydown, wheel, touchmove, touchstart, pointerup o pointerdown. Además, «Combinar JS» metía us.core dentro de un archivo combinado, también retrasado, y jQuery, del que depende Impreza, también lo estaba.
  3. Googlebot no interactúa. No mueve el ratón, no hace clic y no hace scroll. Nunca dispara esos eventos, así que el JavaScript no llegaba a ejecutarse y los bloques se quedaban con opacidad 0.

Una persona mueve el ratón o toca la pantalla nada más entrar, sin darse cuenta, así que nunca veía el fallo. Google, siempre.

El alcance era enorme: 851 de las 859 URLs indexables. En 750 fichas de producto estaba oculto el 100 % del texto, H1 y precio incluidos, y además afectaba a la home, las categorías, las marcas y los casos de éxito. La web anterior, que revisé en Wayback Machine, no tenía animaciones ni scripts retrasados.

El arreglo

El primer intento de desarrollo fue excluir us.core del retraso. No funcionó: el código iba dentro del JavaScript combinado y jQuery seguía retrasado.

Lo corregimos el 19 de octubre: desactivamos «Optimización para invitados» y pasamos «Deferir carga de JS» a «Diferido». Ahora los scripts se ejecutan al terminar de cargar la página, sin esperar a ninguna interacción. Lo verificamos de cuatro formas:

  • el HTML ya no lleva litespeed/javascript;
  • en Chrome, sin tocar nada, se ven el H1 y el precio;
  • la prueba en tiempo real de Search Console muestra la ficha completa;
  • en los logs del servidor, Googlebot descarga las fichas y 148 archivos JS y CSS, todos con código 200.
Inspección de URLs de Search Console con la prueba en tiempo real del 22 de octubre de 2026: la captura de Google ya muestra la foto del producto y el H1 de la ficha
Después del arreglo, prueba del 22 de octubre: Google ya ve la foto y el H1 de la ficha. Datos del producto anonimizados.

Los primeros resultados

Es pronto: el arreglo tiene diez días. Pero en Search Console la caída libre se ha detenido y, en la primera semana completa después del cambio, el índice de visibilidad de Sistrix ya ha crecido más de un 200 %.

Tarjeta del índice de visibilidad de Sistrix con un valor de 0,0011 y una subida de más del 200 %
Índice de visibilidad en Sistrix la semana siguiente al arreglo: más de un 200 % de subida.

Los valores todavía son muy bajos y una semana no hace tendencia, así que lo seguiré de cerca. Pero el cambio de dirección es inmediato. Definitivamente, había dado con la tecla.

Para entender por qué pasa algo así, y cómo detectarlo antes de perder tres meses de tráfico, hay que entender cómo funciona el DOM.

Qué es el DOM

El DOM (Document Object Model) es la representación que construye el navegador a partir del HTML: un árbol de nodos que JavaScript puede leer y modificar. Con este HTML:

<body>
  <h1>Servicios SEO</h1>
  <p>Auditorías técnicas y consultoría SEO.</p>
</body>

el navegador crea un nodo para body, otro para h1, otro para p y otro para cada texto. Lo importante para un SEO es esto: el DOM no es estático. Nace del HTML, pero los scripts pueden añadir, cambiar, ocultar o borrar nodos durante toda la vida de la página.

HTML inicial, DOM y renderizado no son lo mismo

Conviene separar tres conceptos que solemos mezclar:

  • HTML inicial: el documento que devuelve el servidor. Es lo que ves con Ctrl + U.
  • DOM: la estructura viva que construye el navegador a partir de ese HTML y que los scripts van modificando. Es lo que ves en DevTools, en la pestaña Elementos.
  • Renderizado: el proceso de interpretar HTML, CSS y JavaScript para pintar la página. Incluye construir y actualizar el DOM, pero también decidir qué se ve y qué no.

Un ejemplo extremo, típico de las webs hechas con React, Vue o Angular sin renderizado en servidor. El HTML inicial solo trae esto:

<div id="app"></div>
<script src="/app.js"></script>

Y después de ejecutar el JavaScript, el DOM contiene el contenido de verdad:

<div id="app">
  <h1>Consultoría SEO en Málaga</h1>
  <p>Servicios de posicionamiento web.</p>
  <a href="/auditoria-seo/">Auditoría SEO</a>
</div>

Google puede llegar a ese contenido, pero solo si el JavaScript se descarga, se ejecuta sin errores y el contenido está listo cuando Google procesa la página. Cada una de esas condiciones es un punto en el que algo puede fallar.

Cómo procesa Google una página

Google documenta tres fases para las páginas con JavaScript:

  1. Rastreo: Googlebot pide la URL y recibe el HTML inicial. De ahí ya extrae enlaces y directivas.
  2. Renderizado: la página pasa a una cola y el Web Rendering Service la abre con una versión actualizada de Chromium, ejecuta el JavaScript y obtiene el HTML renderizado, es decir, el DOM resultante.
  3. Indexación: Google usa ese HTML renderizado para entender el contenido, descubrir más enlaces y decidir qué indexa.

Así que no es cierto que «Google no lee JavaScript». Sí lo lee (a diferencia de la gran mayoría de LLMs) pero indexa lo que hay en el DOM en el momento en que lo renderiza

  • sin hacer clic,
  • sin hacer scroll y
  • sin mover el ratón.

Si tu contenido necesita algo de eso para aparecer, Google no lo tendrá.

Un detalle que suele pasarse por alto: si el HTML inicial lleva un noindex, Google puede saltarse el renderizado. Quitarlo después con JavaScript no sirve.

El DOM no es lo que ve el usuario

Esta es la clave del caso del ecommerce. Que un texto esté en el DOM no significa que se vea. Y que se vea en tu navegador no significa que se vea igual en el de Google. Hay tres situaciones distintas:

Situación¿Está en el DOM?¿Qué ve Google?
Pestañas o acordeones con el texto ya en el HTML (display: none)SíLo puede procesar, aunque esté plegado
Contenido con opacity: 0 que un script muestra al hacer scroll o al interactuarSí, pero invisibleUna página en blanco en esa zona, porque Google no interactúa
Contenido que solo se crea después de pulsar un botón o hacer scrollNo, hasta que alguien interactúaNada: para Google no existe

Las animaciones de entrada de muchos temas y constructores (aparecer al hacer scroll, fundidos, deslizamientos) funcionan justo así: el contenido arranca invisible y un script lo muestra después.

Si además un plugin de rendimiento retrasa el JavaScript hasta la interacción, como LiteSpeed Cache en este caso, ese script no se ejecuta hasta que el usuario mueve el ratón. Para Google, nunca.

Un ejemplo real con DevTools y la herramienta de Google

Las páginas del ecommerce no puedo enseñarlas sin anonimizar, así que para ver el DOM paso a paso uso un caso equivalente en una web mía. En lasapaixa.com hay un juego, «¿Dónde encaja tu próxima vida?», que te recomienda países europeos según tus prioridades.

El resultado solo aparece después de responder cuatro pasos. Es decir, depende de la interacción, igual que el contenido de aquellas fichas.

Esto es lo que ve una persona cuando termina el juego:

Resultado del juego ¿Dónde emigrar? en lasapaixa.com: título «Hay coincidencias, pero falta ajustar el presupuesto» y tres tarjetas con Polonia, Malta y Rumanía y su afinidad sobre 100
Lo que ve el usuario después de jugar: el veredicto y los tres países recomendados.

En el HTML inicial (Ctrl + U), esa sección existe, pero está vacía y lleva el atributo hidden:

<section id="em-result" hidden aria-label="Tus destinos afines">
  …
  <h2 id="em-verdict" tabindex="-1"></h2>
  <p id="em-summary"></p>
  …
  <div class="cards" id="em-top"></div>
  …
</section>

Si abres DevTools después de jugar (clic derecho sobre el título → Inspeccionar), el DOM es otro: el script ha quitado el hidden y ha rellenado el <h2>, el resumen y las tarjetas.

Panel Elementos de Chrome DevTools con la sección em-result ya sin el atributo hidden y el h2 em-verdict con el texto «Hay coincidencias, pero falta ajustar el presupuesto» seleccionado
El DOM después de la interacción, en DevTools: la sección ya no está oculta y el <h2> tiene texto. Nada de esto estaba en el HTML inicial.

Ahora, lo que ve Google. En la Prueba de resultados enriquecidos pasé la URL con el rastreador para smartphones y abrí Ver página probada. La pestaña HTML muestra el HTML renderizado, el DOM tal como lo dejó Google:

Pestaña HTML de la Prueba de resultados enriquecidos con la búsqueda em-result: la sección sigue con el atributo hidden y el h2 em-verdict, el resumen y las tarjetas están vacíos
El HTML renderizado por Google: Google ha ejecutado el JavaScript, pero como no juega, la sección sigue con hidden y vacía.

Y la pestaña Captura de pantalla lo confirma: Google se queda en el paso 1 de 4.

Captura de pantalla de la Prueba de resultados enriquecidos renderizada con el rastreador para smartphones: el juego aparece en el paso 1 de 4, sin resultado
La captura de Google: el juego en el paso 1 de 4, sin ningún resultado.

En lasapaixa.com esto es correcto: el resultado es personal, no tiene sentido indexarlo, y todo lo que sí quiero posicionar (el título, la explicación, las preguntas frecuentes y las fuentes) está en el HTML inicial.

El problema aparece cuando lo que depende de la interacción es el contenido principal. Eso es exactamente lo que le pasaba al ecommerce: el H1, la descripción, el precio y todo lo que hace que una ficha de producto merezca posicionar estaba en la parte que Google nunca llegaba a ver.

Cómo auditar el DOM de tu web

Son cuatro comprobaciones que puedes hacer hoy mismo, de la más rápida a la más fiable:

  1. Código fuente frente a DOM. Busca una frase del contenido principal con Ctrl + U y después en DevTools (F12 → Elementos → Ctrl + F). Si solo está en el segundo, depende de JavaScript.
  2. Sin JavaScript. En DevTools, pulsa Ctrl + Shift + P, escribe «Desactivar JavaScript» y recarga. Lo que desaparezca depende de los scripts. No es lo mismo que ver como Google, pero te dice dónde mirar.
  3. Lo que ve Google. En Search Console, Inspección de URLs → Probar URL publicada → Ver página probada. Si no tienes acceso, la Prueba de resultados enriquecidos sirve para cualquier URL. Revisa el HTML, la captura y, en Más información, los recursos que no se han podido cargar.
  4. En bulk. Rastrea la web dos veces con Screaming Frog, una en modo texto y otra con renderizado de JavaScript, y compara contenido, enlaces, encabezados y canonicals. Tampoco reproduce exactamente a Googlebot, pero detecta patrones en cientos de URLs.

A raíz de este caso estoy desarrollando mi propia herramienta, Technical SEO Report. Soy consciente de que ninguna herramienta va a permitirme auditar en bloque, y de forma fiable, lo que ven los ojos de Googlebot: eso solo lo sabe Google. Pero al menos me da unas líneas orientativas de donde mirar y priorizar, URL a URL:

  • recursos bloqueados por robots.txt,
  • diferencias entre el HTML inicial y el renderizado, y
  • contenido que solo aparece al interactuar.

Además, el renderizado es solo una parte: la herramienta parte del rendimiento, con Lighthouse y los datos de usuarios reales de CrUX. Dejo el repositorio enlazado aquí, poco a poco la iré iterando 👌🏻 jeje

Qué comparar entre el HTML inicial y el renderizado

ElementoQué buscar
H1 a H6Encabezados nuevos, eliminados o modificados
Texto principalContenido que aparece, desaparece o queda oculto
Enlaces internosURLs que solo existen tras el renderizado o enlaces sin href
CanonicalQue no cambie: Google desaconseja canonicals distintas en cada versión
Meta robotsUn noindex inicial puede impedir el renderizado
JSON-LDDatos estructurados añadidos o eliminados por scripts

El DOM también afecta al rendimiento

Además de lo que Google indexa, el DOM influye en las Core Web Vitals, aunque de forma indirecta:

  • LCP: un DOM muy grande o un elemento principal que depende de un script tarda más en pintarse.
  • INP: cuantos más nodos, más trabajo para el navegador cada vez que hay que responder a una interacción.
  • CLS: los elementos que se insertan tarde empujan al resto de la página.

Eso sí, no existe un número de nodos a partir del cual Google penalice. Un DOM grande es un problema de rendimiento, no de indexación.

Lo que me llevo de este caso

Cuando todo parece correcto y la visibilidad se desploma después de un cambio de diseño, la pregunta no es solo «¿está el contenido en la página?». Es: ¿cuándo aparece, qué lo genera, sigue ahí después del renderizado y qué versión ve Google? El usuario y Googlebot no siempre ven la misma página.

En próximos artículos hablaré de CSR, SSR, SSG e hidratación, que explican por qué se producen muchas de estas diferencias, y de cómo auditar el DOM a fondo.

Si tu web ha perdido visibilidad tras un rediseño y no encuentras el motivo, escríbeme y lo revisamos.