Un noindex ajouté par erreur en production ne casse rien de visible. Le site répond 200, les pages s'affichent, les tests fonctionnels passent. Puis le trafic organique s'effondre sur deux à trois semaines. Le problème : quand vous le voyez dans la Search Console, la désindexation est déjà avancée. Lors du développement ou de la migration d'un site, une balise meta robots noindex est souvent ajoutée pour empêcher l'indexation de l'environnement de développement. Si cette balise n'est pas retirée avant la mise en production, l'intégralité du site peut disparaître de Google en quelques semaines.
La réponse n'est pas un audit mensuel ni une alerte GSC. C'est un contrôle à chaque déploiement, avant que Googlebot ne recrawle. Cet article explique comment détecter un noindex régressif sur les deux surfaces qui comptent — le HTML brut SSR et le rendu JS — et comment bloquer le deploy en CI avant que la régression n'atteigne la prod.
Pourquoi la Search Console arrive toujours trop tard
GSC est un outil de constat, pas de prévention. Sous Disponibilité > Indexation > Indexation autorisée ?, vérifiez si l'instruction "noindex" est toujours détectée. Si elle n'est plus présente, vous pouvez cliquer sur Demander l'indexation. Si l'instruction "noindex" existe toujours, vous devez la supprimer pour que la page soit indexée. Le problème : ce signal n'apparaît qu'après que Googlebot a recrawlé l'URL et appliqué la directive. Vous découvrez la régression au moment où elle produit déjà ses effets.
Les guides SEO classiques recommandent un crawl Screaming Frog après mise en ligne, ou une surveillance manuelle du rapport d'indexation. Deux limites. D'abord, c'est réactif : vous crawlez après le deploy, pas avant. Ensuite, un crawl manuel ne tourne pas à chaque merge. Entre deux audits, vous avez le temps de pousser dix déploiements régressifs.
L'enjeu réel est de déplacer le contrôle avant la production, dans le pipeline. C'est un problème d'observabilité de déploiement, pas un problème d'audit SEO.
Les deux surfaces où le noindex se cache
Un noindex régressif n'apparaît pas toujours là où vous le cherchez. Il faut surveiller trois vecteurs distincts.
1. La meta robots dans le HTML brut (SSR)
Le cas le plus courant : la balise héritée du staging.
<!-- ❌ régressif : hérité de l'env de préprod -->
<meta name="robots" content="noindex, nofollow">
<!-- ✅ attendu en production -->
<meta name="robots" content="index, follow">
Sur un site SSR ou SSG, cette balise est dans le HTML servi par le serveur. Un curl la voit. Le piège classique reste celui de la préproduction : le site de préproduction est volontairement mis en noindex, puis cette directive reste en place après la mise en production. Résultat : le nouveau site est en ligne, mais ses pages stratégiques demandent à Google de ne pas les indexer.
2. Le X-Robots-Tag dans l'en-tête HTTP (invisible dans le source)
Le vecteur le plus traître. Une directive X-Robots-Tag: noindex envoyée par le serveur ne se voit pas dans le code source de la page. Elle suffit pourtant à exclure une URL de l'index. Vous pouvez ouvrir le code source, faire Ctrl+F sur "noindex", ne rien trouver — et avoir quand même un noindex actif. Noindex peut aussi être envoyé via un en-tête de réponse HTTP. C'est courant, et il peut être introduit par des règles serveur ou un CDN.
Une règle Nginx, une config Cloudflare, une variable d'environnement mal propagée : tous peuvent injecter cet en-tête sans laisser de trace dans le HTML. Votre contrôle doit donc inspecter les response headers, pas seulement le DOM.
3. Le noindex injecté côté JS (CSR)
Le piège des SPA. Le HTML brut est propre. Mais un script modifie le DOM au runtime. Google tient compte du code final obtenu après interprétation du Javascript au chargement de la page. Donc si un script JS modifie dynamiquement le HTML initial pour ajouter "noindex", alors Google considèrera que la page ne doit pas/plus être indexée.
Ici, un curl ne suffit plus. Le HTML brut affiche index, follow, mais après hydratation un composant — un guard de route, une logique de feature flag, un état d'auth mal géré — réécrit la meta en noindex. Googlebot exécute le JS et voit la version finale. Vous, en testant avec curl, voyez la version saine. C'est exactement le type de divergence SSR/CSR qui passe sous tous les radars. Le même mécanisme produit des SPA non indexées que Googlebot voit en page blanche.
Conclusion technique : un seul check ne couvre jamais les trois. Il faut comparer le HTML brut (réponse serveur + headers) ET le DOM rendu après exécution JS, sur chaque déploiement.
Détecter avant Googlebot : le contrôle à intégrer
L'objectif est de transformer "le noindex est-il toujours là ?" en assertion automatisée, exécutée avant que la prod ne soit live.
Vérification manuelle minimale (à scripter ensuite)
Inspectez les deux surfaces d'un coup. Pour le HTML brut et les headers :
# Meta robots dans le HTML brut + X-Robots-Tag dans les headers
curl -sI https://votresite.com/page-strategique | grep -i "x-robots-tag"
curl -s https://votresite.com/page-strategique | grep -i 'name="robots"'
Pour le rendu JS, un check via Playwright qui lit le DOM après hydratation :
import { chromium } from 'playwright';
const ROUTES = ['/', '/produits', '/produits/ref-cle'];
for (const route of ROUTES) {
const browser = await chromium.launch();
const page = await browser.newPage();
const resp = await page.goto(`https://votresite.com${route}`, {
waitUntil: 'networkidle',
});
// 1. en-tête HTTP
const xrobots = resp.headers()['x-robots-tag'] ?? '';
// 2. meta robots dans le DOM rendu (post-JS)
const meta = await page.getAttribute('meta[name="robots"]', 'content') ?? '';
if (/noindex/i.test(xrobots) || /noindex/i.test(meta)) {
console.error(`REGRESSION noindex sur ${route} — header="${xrobots}" meta="${meta}"`);
process.exit(1);
}
await browser.close();
}
Ce script échoue avec un code de sortie non nul dès qu'un noindex apparaît, sur l'une des deux surfaces. C'est la brique de base d'un gate CI.
Le piège du robots.txt qui masque le noindex
Attention à un effet de bord documenté par Google. Si la page est bloquée via le fichier robots.txt, la valeur "Indexation autorisée" indique toujours "Oui", car la directive noindex ne peut pas être identifiée ni appliquée par Google. C'est pourquoi votre page peut apparaître dans les résultats de recherche. Si votre check repose sur GSC, un Disallow peut masquer un noindex réel. Votre contrôle CI, lui, lit directement la réponse serveur — il n'est pas trompé par ce masquage. Raison de plus pour ne pas dépendre de la Search Console.
Bloquer le déploiement régressif dans la CI/CD
Le check ne sert à rien s'il ne bloque pas. L'intégration dans le pipeline transforme la détection en garde-fou.
Le principe d'une gate SEO dans GitHub Actions qui fait échouer un déploiement régressif : le job tourne contre l'URL de preview (ou la staging avec headers de prod simulés) avant la promotion vers la production. Si une route stratégique renvoie noindex sur le HTML brut, dans le X-Robots-Tag, ou après rendu JS, le job échoue et la promotion est annulée.
C'est là qu'un monitoring de régression dédié intervient. Sur Seogard, la règle noindex_added compare l'état d'indexabilité de chaque URL surveillée entre le déploiement précédent et le nouveau, sur le HTML brut SSR et le DOM rendu après exécution JS. Quand une page passe de index à noindex — meta ou X-Robots-Tag — la règle se déclenche avant le recrawl Google et peut bloquer le deploy via le hook CI. La même logique couvre robots_txt_changed pour le cas où un Disallow: / apparaît dans le robots.txt, l'autre vecteur classique de désindexation massive en migration. Vous détectez la régression au moment du push, pas trois semaines plus tard dans GSC. Voir comment Seogard surveille les régressions d'indexation.
Checklist de déploiement
À automatiser dans le pipeline, pas à faire à la main :
- HTML brut :
meta robotsabsente ou enindexsur toutes les routes stratégiques. - Headers HTTP : pas de
X-Robots-Tag: noindexcôté serveur ou CDN. - Rendu JS : le DOM post-hydratation ne réécrit pas la meta en
noindex. - robots.txt : pas de
Disallow: /global, et la directive ne masque pas unnoindexque vous croyez actif. - Gate CI : le job échoue et annule la promotion si l'un des points ci-dessus régresse.
La règle est simple : ne faites jamais confiance à un environnement qui hérite de la config d'un autre. Un noindex est un commit comme un autre — il doit être testé avant la prod, sur les deux surfaces, à chaque déploiement.
La référence officielle sur le comportement de la directive : Block Search indexing with noindex — Google Search Central.