SEO JavaScript : comment Google indexe les SPA et les sites React

La file de rendu en deux vagues de Google, les pièges du CSR, la différence entre SSR, SSG et ISR, et des méthodes concrètes pour vérifier que votre site JavaScript est correctement indexé.

Comment Google rend le JavaScript : fonctionnement

Pour une page HTML classique, Google ne fait qu’une étape : il télécharge le HTML et voit immédiatement le contenu. Pour une page JavaScript, il en faut trois : télécharger le HTML, charger le bundle JS, puis l’exécuter dans un Chromium sans interface graphique (headless) pour obtenir le DOM final.

Google utilise son propre moteur de navigation basé sur Chromium, mis à jour régulièrement. Les fonctionnalités JavaScript modernes (ES2020+, import dynamique, WebAssembly) sont donc comprises par Googlebot. Le problème ne vient pas de la prise en charge de la syntaxe, mais du délai de rendu et des contraintes de ressources pendant le crawl.

Trois stratégies de rendu JavaScript : le SSR et le SSG/ISR livrent un HTML prêt à l’emploi, tandis que le CSR construit le DOM dans le navigateur et arrive dans la seconde vague d’indexation.

Le rendu en chiffres

3–4 s

Délai de rendu

Si le JS ne s’exécute pas en environ 3 à 4 secondes, Google indexe une page partiellement rendue

≈ 150 ms

Temps CSS

Un chargement de ressources supérieur à 150 ms peut bloquer le rendu et dégrader l’efficacité du crawl

2 vagues

Indexation

Le contenu JS arrive dans l’index avec un délai par rapport au contenu HTML : parfois de quelques jours, parfois de quelques semaines

100 %

Google evergreen

Googlebot se met à jour avec la dernière version stable de Chromium : les fonctionnalités JS modernes sont entièrement prises en charge

Indexation en deux vagues : pourquoi le contenu JS arrive plus tard dans l’index

Google découpe l’indexation en deux étapes. La première vague est le crawl : Googlebot télécharge le HTML et tous les liens découverts. La seconde vague est le rendu : le robot met la page en file d’attente, exécute le JS et indexe le DOM final.

Entre ces deux vagues, il peut s’écouler de quelques heures à plusieurs semaines, selon l’autorité du site, le budget de crawl et la taille de la file de rendu de Google. Si vos textes clés, vos H1, vos balises meta ou vos liens ne sont générés que par JS, ils arriveront dans l’index avec un délai.

Conclusion pratique : tout le contenu critique pour le SEO (title, description, H1, liens, données structurées) doit figurer dans la réponse HTML du serveur. Il entre alors dans la première vague d’indexation, sans délai.
L’indexation en deux vagues explique pourquoi les nouvelles pages d’un SPA « disparaissent » de l’index pendant 2 à 4 semaines après leur publication, alors que leur HTML est bien accessible.

Le CSR, principal piège du SEO

Le CSR (Client-Side Rendering) consiste à envoyer un <div id="root"></div> vide depuis le serveur, puis à construire tout le HTML dans le navigateur une fois le bundle JS chargé. React, Vue et Angular en mode SPA fonctionnent ainsi par défaut.

Du point de vue du SEO, le CSR pose problème pour plusieurs raisons : 1) le rendu n’intervient qu’en seconde vague ; 2) les ressources bloquées par le crawler (scripts tiers, CDN soumis à robots.txt) ne se chargent pas, et la page s’affiche de façon incomplète ; 3) toute erreur JS produit une page vide dans l’index.

html
<!-- CSR: what Google sees in the first wave -->
<html>
  <head>
    <title></title> <!-- empty -->
  </head>
  <body>
    <div id="root"></div> <!-- no content -->
    <script src="/bundle.js"></script>
  </body>
</html>
Erreur critique : générer le <title>, la <meta name="description"> et le <h1> uniquement en JavaScript côté client. Google reçoit alors des valeurs vides ou par défaut lors du premier crawl, et indexe la page sans elles.

SSR, SSG et ISR : lequel choisir pour le SEO

La solution aux problèmes du CSR tient à la génération du HTML côté serveur. Il existe trois approches principales, chacune optimale dans son propre scénario.

Trois approches de rendu JavaScript et leur impact sur le SEO.

Comparaison des approches de rendu

ApprocheHTML sur le serveurSEODonnées dynamiques
CSRNonFaibleComplètes
SSROui (à chaque requête)ExcellentÉlevées
SSGOui (au build)ExcellentNon (reconstruction nécessaire)
ISROui (à intervalle programmé)ExcellentVia la revalidation
Approches de rendu et cas d’usage adaptés :
ApprocheIdéal pour
CSRSPA authentifiées, tableaux de bord
SSRPages personnalisées, catalogues
SSGBlog, pages d’atterrissage, documentation
ISRCatalogues de prix, actualités

SSR (Server-Side Rendering) : le HTML est généré sur le serveur à chaque requête. Les données sont à jour au maximum, mais la charge serveur est plus élevée. Dans Next.js, generateMetadata et les composants async de l’App Router assurent le SSR par défaut.

SSG (Static Site Generation) : le HTML est généré une seule fois au moment du build et servi comme fichier statique. Le TTFB est le plus court, ce qui est idéal pour le SEO. Inconvénient : toute modification des données impose une reconstruction.

ISR (Incremental Static Regeneration) : une formule hybride. Les pages sont construites de façon statique, puis, après une période de revalidation (revalidate: 3600), le serveur les régénère en arrière-plan à la requête suivante. Dans Next.js, c’est l’approche standard pour la plupart des pages.

typescript
// Next.js App Router — SSG + ISR
export const revalidate = 3600; // revalidate every hour

export async function generateMetadata(): Promise<Metadata> {
  return {
    title: 'Product Catalogue',
    description: 'Full range with up-to-date prices',
  };
}

// All critical content is server-rendered:
export default async function CatalogPage() {
  const products = await fetchProducts(); // server fetch
  return (
    <main>
      <h1>Product Catalogue</h1>
      {products.map(p => <ProductCard key={p.id} {...p} />)}
    </main>
  );
}

Liens dynamiques et navigation

Googlebot ne comprend que les liens au format <a href="/url">. Les liens implémentés via onClick, button, data-href ou window.location sont invisibles pour le crawler. Les pages accessibles uniquement par ce type de navigation risquent donc de ne pas être indexées.

  • Utilisez <a href> pour tous les liens de navigation, et non un button onClick avec router.push()
  • Pagination par paramètres d’URL (?page=2) : Googlebot crawle ces URL si elles figurent dans le HTML
  • Routeur SPA : les composants <Link> de Next.js et de React Router génèrent de vraies balises <a> côté serveur
  • Navigation par ancre (#ancre) : elle ne crée pas d’URL distinctes dans l’index. Ne l’utilisez pas pour un contenu qui doit être positionné de manière indépendante
  • Menus dynamiques : si les éléments de menu s’affichent depuis une API après le chargement de la page, Google peut ne pas les découvrir avant le rendu
Vérification : dans Google Search Console → Inspection d’URL → « View as Googlebot » affiche les liens que le crawler a trouvés sur la page. Si un lien dynamique n’apparaît pas dans cette liste, Googlebot ne peut pas le voir.

Lazy load et défilement infini

Les images en loading="lazy" sont chargées par Googlebot : le crawler moderne prend en charge le lazy loading. Mais une condition s’impose : l’image doit figurer dans le DOM avec un attribut src correct dès le SSR. Si le src est défini par JavaScript dans le navigateur, le crawler voit une balise vide.

Le défilement infini nécessite un chemin explorable vers chaque élément pertinent. Proposez des URL séquentielles et des liens classiques qui fonctionnent sans clic sur un bouton, puis vérifiez avec l’Inspection d’URL ou un crawl que le HTML rendu expose bien le contenu voulu.

MotifVu par Googlebot ?Recommandation
<img src="/img.webp" loading="lazy">OuiÀ utiliser
<img data-src="/img.webp"> (JS définit le src)NonÀ éviter
Défilement infini sans URLPremier écran seulementAjouter une pagination
Contenu derrière un bouton « Afficher plus »NonAfficher une partie dans le HTML
Contenu en onglets (onglets masqués)Oui, avec délaiDupliquer dans le HTML

Diagnostic : comment vérifier le rendu JavaScript

La question de diagnostic clé est : « Que voit Googlebot sur ma page ? » Plusieurs outils permettent d’y répondre.

Outils de diagnostic

  • Google Search Console → Inspection d’URL : affiche une capture d’écran de la page après rendu par Googlebot, ainsi que la liste des ressources et des liens découverts. C’est la méthode de vérification la plus directe.
  • « View as Googlebot » dans la GSC : lance le crawler réel et renvoie le HTML après rendu. Comparez-le avec le HTML source.
  • curl ou wget : récupèrent le HTML brut, sans JS. Si les balises meta et le contenu clés figurent dans la sortie de curl, ils seront présents dès la première vague d’indexation.
  • Désactiver JavaScript dans Chrome DevTools (F12 → Ctrl+Maj+P → « Disable JavaScript ») : une façon rapide de voir la page comme le crawler, sans rendu.
  • Screaming Frog avec rendu : le paramètre « Spider > Configuration > Rendering > Googlebot » permet de crawler le site avec rendu JS et de voir les liens découverts après rendu.
Exemple de configuration Next.js pour SSR/SSG :
bash
# Check what Google sees without JS rendering:
curl -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
  https://example.com/page

# Find all title / meta description / h1 in HTML response:
curl -s https://example.com/page | grep -E '<title>|<meta name="description"|<h1'

Checklist du SEO JavaScript

Contrôles clés

  • Le title et la meta description figurent dans la réponse HTML du serveur (SSR/SSG), et non générés par JS
  • Le H1, les H2 et le contenu principal sont accessibles sans JavaScript
  • Les liens de navigation utilisent <a href>, et non onClick ou button
  • Les données structurées (JSON-LD) figurent dans le <head> de la réponse HTML
  • Les images ont un src statique dans le HTML ; loading="lazy" seulement pour les images hors LCP
  • Le fichier robots.txt ne bloque pas les fichiers JS et CSS nécessaires au rendu
  • Aucune erreur JS ne bloque le rendu (à vérifier dans la console de Chrome DevTools, sur la page)
  • Core Web Vitals : LCP, INP et CLS atteignent les valeurs seuils de Google
  • Pagination par paramètres d’URL, et non uniquement par état JS
  • URL canoniques (<link rel="[canonical](/glossary/canonical)">) présentes dans le HTML, et non définies par JS

FAQ

Google peut-il indexer le JavaScript ?
Oui. Googlebot utilise Chromium Evergreen et peut exécuter le JS moderne. Le problème n’est pas la prise en charge, mais le délai : le rendu intervient en seconde vague, qui peut arriver quelques jours ou quelques semaines après le crawl du HTML.
Un site React ou Next.js est-il automatiquement bien indexé ?
Next.js avec SSR ou SSG : oui, à condition d’être correctement configuré. Une SPA React classique (Create React App, Vite sans SSR) fonctionne en CSR par défaut, ce qui nuit au SEO. L’essentiel est de générer côté serveur les balises meta, le H1 et le contenu principal.
Faut-il recourir au prerendering ou au rendu dynamique ?
Le rendu dynamique (servir un HTML différent à Googlebot et aux utilisateurs) est une approche dépassée. Google le tolère mais ne le recommande pas. La bonne voie est le SSR ou le SSG, qui servent le même HTML complet à tout le monde.
Puis-je utiliser React.lazy et le code splitting ?
Oui. Le code splitting avec React.lazy et les imports dynamiques améliore les performances sans nuire au SEO, à condition que le contenu critique (H1, texte principal) soit déjà présent dans le HTML initial. Les composants chargés à la demande seront tout de même récupérés par Googlebot lors du rendu.
Comment vérifier que mon site est correctement indexé ?
Utilisez Google Search Console → Inspection d’URL. Demandez le rendu et comparez la capture d’écran à ce que voit un utilisateur. Vérifiez aussi avec curl la présence du title, du H1 et de la meta description dans la réponse HTML, sans JS.

Check it with SpiderHead

Free and local: run the audit on your own machine.

Try it