Pourquoi le trafic chute après une migration headless, et comment l'éviter
Rendu côté client, balises canonical perdues et origine lente. Les trois façons dont une migration headless coûte discrètement du trafic organique — et comment fermer chacune.
Un CMS headless n'a aucune opinion sur votre HTML. Il renvoie le contenu via une API ; tout ce qu'un moteur de recherche voit est produit par du code que vous avez écrit.
C'est pourquoi « le headless est-il mauvais pour le SEO ? » est la mauvaise question. La bonne est : qu'est-ce que la refonte a changé au HTML ? En pratique, la réponse est l'une de trois choses, et les trois sont réparables.
#Fuite 1 — Un contenu qui n'existe qu'après l'exécution du JavaScript
La plus courante et la plus coûteuse.
Vous êtes passé à un framework avec rendu côté serveur, puis vous avez récupéré le corps de l'article dans un effet côté client, parce que c'est ce que faisait le tutoriel. Maintenant :
Googlebot obtient une coquille vide au premier passage, et le rendu est mis en file d'attente pour plus tard — parfois bien plus tard.
Les autres robots (Bing, robots d'IA, robots d'aperçu social) ne font généralement aucun rendu. Vos liens s'affichent vides.
Le Largest Contentful Paint mesure le contenu, et votre contenu arrive un aller-retour après la coquille.
Diagnostic — une seule commande, sans outillage :
0 signifie que votre contenu n'est pas dans le HTML. Tout le reste de cet article est secondaire tant que ceci ne renvoie pas 1.
Correctif — récupérez côté serveur. Dans l'App Router de Next.js, c'est le comportement par défaut ; l'erreur est généralement une frontière 'use client' placée trop haut dans l'arbre. Descendez-la vers le composant interactif au lieu d'envelopper la page.
#Fuite 2 — Canonical, métadonnées et données structurées perdues dans la refonte
L'ancien CMS avait un plugin SEO qui produisait des balises canonical, des méta-descriptions, des balises Open Graph et un schéma Article pour chaque page. Personne n'a explicitement décidé de le retirer. C'était simplement absent de la liste de contrôle de la refonte.
Symptômes : regroupement de contenu dupliqué (URL avec paramètres, variantes avec ou sans barre oblique finale, archives paginées indexant toutes séparément), résultats enrichis manquants, et partages sociaux qui s'affichent avec le mauvais titre.
Correctif — faites de ces champs une partie du modèle de contenu, pas du thème. Dans corpusctl, le module SEO stocke, par entrée, le titre, la description, le canonical et l'image sociale aux côtés du contenu, de sorte qu'ils voyagent avec l'entrée plutôt que de vivre dans ce qui la rend.
Puis affirmez-les dans la CI. Un test qui récupère dix URL représentatives et vérifie que chacune a exactement un canonical auto-référent, une description non vide de moins de 155 caractères, et un JSON-LD valide coûte une heure et attrape cette catégorie de régression pour de bon.
#Fuite 3 — Une origine lente derrière un cache auquel vous n'avez pas pensé
Le headless améliore généralement les performances. Il les dégrade quand le front-end interroge le CMS à chaque requête et que le CMS est à une requête de base de données de distance.
Votre TTFB est désormais le temps de réponse du CMS plus votre temps de rendu, à chaque échec de cache, et chaque échec de cache est un vrai utilisateur qui attend.
Correctif — décidez où vit le contenu au moment de la requête. Trois options, par ordre croissant de robustesse :
Récupération à chaque requête. Le CMS est sur le chemin critique. Correct pour un tableau de bord, faux pour du contenu que vous voulez voir classé.
ISR avec une fenêtre temporelle. Le contenu a au plus N secondes de retard ; chaque expiration de fenêtre est un échec de cache que quelqu'un paie.
Pré-compilation et service depuis le cache. Rendu au moment de la publication, servi comme un artefact statique. Le plus rapide et le moins cher — à condition que l'invalidation soit gérée.
La partie difficile de la troisième option est l'invalidation, car la page est une copie d'un calcul qui pourrait changer à tout moment.
corpusctl supprime le problème plutôt que de le gérer. Publier écrit le contenu dans un fichier immuable, adressé par hachage dans le stockage objet et rafraîchit un manifeste ; le client résout le slug vers un fragment de manifeste localement, puis récupère cette adresse depuis le cache de périphérie nginx. L'adresse est un hachage du contenu, donc la même adresse ne peut jamais renvoyer un contenu différent — elle est mise en cache pendant trente jours, et publier écrit une nouvelle adresse. Il n'y a rien à purger.
Pour les Core Web Vitals, cela compte directement : le document arrive d'un cache plutôt que d'un calcul, si bien que le TTFB cesse de varier avec la charge de la base de données et que le LCP cesse de dépendre du fait que vous ayez eu un succès de cache ou non.
Si vous gérez plusieurs langues — et un CMS headless est souvent choisi précisément pour cela — voici la quatrième fuite.
Des règles faciles à énoncer et faciles à mal appliquer :
Chaque version linguistique renvoie vers chaque autre version, y compris elle-même.
Il existe un x-default pointant vers la version destinée aux visiteurs non appariés.
Les liens sont réciproques. Un hreflang à sens unique est totalement ignoré.
Les codes de langue sont des BCP 47 valides. Le chinois simplifié est zh-Hans, pas zh-CN, lorsque vous désignez l'écriture plutôt que la région.
L'URL dans hreflang correspond au canonical de la page vers laquelle il pointe.
Ne vérifiez pas cela à la main. Récupérez chaque URL et affirmez l'ensemble complet :
Dans le même ordre d'idées : l'URL racine qui négocie la langue devrait renvoyer un 302, pas un 301. La réponse varie selon Accept-Language, elle n'est donc pas permanente ; un 301 est mis en cache dans le navigateur et la personne suivante sur cette machine ne peut pas changer de langue. Envoyez Vary: Accept-Language, Cookie avec, sinon un cache intermédiaire servira la langue du premier visiteur à tout le monde.
Deux semaines minimum après la bascule. Les classements bougent selon leur propre rythme et une panique de trois jours ne vous apprend rien.
Search Console → Couverture. Une hausse des 404 signale une redirection que vous avez manquée. Une hausse des « Explorée, actuellement non indexée » signifie souvent une sortie mince ou dupliquée provenant d'un modèle.
Search Console → Performances, segmentées par type de page. Si un modèle a perdu plus que les autres, le bug est dans ce modèle, pas dans la migration.
Les journaux serveur, pas seulement Search Console. Le journal d'exploration vous dit ce que Googlebot a réellement demandé et ce qu'il a reçu. Un 404 là est gratuit à corriger aujourd'hui et coûteux à corriger dans un mois.
Les données de terrain des Core Web Vitals, pas les scores de laboratoire. Les scores de laboratoire mesurent votre ordinateur portable.
#Une liste de contrôle que vous pouvez exécuter aujourd'hui
Un CMS headless qui épouse Next.js au lieu de le combattre
Le mode brouillon, l'ISR, l'App Router et la couche de rendu. Ce qui compte vraiment quand vous branchez un CMS headless à Next.js — et les trois façons dont ça tourne mal.