SEO con JavaScript

Cómo asegurar que los buscadores rastreen, rendericen e indexen contenido que depende de JavaScript: enlaces reales, paridad, carga diferida, desplazamiento infinito, soft 404 y pruebas.

1 señal de evidencia en esta página

El SEO con JavaScript comprueba si los buscadores pueden rastrear, renderizar e indexar contenido dependiente de JavaScript. Google puede ejecutar JS; los fallos reales son la paridad entre HTML inicial y renderizado, la interacción, el estado y el tiempo. Usa enlaces reales, no bloquees JS/CSS, prefiere SSR o prerenderizado para el contenido que debe posicionarse y vigila el desplazamiento infinito.

TL;DR — Google puede ejecutar JavaScript, así que «¿puede Google leer JS?» no es la pregunta correcta. Los modos de fallo son la paridad (DOM inicial frente al renderizado), la interacción (Google no se desplaza ni hace clic), el estado (el renderizador no conserva estado) y el tiempo. Mantén los enlaces como anclas <a href> reales, no bloquees JS ni CSS, carga de forma diferida según el viewport y no según una interacción, devuelve estados reales para los 404 del lado del cliente y recuerda que un noindex en el HTML inicial puede impedir el renderizado antes de que JavaScript lo elimine. Combina únicamente las directivas que se hayan procesado; no supongas que el HTML inicial o el renderizado gana siempre. Vigila especialmente el desplazamiento infinito: un viewport de renderizado alto puede activar el cargador y fusionar dos URL en una sola página indexada. Para conocer el funcionamiento interno y elegir un modo, consulta renderizado.

¿Puede Google leer JavaScript? Sí, esa no es la pregunta.

Google puede ejecutar JavaScript; los riesgos reales son la paridad, la interacción, el estado y el tiempo. Fuente: /technical-seo/javascript-seo/

De izquierda a derecha aparecen rastreo, renderizado e indexación. Del renderizado salen cuatro fallos: paridad, cuando el DOM renderizado no coincide con lo esperado; interacción, cuando el contenido exige desplazarse o hacer clic; estado, cuando depende de cookies o almacenamiento que el renderizador borra; y tiempo, cuando JavaScript retrasa el contenido.

© Patrick Stox LLC · CC BY 4.0 ·

Google procesa las aplicaciones JavaScript en tres fases: “Google processes JavaScript web apps in three main phases: 1. Crawling 2. Rendering 3. Indexing.” (traducción) «Google procesa las aplicaciones web JavaScript en tres fases principales: 1. Rastreo, 2. Renderizado y 3. Indexación». En la fase intermedia ejecuta el JS en una versión actualizada y sin interfaz gráfica de Chrome para construir el DOM que se indexará. “Rendering is important because websites often rely on JavaScript to bring content to the page, and without rendering Google might not see that content.” (traducción) «El renderizado es importante porque los sitios web suelen depender de JavaScript para incorporar contenido a la página y, sin él, es posible que Google no vea ese contenido».

Evidencia de esta afirmación Google processes JavaScript web apps in three main phases: crawling, rendering, and indexing; without rendering, Google might not see JavaScript-provided content. Alcance: Google Search's processing of JavaScript pages; successful rendering does not guarantee indexing or ranking. Confianza: alta · Verificado: Google Search Central: Understand the JavaScript SEO basics

Por tanto, Google sí puede ejecutar tu JavaScript. Las preguntas útiles son más específicas:

  • Paridad — ¿El DOM renderizado contiene realmente lo que crees?
  • Interacción — ¿Hay algo que requiera un desplazamiento o un clic que Google no vaya a realizar?
  • Estado — ¿Dependes de cookies o del almacenamiento local que el renderizador sin estado borra?
  • Tiempo — ¿El contenido crítico queda pospuesto detrás de JavaScript lento o tardío?

En cuanto al tiempo, Google pone en cola para el renderizado una página rastreada que ha devuelto un 200: “the page may stay on this queue for a few seconds, but it can take longer than that.” (traducción) «La página puede permanecer en esta cola unos segundos, aunque también puede tardar más». No se ha publicado un retraso ni un tiempo de espera fijo. Una página que devuelva un estado distinto de 200 o que empiece con una directiva noindex puede saltarse la cola de renderizado en lugar de esperar a que JavaScript la cambie.

Evidencia de esta afirmación Google queues crawled pages with a 200 response for rendering; the page may stay in that queue for a few seconds but can take longer, with no published fixed delay or timeout, and non-200 or initial noindex responses may skip rendering. Alcance: Google Search's documented render-queue behavior; not a guaranteed or universal timing figure. Confianza: alta · Verificado: Google Search Central: Understand the JavaScript SEO basics

La mecánica de cómo renderiza Google —el servicio de renderizado web, la ausencia de estado, el almacenamiento en caché y el mito de las «dos oleadas»— se explica en la página sobre renderizado. Aquí me centraré en los problemas prácticos y sus soluciones.

Los enlaces deben ser anclas <a href> reales

Este es el error de SEO para JavaScript más común. “Google can only discover your links if they are <a> HTML elements with an href attribute.” (traducción) «Google solo puede descubrir tus enlaces si son elementos HTML «a» con un atributo href». Un <div> con un controlador onclick, aunque sea pulsable, no es visible para Google como enlace: no lo seguirá y puede que no rastree las páginas que dependan de él para su descubrimiento. Es perfectamente válido inyectar enlaces con JavaScript siempre que terminen como anclas <a href> reales en el DOM renderizado. Sin embargo, esas anclas se analizan después de ejecutar JavaScript: aparecer en el DOM renderizado hace que el enlace sea detectable, pero no garantiza que la URL se rastree, se indexe o se trate igual que un enlace presente en el HTML inicial.

Evidencia de esta afirmación Google can reliably discover links only when they are HTML anchor elements with an href attribute. Alcance: Link discovery by Google Search; this does not claim that every discovered URL will be crawled or indexed. Confianza: alta · Verificado: Google Search Central: Make your links crawlable

Contenido de carga diferida y controlado por interacción

El renderizador no se comporta como un usuario curioso: “Google Search does not interact with your page.” (traducción) «La Búsqueda de Google no interactúa con tu página». No se desplaza, no hace clic ni pasa el cursor. Por eso no verá el contenido que solo se cargue tras uno de esos eventos.

La recomendación de Google es cargar el contenido cuando entra en el viewport, no cuando actúa el usuario: “make sure that your lazy-loading implementation loads all relevant content whenever it is visible in the viewport,” (traducción) «asegúrate de que la implementación de carga diferida cargue todo el contenido pertinente cuando sea visible en el viewport», y “don’t add lazy-loading to content that is likely to be immediately visible when a user opens a page.” (traducción) «no apliques carga diferida al contenido que probablemente sea visible en cuanto el usuario abra la página». Usa Intersection Observer o loading="lazy" nativo para las imágenes, nunca un controlador de desplazamiento o clic, de modo que el contenido se cargue durante un renderizado normal.

Evidencia de esta afirmación Google Search does not interact with a page, so lazy-loaded content should load when it becomes visible in the viewport rather than requiring user interaction. Alcance: Google Search's documented rendering behavior for lazy-loaded content; other crawlers can behave differently. Confianza: alta · Verificado: Google Search Central: Fix lazy-loaded content

Desplazamiento infinito: cuando dos páginas se indexan como una

Un viewport alto de Google puede activar el desplazamiento infinito y unir dos páginas bajo una sola URL indexada. Fuente: /technical-seo/javascript-seo/

Un viewport normal termina tras la primera página. El viewport de renderizado de Google puede ser más alto, alcanzar el disparador, cargar la página siguiente sin desplazamiento real y anexarla al mismo DOM. Google puede indexar entonces el contenido de ambas bajo una URL.

© Patrick Stox LLC · CC BY 4.0 ·

Este es el problema que casi nadie explica, y merece una sección completa.

Googlebot puede renderizar con un viewport considerablemente más alto que una ventana de navegador habitual. Google no publica su tamaño exacto —y este puede cambiar—, así que no diseñes para una cifra concreta: prueba tu propia implementación. Lo importante es el mecanismo. Si el cargador del desplazamiento infinito se activa según la posición del desplazamiento o la altura del viewport, uno más alto de lo esperado puede activar el cargador durante el propio renderizado y añadir al mismo DOM el contenido del siguiente artículo o producto. El contenido de dos URL distintas queda renderizado junto y Google puede indexarlo como una sola página. En mi experiencia, “occasionally, two pages get indexed as one” (traducción) «en ocasiones, dos páginas se indexan como una sola». Me han comunicado páginas «no indexadas» que en realidad se habían indexado dentro de otra página —normalmente la entrada anterior del feed— porque “when Google resized the viewport to be longer … it triggered the infinite scroll and loaded another article in when it was rendering.” (traducción) «cuando Google alargó el viewport… activó el desplazamiento infinito y cargó otro artículo mientras renderizaba». Comprueba si tu configuración hace esto inspeccionando el HTML renderizado de una URL que debería detenerse antes. No des por hecho un tamaño ni que la implementación sea segura.

Hay dos capas para hacer esto bien.

Haz que el desplazamiento infinito sea compatible con la búsqueda desde el principio. Ofrece una carga paginada debajo del desplazamiento infinito. Cada bloque debe tener “its own persistent, unique URL,” (traducción) «su propia URL única y permanente»; el contenido de cada URL debe ser el mismo cada vez que se cargue; debes evitar parámetros relativos como ?date=yesterday; y conviene “link sequentially to the individual URLs so that search engines can discover the URLs in a paginated set,” (traducción) «enlazar secuencialmente las URL individuales para que los motores de búsqueda puedan descubrirlas en un conjunto paginado». Cuando se cargue un nuevo bloque al desplazarse, debes “update the displayed URL using the History API.” (traducción) «actualizar la URL mostrada mediante la History API». Usa enlaces de paginación <a href> reales y URL únicas; “don’t use URL fragment identifiers” (traducción) «no uses identificadores de fragmento de URL» —la parte situada tras #— para los números de página, porque Google los ignora. Como digo en mi guía de SEO para JavaScript, “if you have an infinite scroll setup, I still recommend a paginated page version so that Google can still crawl properly.” (traducción) «Si tienes una configuración de desplazamiento infinito, sigo recomendando una versión paginada para que Google pueda rastrearla correctamente».

Si un cargador defectuoso está fusionando páginas, la solución más rápida es directa: “block the JavaScript file that handles the infinite scrolling so the functionality can’t trigger.” (traducción) «bloquea el archivo JavaScript que gestiona el desplazamiento infinito para que la función no pueda activarse». Si el cargador no puede ejecutarse durante el renderizado, tampoco puede añadir el contenido de la página siguiente y cada URL vuelve a renderizarse por separado.

Soft-404 después del enrutamiento del lado del cliente

Las aplicaciones de una sola página pueden cambiar el contenido sin modificar el código de estado HTTP, por lo que una vista «no encontrada» puede seguir devolviendo 200. Google puede clasificar esa respuesta como un soft 404 después de evaluar el contenido, pero una petición estática por sí sola no demuestra que Google lo haya hecho. Hay dos correcciones: navegar con la History API y, cuando el recurso no exista de verdad, dirigir a una URL que devuelva un estado 404 real o añadir una etiqueta noindex. Tampoco debes depender de fragmentos de URL para el enrutamiento: “the AJAX-crawling scheme has been deprecated since 2015, so you can’t rely on URL fragments to work with Googlebot.” (traducción) «El sistema de rastreo AJAX está obsoleto desde 2015, así que no puedes confiar en que los fragmentos de URL funcionen con Googlebot».

Una redirección del lado del cliente plantea el mismo problema de evidencia: la respuesta inicial puede seguir siendo 200 hasta que se ejecute JavaScript. Google admite las redirecciones de JavaScript solo como alternativa cuando no son posibles las redirecciones del servidor o mediante actualización meta. Informa por separado del estado estático y de la navegación renderizada observada; no reescribas el estado HTTP en la auditoría ni llames redirección a cada cambio de URL renderizado.

No bloquees JavaScript o CSS en robots.txt

Google no renderizará JavaScript desde archivos bloqueados ni en páginas bloqueadas. Una regla de robots.txt que impida acceder al paquete —o al directorio /_next/, /static/ o /assets/ que lo contiene— puede romper por completo el renderizado: Google obtiene la carcasa, no puede ejecutar los scripts e indexa una página vacía. Comprueba en los recursos de la página de la inspección de URLs si hay elementos bloqueados.

Directivas de paridad DOM y robots conscientes de la etapa

Compara el HTML inicial (Ver código fuente) con el HTML renderizado (inspección de URLs). El contenido que solo existe en el HTML renderizado puede indexarse si el renderizado se completa. El contenido que no aparece en ninguno de los dos estados no existe para Google.

Google documenta un riesgo relacionado con el orden de las fases: “When Google encounters the noindex tag, it may skip rendering and JavaScript execution, which means using JavaScript to change or remove the robots meta tag from noindex may not work as expected.” (traducción) «Cuando Google encuentra la etiqueta noindex, puede omitir el renderizado y la ejecución de JavaScript; por eso, usar JavaScript para cambiar o eliminar noindex de la etiqueta meta robots podría no funcionar como se espera». Si el HTML inicial incluye un noindex que pretendías sustituir con JavaScript, Google puede actuar sobre esa directiva inicial y no ejecutar nunca el script que debía eliminarla.

No conviertas esto en una regla universal según la cual «gana lo renderizado». La conciliación depende de cada campo:

CampoLo que puede establecer la comparación inicial/renderizado
Contenido principal y enlacesGoogle puede usar contenido y enlaces <a href> reales generados durante el renderizado si este tiene éxito. La presencia en el HTML inicial reduce esa dependencia.
Título y descripciónGoogle puede procesar metadatos establecidos con JavaScript, pero elige los enlaces de título y los fragmentos a partir de varias fuentes. Muestra ambos estados; no afirmes que estén garantizados el valor renderizado, el primero o el último.
Directivas de robotsUn noindex inicial puede hacer que Google omita el renderizado, por lo que quizá nunca vea que JavaScript lo elimina. Añadir restricciones más tarde no demuestra que una restricción anterior se haya cancelado.
CanonicalLa guía de Google sobre JavaScript aconseja no establecer un valor en el código fuente para después cambiarlo con JavaScript. Usa un único método y verifica una sola declaración en la cabecera renderizada.
Estado HTTP y redirecciónJavaScript no puede cambiar el estado de la respuesta ya recibida. Registra por separado el estado estático y cualquier navegación renderizada que observes.

Por esta razón, una auditoría debe mantener separados el código fuente, el estado renderizado, los encabezados de respuesta y el estado observado en la búsqueda, en vez de reducirlos a un único valor «efectivo».

Elija un modo de renderizado que coloque el contenido en el DOM

La mayor parte del riesgo del SEO para JavaScript depende de cómo se genera el HTML. En resumen, SSR, el renderizado estático o prerenderizado y la hidratación colocan el contenido en el DOM —o lo hacen con rapidez—, lo que reduce la dependencia de que el renderizador funcione correctamente. El renderizado íntegro del lado del cliente deja más elementos supeditados a que el proceso termine bien, a tiempo y en cada ocasión. El renderizado dinámico es una solución alternativa, no una opción equivalente: la guía de Google, actualizada por última vez en diciembre de 2025, lo describe como una medida provisional, no como una solución a largo plazo, y recomienda en su lugar el renderizado del lado del servidor, el renderizado estático o la hidratación. Como lo explico en mi guía de SEO para JavaScript, “any kind of SSR, static rendering, and prerendering setup is going to be fine for search engines.” (traducción) «Cualquier configuración de SSR, renderizado estático o prerenderizado funcionará bien para los motores de búsqueda». El menú completo —CSR, SSR, SSG, hidratación, ISR, edge, streaming y renderizado dinámico—, con una tabla de ventajas y desventajas, está en la página sobre renderizado. Google también describe el renderizado del lado del servidor o el prerenderizado como una buena opción para los usuarios y los rastreadores. Evidencia de esta afirmación Google describes server-side rendering or pre-rendering as a good idea because it makes a website faster for users and crawlers. Alcance: Google Search guidance for JavaScript sites; the source does not prescribe one framework or guarantee indexing. Confianza: alta · Verificado: Google Search Central: Understand the JavaScript SEO basics

Cómo hacer las pruebas

La inspección de URLs de Search Console es la fuente de referencia: ejecuta una prueba en directo y examina el HTML renderizado, la captura de pantalla y los recursos de la página y mensajes de consola para saber qué se cargó y qué falló. La prueba de resultados enriquecidos ofrece una comprobación rápida del HTML renderizado. A escala, usa un rastreador que ejecute JavaScript —Ahrefs Site Audit o Screaming Frog en modo de renderizado de JS— para comparar el HTML inicial y el renderizado en todo el sitio.

Una diferencia de renderizado diagnostica, no puntúa: investiga los elementos esenciales que aparecen solo tras JavaScript o desaparecen después.

Una página ilustrativa tiene un título en ambos estados, 18 encabezados inicialmente y 19 renderizados, 42 enlaces internos inicialmente y 71 renderizados, ninguna descripción de producto inicialmente y 12 renderizadas, y seis canonical inicialmente pero uno renderizado. Los datos son sintéticos.

JavaScript no es malo para el SEO ni es perjudicial por naturaleza. Simplemente es distinto de aquello a lo que muchos profesionales del SEO están acostumbrados. Trabaja con los desarrolladores, introduce el contenido importante en el DOM y deja que las herramientas de Google —no tus suposiciones— determinen qué se ha renderizado.

Adónde ir a continuación: el clúster SEO de JavaScript

Este artículo central es el mapa. Cada tema siguiente cuenta con su propia guía detallada:

Renderizado y arquitectura

  • SEO para un CMS headless — cómo afectan las interfaces desacopladas al rastreo, el renderizado, los metadatos, los sitemaps y las etiquetas canonical; qué modo de renderizado elegir; y qué fallos específicos de una arquitectura headless debes conocer.

Guías específicas del marco

  • SEO para React — por qué la prioridad de CSR en React crea riesgos de indexación, cómo renderiza Google las aplicaciones React, React Router y la History API, react-helmet-async para las etiquetas meta y cuándo conviene recurrir a Next.js.
  • SEO para Angular — la configuración de SPA predeterminada, @angular/ssr —sucesor de Angular Universal—, los servicios Title y Meta integrados, el prerenderizado y la hidratación incremental de las versiones modernas de Angular.
  • SEO para Next.js — Pages Router frente a App Router, la Metadata API, next/image y Core Web Vitals, la sincronización de ISR con Googlebot, los sitemaps y los errores de SEO más habituales en Next.js.
  • SEO para Nuxt — SSR de forma predeterminada, useSeoMeta(), los modos de renderizado de Nuxt, el ecosistema de módulos @nuxtjs/seo y su comparación con Vue sin metaframework respecto a la indexabilidad.
  • SEO para Vue — el CSR predeterminado de Vue 3 y sus consecuencias para los rastreadores, createWebHistory(), @unhead/vue, las opciones de prerenderizado sin metaframework y cuándo Nuxt es la decisión adecuada.
  • SEO para Svelte — Svelte frente a SvelteKit, el SSR predeterminado de SvelteKit, <svelte:head>, la trampa de adapter-static + ssr: false, las opciones de adaptadores y las implicaciones para los rastreadores de IA.
  • SEO para Astro — cero JavaScript de forma predeterminada, arquitectura de islas, @astrojs/sitemap, astro:assets, View Transitions y la History API, el comportamiento alternativo de Server Islands y las ventajas de Astro para Core Web Vitals.

Añadir una nota de experto

Fijar una cita de experto

¿Es una persona nueva? Crea su perfil sin reclamar en /admin/experts/ → Fijar una cita de experto primero.