SEO & GEO

¿Por qué Google no indexa mi sitio en React?

By Jake Luo · Published 7 sept 2026

Casi siempre porque la página que recibe un rastreador no es la que ves tú. Una app de React que se renderiza en el navegador sirve un esqueleto HTML casi vacío y lo rellena con JavaScript, y aunque Google sí ejecuta ese JavaScript, lo hace en una pasada posterior y no en el momento del rastreo. Todo lo que se decide en la primera pasada — si una página es duplicada, cuál es la URL canónica, qué versión de idioma corresponde — se decide sobre ese esqueleto. Así que antes de cambiar nada, lee el HTML en bruto que devuelve tu servidor en lugar de la página que pinta tu navegador.

La página que recibe un rastreador no es la que ves tú

Abre tu sitio en producción y elige ver código fuente, no inspeccionar. Inspeccionar te muestra el DOM después de que tu JavaScript se haya ejecutado; ver código fuente te muestra los bytes que envió realmente el servidor. En una app de React renderizada en el cliente esos bytes suelen ser un título, unas pocas etiquetas link, un contenedor vacío y un bundle de scripts. Ese documento es lo primero que lee un rastreador, y en un sitio joven puede ser la única versión que alguien lea durante un buen tiempo.

Google explica abiertamente que trata el JavaScript en fases separadas: rastrea la URL, pone la página en cola para renderizarla e indexa lo que sale de ahí — y el renderizado se aplaza en lugar de ser inmediato. De ahí salen dos consecuencias. La primera es la evidente: el contenido que solo existe cuando corre el bundle se indexa tarde, si es que se indexa. La segunda hace más daño porque nunca se resuelve sola. Hay señales que solo se leen de esa primera respuesta, y ningún renderizado posterior las rescata.

La etiqueta canónica es el caso más claro. La propia guía de Google dice que el elemento canónico va dentro de la cabecera del documento, y lo mismo vale para las anotaciones hreflang que conectan las variantes de idioma. Una etiqueta que tu framework inyecta después — en el cuerpo, o cuando la cabecera ya se ha enviado — es una etiqueta que no estaba cuando se tomó la decisión. La página se ve correcta en un navegador, porque el navegador la aplica igualmente. Simplemente llega tarde para el único lector cuya opinión intentabas cambiar.

Averigua qué recibió Google de verdad

Esto lleva unos veinte minutos y zanja la duda antes de que reescribas nada. Hazlo contra la URL en producción, no contra una vista previa.

  1. Lee la respuesta en bruto. Descarga la página con curl o usa ver código fuente. Hazle dos preguntas a lo que vuelve: ¿está en ese texto el contenido por el que quieres posicionar, y está la etiqueta canónica dentro del elemento head y no más abajo del documento? Si la respuesta a cualquiera de las dos es no, ya tienes el problema.
  2. En Search Console lee la página rastreada, no la prueba en vivo. La inspección de URL muestra las dos. La prueba en vivo es una descarga nueva hecha en ese momento; el HTML rastreado es lo que se guardó la última vez. Cuando ambas difieren, cree a la copia rastreada: esa discrepancia ya es el hallazgo.
  3. Pide directamente una URL interna. Los enrutadores del cliente pueden generar rutas que el servidor no sirve. Abre una de tus páginas internas en una pestaña limpia, o pídela con curl, y confirma que responde con su propio contenido en lugar de redirigir a la portada o devolver una página que dice que no hay nada y aun así informa de éxito.
  4. Comprueba que sirves un solo host, no tres. Pide la forma con www, la forma sin www y la forma insegura de tu dominio. Dos de las tres deberían redirigir a la tercera. Si más de una sirve el sitio entero, has publicado el mismo sitio en dos direcciones y le has pedido a Google que elija.

El fallo que se escondió de nuestras propias pruebas

Publicamos AgentCeres — el AI Growth Officer, en agentceres.com — sobre un framework de React, y perdimos meses de indexación por una versión de este problema que todas nuestras comprobaciones daban por sana. Merece contarse entero, porque cada parte falló de una forma que parecía un acierto.

Search Console marcó un bloque grande de nuestras páginas como duplicadas sin canónica seleccionada por el usuario, es decir: no encontró ninguna canónica en la que confiar y eligió una por su cuenta. La etiqueta estaba. Estaba a unos cuarenta kilobytes dentro de la respuesta, porque el framework envía los metadatos en streaming en cualquier página que renderiza dinámicamente, mientras que el elemento head se había cerrado alrededor de kilobyte y medio desde arriba. Todos los navegadores la aplicaban. La primera pasada de rastreo nunca la vio.

El motivo de que esas páginas fueran dinámicas fue el segundo fallo. Una docena de rutas que creíamos prerenderizadas en el build habían dejado de estarlo sin avisar: un componente de cabecera compartido llamaba a un helper de traducción que lee cabeceras de la petición, y leer una cabecera de la petición basta para volver dinámica una página. La tabla de rutas del propio build seguía imprimiéndolas como estáticas. El manifiesto de archivos HTML generados no contenía ninguna. El resumen y el artefacto se contradecían, y nosotros veníamos leyendo el resumen.

La tercera parte es la que hay que llevarse. Los frameworks que envían metadatos en streaming suelen mantener una lista de rastreadores que reciben el comportamiento bloqueante de antes, y el nuestro traía esa lista por defecto. Googlebot no estaba en ella. La herramienta de inspección de Google — el rastreador que hay detrás del botón de prueba en vivo — sí. Así que el botón que pulsábamos para revisar nuestro trabajo descargaba la versión buena todas y cada una de las veces, mientras los rastreos normales seguían recibiendo la rota. Si tu herramienta de verificación es un caso especial dentro de tu propio stack, no es verificación.

Dos notas al pie, ambas baratas. Nuestro host con www servía el sitio entero sin redirigir, así que Google lo había indexado como una segunda copia y había degradado la dirección de nuestro sitemap; se arregló con dos líneas de middleware. Y si te tienta el ajuste por rastreador, recuerda que una CDN delante de tu origen suele cachear sin fijarse en quién pidió, de modo que la variante que caiga en la caché es la que recibirá el siguiente rastreador. Detrás de una CDN, tratar de forma especial a un rastreador no es una regla en la que puedas apoyarte.

Qué cambiar, en el orden que compensa

  • Prerenderiza las páginas que quieres que encuentren. Páginas de marketing, documentación, cualquier cosa que un desconocido pueda buscar: genera el HTML en el build. La salida estática esquiva el problema entero, porque la primera pasada ya trae tanto el contenido como las etiquetas.
  • Renderiza en servidor lo que de verdad tenga que ser dinámico. Una página que depende de la petición también puede devolver HTML completo. Lo que importa es que la primera respuesta esté completa, no que se haya calculado por adelantado.
  • Mantén título, descripción, canónica e idioma en la cabecera de esa primera respuesta. Si tu framework puede aplazarlas, busca el ajuste que lo impide y confirma el arreglo leyendo el HTML en bruto, no el DOM renderizado. Este es el paso que la gente cree haber hecho.
  • Dale a cada página una URL real y un enlace real hacia ella. Las rutas que viven detrás de un fragmento o de un manejador de clic no son rastreables. Los rastreadores siguen elementos de anclaje con href, así que una navegación hecha de botones es una navegación que Google no puede recorrer.
  • Elige un host y redirige los demás. Después envía un sitemap que liste solo la forma elegida, para que tus propias declaraciones no se contradigan entre sí.

Nada de esto es una estrategia de posicionamiento. Es la condición previa para tenerla, y merece la pena hacerlo en una tarde precisamente para no volver a pensar en ello. Cuando tus páginas se lean de verdad, las preguntas que deciden si rinden algo son por qué una página perfectamente buena sigue sin tráfico y de dónde salen realmente las primeras visitas. Y si prefieres no mantener esta tubería, un generador de sitios estáticos con un editor sobre Git evita la cuestión del renderizado por construcción, porque lo que despliega ya es HTML terminado.

FAQ

¿Google indexa los sitios hechos con JavaScript?
Sí. Googlebot ejecuta JavaScript e indexa aquello en lo que se convierte la página, pero lo hace en una pasada aplazada y no durante el rastreo, así que todo lo que solo existe después de tu bundle se indexa más tarde y con menos fiabilidad que el contenido que ya está en el HTML. Las partes que solo se leen de esa primera respuesta — la etiqueta canónica y las anotaciones hreflang, entre otras — no las rescata el renderizado. Trata el renderizado en el cliente como un retraso más un riesgo, no como un bloqueo absoluto.
¿Necesito renderizado en servidor para arreglarlo?
Normalmente no. El prerenderizado estático basta para las páginas que un desconocido llegaría a buscar, y es más simple y más barato de operar que el renderizado en servidor. Reserva el servidor para páginas cuyo contenido dependa de verdad de quién pregunta. La regla que importa no es qué técnica eliges sino si la primera respuesta ya está completa: una página prerenderizada y una renderizada en servidor lo cumplen, y una renderizada en el cliente no.
La prueba en vivo de Search Console se ve perfecta, ¿por qué no se indexa mi página?
Porque la prueba en vivo es una descarga y un renderizado hechos en ese momento, y tu stack puede entregarle una respuesta distinta de la que recibe un rastreo normal — el nuestro lo hacía, porque la lista por defecto de rastreadores que reciben metadatos bloqueantes incluía la herramienta de inspección de Google pero no a Googlebot. Lee en su lugar el HTML rastreado y guardado en ese mismo informe. Cuando ambos difieren, la copia rastreada es la que se indexa, y la prueba en vivo te está hablando de una página que no se le sirve a nadie más.
Related questions
¿Por qué mi sitio web no recibe tráfico?¿Cómo hago SEO para un sitio web completamente nuevo?How do I get traffic to a website I built with AI?¿Debería usar IA para crear mi sitio web?

Want this done for you?

AgentCeres is a managed AI marketing team — specialists draft the work, you approve what ships. 14-day free trial, from $39/month.

Start free trialMore answers