Prerendering SEO : quand et comment l'implémenter

Un catalogue e-commerce de 22 000 fiches produit, propulsé par une SPA Vue.js. Trafic organique en chute de 38 % après une refonte. La Search Console affiche des centaines de pages en "Discovered – currently not indexed". Le rendu côté client fonctionne parfaitement dans le navigateur. Mais Googlebot, lui, voit un squelette HTML vide sur la majorité des URLs — parce que le budget de rendering de Google n'est pas illimité et que la file d'attente du Web Rendering Service a ses propres contraintes. Le prerendering aurait évité ce scénario. Encore faut-il savoir quand il est pertinent, et comment l'implémenter sans introduire d'autres régressions.

Ce que "prerendering" signifie réellement — et ce qu'il n'est pas

Le terme est galvaudé. Il recouvre au moins trois réalités techniques distinctes qu'il faut démêler avant de choisir une stratégie.

Static Site Generation (SSG) au build time

Le framework génère le HTML complet de chaque page au moment du build. C'est le prerendering au sens strict : le fichier .html servi au crawler contient tout le contenu, les balises meta, le markup sémantique. Aucun JavaScript n'est nécessaire pour que le contenu soit lisible. Next.js (getStaticProps), Nuxt (nuxt generate), Astro (par défaut) et Gatsby fonctionnent sur ce modèle.

Prerendering dynamique via un headless browser

Un service comme Prerender.io ou Rendertron intercepte les requêtes des crawlers (détectées via le User-Agent), exécute la page dans un headless Chrome, puis sert le HTML résultant. L'utilisateur humain reçoit la SPA classique. C'est du dynamic rendering — un terme que Google a officiellement documenté comme solution acceptable mais temporaire. Google a d'ailleurs retiré la documentation dédiée au dynamic rendering de Search Central en mars 2024, signal clair que cette approche est en fin de vie.

Prerendering au sens de l'API Speculation Rules

Chrome propose depuis la version 109 une API Speculation Rules qui permet de prerender des pages en arrière-plan avant que l'utilisateur ne clique. C'est une optimisation de performance (Core Web Vitals), pas une stratégie de crawl SEO. Ne confondez pas les deux.

Pour cet article, on parle principalement du SSG/prerendering au build time et de ses variantes hybrides (ISR, SSG partiel), qui sont les solutions pérennes pour le SEO. Le dynamic rendering via headless browser est abordé uniquement comme solution transitoire.

Si vous hésitez entre SSR, CSR et SSG, l'article SSR vs CSR : impact réel sur le SEO pose les bases de cette comparaison.

Quand le prerendering est la bonne réponse

Le prerendering n'est pas toujours nécessaire. Voici les critères de décision concrets.

Votre site est une SPA et Googlebot ne voit pas votre contenu

Vérification rapide : ouvrez la Search Console, outil d'inspection d'URL, et comparez le "HTML brut" (ce que Googlebot reçoit) avec la "capture d'écran" (ce que le WRS rend après exécution JS). Si le HTML brut ne contient que le <div id="app"></div> et un bundle JS, vous êtes en CSR pur. L'article Pourquoi Google voit une page blanche sur votre SPA détaille ce diagnostic.

Le prerendering résout ce problème de manière déterministe : le HTML est déjà complet, indépendamment de l'exécution JavaScript.

Votre volume de pages dépasse ce que le WRS peut traiter efficacement

Google utilise un Web Rendering Service (WRS) basé sur une version headless de Chrome pour rendre les pages JavaScript. Ce processus est coûteux en ressources. Sur un site de 22 000 pages produit, le délai entre le crawl initial et le rendering complet peut atteindre plusieurs jours voire semaines. Pendant ce temps, vos pages sont dans un état "discovered but not indexed" — visibles dans la Search Console mais absentes des SERPs.

Le prerendering élimine ce goulet d'étranglement : Googlebot obtient le HTML complet au premier crawl, sans passer par la file de rendering.

Le contenu est relativement stable

Le prerendering au build time excelle pour les contenus qui ne changent pas à chaque requête : fiches produit, articles de blog, pages catégories, landing pages, documentation. Si votre contenu change toutes les 30 secondes (cours de bourse en temps réel, chat en direct), le SSG pur n'est pas adapté — mais l'ISR (Incremental Static Regeneration) peut combler ce gap.

Quand le prerendering N'est PAS la réponse

  • Pages derrière authentification : inutile de prerender des dashboards utilisateur. Googlebot ne les verra pas et ne doit pas les voir.
  • Contenu ultra-personnalisé : si chaque visiteur voit un contenu différent (résultats de recherche internes contextualisés, recommandations ML), le prerendering ne peut capturer qu'une version "par défaut".
  • Sites de moins de 50 pages en SSR : si votre SSR fonctionne correctement et que votre site est petit, ajouter une couche de prerendering est de l'over-engineering. Le SSR suffit.

Implémentation concrète avec les frameworks modernes

Next.js : SSG, ISR et le App Router

Avec le App Router de Next.js 14+, le comportement par défaut des Server Components est déjà du prerendering statique. Next.js détecte automatiquement si une route peut être rendue statiquement.

Pour forcer le prerendering statique d'une page dynamique (fiche produit par exemple) :

// app/products/[slug]/page.tsx
import { Metadata } from 'next'
import { getProduct, getAllProductSlugs } from '@/lib/api'

// Génère les chemins statiques au build time
export async function generateStaticParams() {
  const slugs = await getAllProductSlugs()
  // Pour un catalogue de 22K produits, on peut limiter
  // les pages pré-rendues et laisser l'ISR gérer le reste
  return slugs.map((slug) => ({ slug }))
}

// Metadata SEO générée statiquement
export async function generateMetadata(
  { params }: { params: { slug: string } }
): Promise<Metadata> {
  const product = await getProduct(params.slug)
  return {
    title: `${product.name} — MonCatalogue`,
    description: product.metaDescription,
    alternates: {
      canonical: `https://moncatalogue.fr/products/${params.slug}`,
    },
  }
}

export const revalidate = 3600 // ISR : revalidation toutes les heures

export default async function ProductPage(
  { params }: { params: { slug: string } }
) {
  const product = await getProduct(params.slug)
  return (
    <article>
      <h1>{product.name}</h1>
      <p>{product.description}</p>
      <script
        type="application/ld+json"
        dangerouslySetInnerHTML={{
          __html: JSON.stringify({
            '@context': 'https://schema.org',
            '@type': 'Product',
            name: product.name,
            description: product.description,
            sku: product.sku,
            offers: {
              '@type': 'Offer',
              price: product.price,
              priceCurrency: 'EUR',
              availability: product.inStock
                ? 'https://schema.org/InStock'
                : 'https://schema.org/OutOfStock',
            },
          }),
        }}
      />
    </article>
  )
}

Le revalidate = 3600 active l'ISR : la page est servie depuis le cache statique, puis régénérée en arrière-plan après une heure. C'est le meilleur compromis pour un catalogue produit qui évolue quotidiennement sans être temps réel.

Le piège courant : oublier generateStaticParams et laisser Next.js en mode SSR dynamique par défaut. Vérifiez la sortie du build — Next.js affiche clairement quelles routes sont statiques (○), SSR (λ) ou ISR (●).

Pour approfondir les différences entre ISR, SSR et SSG, consultez ISR, SSR, SSG : quel mode de rendering pour le SEO.

Nuxt 3 : route rules et prerendering sélectif

Nuxt 3 permet un contrôle granulaire du prerendering via les route rules dans nuxt.config.ts :

// nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // Pages statiques : prerendering au build
    '/': { prerender: true },
    '/about': { prerender: true },
    '/blog/**': { prerender: true },

    // Catalogue produit : ISR avec revalidation
    '/products/**': { isr: 3600 },

    // Pages dynamiques pures : SSR
    '/search': { ssr: true },
    '/account/**': { ssr: false }, // CSR pour les pages auth
  },

  // Crawle automatiquement les liens pour découvrir
  // toutes les pages à prerender
  nitro: {
    prerender: {
      crawlLinks: true,
      routes: ['/sitemap.xml'],
      // Concurrence du prerendering — ajustez selon votre CI
      concurrency: 10,
    },
  },
})

L'option crawlLinks: true est particulièrement utile : Nuxt suit automatiquement les liens internes à partir des routes spécifiées pour découvrir et prerender toutes les pages accessibles. Pour un site de 22 000 pages, ajustez concurrency en fonction des ressources de votre pipeline CI/CD — un build avec 10 workers parallèles prend environ 18 minutes sur une machine 4 vCPU.

Astro : prerendering par défaut, opt-in pour le dynamique

Astro inverse le paradigme : tout est statique par défaut. Vous optez explicitement pour le rendu serveur quand nécessaire.

---
// src/pages/products/[slug].astro
// Par défaut, cette page est prerendue au build time
import Layout from '@/layouts/Layout.astro'
import { getCollection } from 'astro:content'

export async function getStaticPaths() {
  const products = await getCollection('products')
  return products.map((product) => ({
    params: { slug: product.slug },
    props: { product },
  }))
}

const { product } = Astro.props
---

<Layout
  title={`${product.data.name} — MonCatalogue`}
  description={product.data.metaDescription}
  canonical={`https://moncatalogue.fr/products/${product.slug}`}
>
  <article>
    <h1>{product.data.name}</h1>
    <p>{product.data.description}</p>
  </article>
</Layout>

L'avantage d'Astro pour le prerendering SEO : zéro JavaScript côté client par défaut. Le HTML servi est aussi léger que possible. Pour un site média ou documentation, c'est le choix optimal en termes de crawl efficiency — Googlebot parse le contenu instantanément, sans attendre d'exécution JS.

Scénario réel : migration d'une SPA Vue.js vers Nuxt avec prerendering

Contexte

Un retailer français opère un site e-commerce de 22 000 fiches produit et 340 pages catégories. Stack initiale : Vue.js 3 en mode SPA, déployé sur un CDN. API REST pour les données produit.

Symptômes avant migration :

  • Search Console : 14 200 pages en "Discovered – currently not indexed"
  • Couverture indexée réelle : 6 800 pages sur 22 340
  • Trafic organique : 28 000 sessions/mois (en baisse de 38 % sur 6 mois)
  • Test d'inspection d'URL : le HTML brut ne contient que le shell applicatif, aucune donnée produit
  • Screaming Frog en mode "JavaScript rendering" : crawl complet en 14 heures. En mode HTML brut : 0 balise title détectée sur les pages produit

Stratégie de migration

L'équipe opte pour Nuxt 3 avec une stratégie de rendering hybride :

  • Pages catégories (340 pages) : prerendering SSG au build time. Contenu stable, mis à jour une fois par jour via un rebuild déclenché par le CMS.
  • Fiches produit (22 000 pages) : ISR avec revalidation toutes les 2 heures. Le premier visiteur (ou Googlebot) déclenche la génération statique ; les requêtes suivantes sont servies depuis le cache.
  • Page de recherche : SSR pur — le contenu dépend entièrement de la query string.
  • Espace compte client : CSR — aucune raison de rendre ces pages côté serveur.

Résultats après 8 semaines

  • Pages indexées : de 6 800 à 21 400 (+215 %)
  • Pages "Discovered – currently not indexed" : de 14 200 à 380 (principalement des URLs paginées avec noindex)
  • Trafic organique : de 28 000 à 52 000 sessions/mois (+86 %)
  • Time to first byte (TTFB) médian : de 2,4s (SSR SPA hydration) à 45ms (HTML statique depuis CDN)
  • Temps de build complet : 22 minutes pour 22 340 pages (CI sur 8 vCPU)

Le facteur déterminant n'est pas la sophistication du framework. C'est le fait que Googlebot reçoit du HTML complet au premier crawl, sans dépendre du WRS.

Les pièges techniques du prerendering

Le piège du build time qui explose

22 000 pages × 1,2 seconde de génération moyenne = 7,3 heures de build séquentiel. Sans parallélisation ni stratégie ISR, le prerendering au build time ne scale pas au-delà de quelques milliers de pages.

Solutions :

  • ISR : ne prérendre au build que les pages à fort trafic (Top 2000 pages par sessions organiques), laisser les autres se générer à la demande.
  • Parallélisation : Next.js et Nuxt supportent la génération concurrente. Augmentez les workers CI.
  • Builds incrémentaux : Netlify et Vercel supportent les builds qui ne régénèrent que les pages modifiées.

L'hydration mismatch sur les pages prerendered

Le HTML statique est généré au build time. Le JavaScript côté client s'hydrate ensuite. Si l'état diffère (date courante, contenu personnalisé, flag feature flipé), React/Vue lèvent un hydration mismatch et re-rendent le DOM entier — ce qui peut temporairement afficher un contenu différent de celui indexé.

Ce sujet est couvert en profondeur dans Hydration mismatch : le bug invisible qui tue votre SEO.

Règle : toute donnée susceptible de varier entre build time et client time doit être rendue exclusivement côté client via useEffect (React) ou onMounted (Vue), sans affecter le contenu SEO-critique (title, H1, description, structured data).

Les meta tags manquantes après un déploiement

Scénario classique : un développeur modifie le composant <Head> dans un layout partagé. Le build passe, les pages sont prégénérées, déployées. Mais un edge case dans le nouveau code fait disparaître la balise canonical sur les 340 pages catégories. Sans monitoring, personne ne le remarque pendant 3 semaines.

C'est exactement le type de régression qu'un outil de monitoring comme Seogard détecte automatiquement : une alerte se déclenche dès qu'une balise meta disparaît sur un lot de pages qui l'avaient précédemment.

Le cache CDN qui sert du stale content aux crawlers

Avec l'ISR, une page peut être servie depuis un cache edge pendant que la version régénérée se propage. Si Googlebot crawle pendant cette fenêtre, il voit le contenu périmé. Pour la plupart des sites, ce n'est pas critique — une heure de décalage sur un prix produit est acceptable. Mais si vous supprimez un produit et que le cache sert encore la page avec un 200, Googlebot continuera de l'indexer.

Configurez des purges de cache explicites pour les suppressions et les redirections :

# Exemple avec l'API Vercel pour purger le cache ISR d'une URL spécifique
curl -X POST "https://api.vercel.com/v1/projects/mon-projet/revalidate" \
  -H "Authorization: Bearer $VERCEL_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "urlPath": "/products/chaise-ergonomique-pro-x1",
    "type": "path"
  }'

# Ou via la fonction revalidatePath dans un webhook Next.js
# pages/api/revalidate.ts
# import { revalidatePath } from 'next/cache'
# revalidatePath('/products/chaise-ergonomique-pro-x1')

Vérifier que le prerendering fonctionne réellement

Déployer du prerendering sans vérifier que Googlebot reçoit bien le HTML attendu, c'est piloter à l'aveugle.

Vérification côté serveur

# Simuler une requête Googlebot pour vérifier le HTML brut
curl -A "Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)" \
  -s "https://moncatalogue.fr/products/chaise-ergonomique-pro-x1" \
  | grep -E '<title>|<meta name="description"|<link rel="canonical"|<h1'

# Résultat attendu :
# <title>Chaise Ergonomique Pro X1 — MonCatalogue</title>
# <meta name="description" content="Chaise de bureau ergonomique...">
# <link rel="canonical" href="https://moncatalogue.fr/products/chaise-ergonomique-pro-x1">
# <h1>Chaise Ergonomique Pro X1</h1>

Si cette commande retourne un <div id="__nuxt"></div> vide, votre prerendering ne fonctionne pas — la page est servie en CSR.

Vérification via Screaming Frog

Configurez Screaming Frog en mode HTML brut (pas de rendering JavaScript) et crawlez un échantillon de 500 pages. Vérifiez :

  • Colonne "Title 1" : doit contenir le title spécifique, pas un title générique ou vide
  • Colonne "H1-1" : doit contenir le H1 unique de chaque page
  • Colonne "Canonical Link Element 1" : doit être renseigné et pointer vers l'URL correcte
  • Status code : 200 sur les pages actives, 301 sur les redirections

Si ces colonnes sont vides en mode HTML brut mais remplies en mode JavaScript rendering, vous êtes encore en CSR — le prerendering n'a pas pris effet.

Monitoring continu via Search Console

Dans le rapport "Pages" (anciennement "Couverture"), surveillez deux métriques :

  • Le ratio "Pages indexées" vs "Pages découvertes non indexées" — il doit converger vers 95%+ après déploiement du prerendering
  • Les erreurs de type "Soft 404" qui peuvent indiquer des pages prégénérées avec un contenu vide (build raté sur certaines routes)

Croisez ces données avec les logs serveur pour vérifier que Googlebot crawle bien vos pages prégénérées et reçoit des réponses rapides (TTFB < 200ms).

Dynamic rendering : la solution temporaire qui dure

Si une réécriture complète vers un framework SSG n'est pas envisageable à court terme, le dynamic rendering reste une option transitoire. Le principe : détecter les bots via le User-Agent et leur servir une version HTML pré-rendue, tandis que les utilisateurs reçoivent la SPA.

Google a explicitement validé cette approche dans sa documentation — puis l'a retirée en 2024. Le signal est clair : c'est toléré, mais ce n'est pas la direction recommandée.

Les risques du dynamic rendering :

  • Dérive de contenu : si la version pré-rendue n'est pas synchronisée avec la SPA, Google indexe un contenu différent de celui vu par les utilisateurs. C'est potentiellement du cloaking.
  • Maintenance double : vous devez maintenir le service de rendering (Rendertron, Prerender.io) en plus de votre SPA.
  • Point de défaillance supplémentaire : si le service de prerendering tombe, Googlebot revoit la page blanche.

Si vous êtes actuellement en dynamic rendering, planifiez la migration vers du SSG/ISR natif. C'est un investissement technique qui élimine une couche d'infrastructure fragile.

Checklist de déploiement

Avant de considérer votre prerendering comme "en production" :

Build & déploiement

  • Vérifiez la sortie du build : le framework indique quelles routes sont statiques vs dynamiques
  • Testez avec curl + User-Agent Googlebot sur 10 URLs représentatives (homepage, catégorie, produit, blog)
  • Mesurez le TTFB des pages prégénérées — visez < 100ms depuis le CDN

SEO technique

  • Chaque page prégénérée contient : title unique, meta description, canonical, H1, structured data si applicable
  • Les pages supprimées retournent un 404 ou 410, pas un 200 avec un contenu vide
  • Le sitemap XML référence uniquement les pages actives et indexables
  • Les balises hreflang (si site multilingue) sont présentes dans le HTML statique, pas injectées en JS

Monitoring

  • Configurez des alertes sur la disparition de balises meta critiques post-déploiement
  • Surveillez le ratio d'indexation dans la Search Console hebdomadairement pendant les 8 premières semaines
  • Crawlez votre site en mode HTML brut (Screaming Frog ou équivalent) après chaque déploiement majeur

Le prerendering est la solution la plus fiable pour garantir que Googlebot indexe exactement ce que vous voulez, quand vous le voulez. Mais c'est une infrastructure vivante : chaque déploiement peut introduire une régression silencieuse. Un monitoring continu — via Seogard ou un pipeline de tests custom — transforme cette fragilité en un processus contrôlé.

Articles connexes

Rendering5 avril 2026

SSR vs CSR : impact réel sur le SEO technique

Comparaison technique SSR et CSR avec exemples de crawl, code et scénarios concrets. Ce que Googlebot voit vraiment selon votre mode de rendering.

Rendering5 avril 2026

Google voit une page blanche sur votre SPA : diagnostic et solutions

Diagnostic technique complet des problèmes de rendering JavaScript sur les SPA. Solutions SSR, prerendering et monitoring pour Googlebot.

Rendering5 avril 2026

Hydration mismatch : le bug invisible qui tue votre SEO

Détectez et corrigez les erreurs d'hydratation SSR qui dégradent silencieusement votre indexation. Méthodes, outils et code pour debug avancé.