[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fnycoBQEvFM1rtapNWRO67ZNUkttqdbiY1s7iFSMIwiI":3,"$fexhppdrTv-fI1zWKcHQ8vcltn3nqQYHUDe5EDQwiKr4":25},{"_id":4,"slug":5,"__v":6,"author":7,"body":8,"canonical":9,"category":10,"createdAt":11,"date":12,"description":13,"htmlContent":14,"image":15,"imageAlt":15,"readingTime":16,"tags":17,"title":23,"updatedAt":24},"69e9b607aa6b273b0cd0e423","what-s-the-biggest-technical-seo-blind-spot-from-over-relying-on-tools-ask-an-seo-via-sejournal-helenpollitt1",0,"Equipe Seogard","Un site e-commerce de 22 000 pages produit. Screaming Frog remonte zéro erreur critique. Sitechecker affiche un score de 94/100. Pourtant, 8 400 pages n'ont reçu aucune visite de Googlebot depuis 97 jours. Le trafic organique a chuté de 31% en deux mois sans qu'aucune alerte ne se déclenche. Le problème n'était pas technique au sens classique — c'était un angle mort structurel que les outils de crawl ne sont tout simplement pas conçus pour détecter.\n\nHelen Pollitt a récemment soulevé cette question sur Search Engine Journal : quel est le plus gros angle mort du SEO technique quand on se repose trop sur les outils ? La réponse courte : les outils crawlent votre site comme des outils, pas comme Googlebot. La réponse longue mérite qu'on ouvre les logs serveur.\n\n## Le fossé fondamental entre un crawl tool et Googlebot\n\nScreaming Frog, Sitebulb, Ahrefs Site Audit — ces outils envoient un user-agent HTTP, récupèrent le HTML, parsent le DOM, et génèrent un rapport. C'est utile. Mais c'est une simulation, pas une observation du comportement réel de Google.\n\n### Ce que fait un crawler tool\n\nUn crawler tool parcourt votre site de manière exhaustive, en suivant chaque lien interne depuis un point d'entrée. Il respecte le `robots.txt`, applique éventuellement un rendering JavaScript, et génère un inventaire structurel : status codes, titles, canonicals, hreflang, structured data. C'est un snapshot statique de votre architecture.\n\n### Ce que fait Googlebot\n\nGooglebot ne crawle pas votre site de manière exhaustive. Il alloue un budget de crawl basé sur la popularité de vos pages, la fréquence de changement détectée, et la qualité perçue du site. Il rend le JavaScript avec un délai variable (parfois plusieurs jours). Il priorise certaines URLs, en ignore d'autres complètement. Et surtout, il réagit à des signaux que votre crawler tool ne voit pas : les backlinks entrants, le CTR dans les SERPs, les patterns de linking interne pondérés.\n\nLe fossé se résume à ça : un tool vous dit ce qui **existe** sur votre site. Les logs vous disent ce que Google **choisit de voir**.\n\n### La preuve dans les logs\n\nVoici comment extraire cette donnée à partir de logs Apache bruts :\n\n```bash\n# Extraire toutes les requêtes Googlebot sur les 90 derniers jours\ngrep -i \"googlebot\" /var/log/apache2/access.log* \\\n  | awk '{print $7}' \\\n  | sort | uniq -c | sort -rn > googlebot_urls_90d.txt\n\n# Comparer avec le sitemap pour trouver les pages jamais crawlées\ncomm -23 \u003C(sed 's|https://www.votresite.fr||' sitemap_urls.txt | sort) \\\n         \u003C(awk '{print $2}' googlebot_urls_90d.txt | sort) \\\n  > pages_non_crawlees.txt\n\nwc -l pages_non_crawlees.txt\n# Output: 8417 pages_non_crawlees.txt\n```\n\n8 417 pages dans le sitemap que Googlebot n'a pas visitées en 3 mois. Screaming Frog ne remontera jamais cette information parce que ce n'est pas son rôle. C'est la différence entre un diagnostic d'architecture et une observation du comportement de crawl réel.\n\nPour une analyse approfondie de ce que les logs révèlent sur les crawlers — y compris les bots IA — consultez notre article sur [l'analyse des fichiers de log pour les crawlers IA](/blog/why-log-file-analysis-matters-for-ai-crawlers-and-search-visibility).\n\n## Le rendering JavaScript : l'angle mort le plus coûteux\n\nLa majorité des crawlers tools proposent un mode \"JavaScript rendering\". Screaming Frog utilise un Chromium headless embarqué. Sitebulb fait de même. Le problème : leur rendering ne reproduit pas le comportement du Web Rendering Service (WRS) de Google.\n\n### Les différences concrètes\n\nLe WRS de Google fonctionne en deux passes documentées par Google dans sa [documentation sur le rendu JavaScript](https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics) :\n\n1. **Première passe** : Googlebot récupère le HTML brut, indexe ce qu'il peut, et met la page en file d'attente pour le rendering.\n2. **Deuxième passe** : le WRS rend la page avec Chromium, exécute le JS, et met à jour l'index.\n\nLe délai entre les deux passes est variable. Sur un site à faible autorité, il peut dépasser une semaine. Pendant ce temps, Google indexe le HTML brut — qui, sur un SPA React ou une application Angular, peut être quasi vide.\n\n### Ce que votre tool ne teste pas\n\nScreaming Frog rend la page instantanément. Il ne simule pas le délai. Il ne simule pas non plus les erreurs JavaScript qui surviennent uniquement dans l'environnement WRS (pas de `localStorage`, pas de `sessionStorage`, certaines APIs navigateur absentes).\n\nVoici un cas réel : un composant React qui charge les données produit côté client :\n\n```typescript\n// ProductPage.tsx — composant problématique\nconst ProductPage = ({ productId }: { productId: string }) => {\n  const [product, setProduct] = useState\u003CProduct | null>(null);\n  const [error, setError] = useState(false);\n\n  useEffect(() => {\n    // Ce fetch dépend d'un cookie de session pour la localisation\n    const locale = localStorage.getItem('user_locale') || 'fr-FR';\n    \n    fetch(`/api/products/${productId}?locale=${locale}`, {\n      headers: {\n        'Authorization': `Bearer ${sessionStorage.getItem('api_token')}`\n      }\n    })\n      .then(res => res.json())\n      .then(data => setProduct(data))\n      .catch(() => setError(true));\n  }, [productId]);\n\n  if (!product) return \u003Cdiv className=\"loading-skeleton\" />;\n  \n  return (\n    \u003Cdiv>\n      \u003Ch1>{product.name}\u003C/h1>\n      \u003Cp>{product.description}\u003C/p>\n      {/* ... */}\n    \u003C/div>\n  );\n};\n```\n\nScreaming Frog va rendre cette page avec succès dans la plupart des cas — il simule un navigateur complet. Mais le WRS de Google n'a pas accès à `localStorage` ni `sessionStorage`. Le fetch échoue silencieusement, le composant reste sur le skeleton loader, et Google indexe une page vide.\n\nLe fix est trivial en SSR :\n\n```typescript\n// ProductPage.tsx — version SSR-compatible (Next.js App Router)\nexport async function generateMetadata({ params }: { params: { id: string } }) {\n  const product = await getProduct(params.id, 'fr-FR'); // locale par défaut côté serveur\n  return {\n    title: product.name,\n    description: product.description.slice(0, 155),\n  };\n}\n\nexport default async function ProductPage({ params }: { params: { id: string } }) {\n  const product = await getProduct(params.id, 'fr-FR');\n  \n  return (\n    \u003Cdiv>\n      \u003Ch1>{product.name}\u003C/h1>\n      \u003Cp>{product.description}\u003C/p>\n      {/* Hydration côté client pour les éléments interactifs */}\n      \u003CAddToCartButton productId={params.id} />\n    \u003C/div>\n  );\n}\n```\n\nCe type de problème est invisible dans Screaming Frog mais catastrophique dans l'index Google. La seule façon de le détecter : comparer le HTML brut servi à Googlebot avec le DOM rendu, via l'outil d'inspection d'URL de Search Console ou via un test manuel avec `curl` :\n\n```bash\n# Voir exactement ce que Googlebot reçoit en première passe\ncurl -A \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\" \\\n  -s https://www.votresite.fr/produit/chaussure-running-x500 \\\n  | grep -i \"\u003Ch1>\\|\u003Ctitle>\\|\u003Cmeta name=\\\"description\\\"\"\n```\n\nSi ce `curl` renvoie un `\u003Ch1>` vide ou un skeleton loader, vous avez un problème que Screaming Frog ne verra pas.\n\nPour aller plus loin sur les enjeux du rendering JavaScript et les fallbacks nécessaires, voir notre analyse sur [les fallbacks JavaScript en 2026](/blog/no-javascript-fallbacks-in-2026-less-critical-still-necessary).\n\n## Les canonicals : quand Google ignore vos directives\n\nLes outils SEO vérifient la syntaxe de vos canonicals. Ils s'assurent que la balise `\u003Clink rel=\"canonical\">` est présente, qu'elle pointe vers une URL valide, qu'elle est cohérente avec le hreflang. Ce qu'ils ne vérifient pas : est-ce que Google respecte effectivement votre canonical ?\n\n### Le scénario classique que les outils ratent\n\nUn site e-commerce avec des filtres de facettes. Chaque combinaison couleur/taille/marque génère une URL distincte :\n\n```\n/chaussures?couleur=noir\n/chaussures?couleur=noir&taille=42\n/chaussures?couleur=noir&taille=42&marque=nike\n```\n\nVous avez configuré un canonical vers `/chaussures` sur toutes ces pages. Screaming Frog confirme : canonical présent, syntaxe correcte, aucune erreur. Audit clean.\n\nMais Google peut décider d'ignorer votre canonical. C'est documenté : Google traite le canonical comme un **signal**, pas une directive. Si Google détecte que le contenu de `/chaussures?couleur=noir` est significativement différent de `/chaussures`, il peut choisir de l'indexer séparément — ou pire, choisir la version paramétrée comme canonical à la place de votre page principale.\n\nGoogle a d'ailleurs listé [9 scénarios expliquant comment il sélectionne les URLs canoniques](/blog/google-lists-9-scenarios-that-explain-how-it-picks-canonical-urls-via-sejournal-martinibuster). Parmi eux : les signaux de linking interne. Si 200 pages internes linkent vers `/chaussures?couleur=noir` et seulement 3 vers `/chaussures`, Google peut inverser votre canonical.\n\n### Comment détecter le problème\n\nSearch Console est le seul outil fiable ici. Dans le rapport \"Pages\" > \"Indexation\", filtrez par \"Autre page ayant un canonical choisi par Google\" ou \"URL canonique alternative envoyée par l'utilisateur\". Cela vous montre les pages où Google a **activement décidé** d'ignorer votre directive.\n\nAucun crawler tool ne remonte cette donnée parce qu'elle n'existe que côté Google.\n\n## Les réponses conditionnelles : le cloaking involontaire\n\nC'est probablement l'angle mort le plus insidieux. Votre serveur peut servir des réponses différentes selon le user-agent, l'IP source, les cookies, les headers `Accept-Language`, ou même la charge serveur — et vous ne le savez peut-être pas.\n\n### Le CDN qui cache des 200 sur des 404\n\nScénario réel : un site média de 45 000 articles utilise Cloudflare avec un cache agressif. Un article est supprimé côté CMS, le serveur origin renvoie un 404. Mais Cloudflare a mis en cache la version 200 de la page. Googlebot, qui passe par les mêmes PoPs que les visiteurs classiques, reçoit un 200 avec du contenu périmé. L'article reste indexé indéfiniment.\n\nScreaming Frog crawle depuis votre IP — il peut recevoir la réponse du cache ou de l'origin selon la configuration. Il n'a aucun moyen de savoir ce que Googlebot reçoit réellement.\n\n### Les redirections conditionnelles\n\nAutre cas classique : les redirections géo-localisées. Un middleware Next.js qui redirige selon la géolocalisation de l'IP :\n\n```typescript\n// middleware.ts — piège à Googlebot\nimport { NextResponse } from 'next/server';\nimport type { NextRequest } from 'next/server';\n\nexport function middleware(request: NextRequest) {\n  const country = request.geo?.country || 'FR';\n  const pathname = request.nextUrl.pathname;\n\n  // Redirection géo-conditionnelle\n  if (country === 'US' && !pathname.startsWith('/en')) {\n    return NextResponse.redirect(new URL(`/en${pathname}`, request.url));\n  }\n  if (country === 'DE' && !pathname.startsWith('/de')) {\n    return NextResponse.redirect(new URL(`/de${pathname}`, request.url));\n  }\n\n  return NextResponse.next();\n}\n```\n\nGooglebot crawle principalement depuis les États-Unis. Ce middleware redirige systématiquement Googlebot vers `/en/*`, même quand il tente de crawler vos pages `/fr/*`. Résultat : vos pages françaises disparaissent de l'index français, remplacées par les versions anglaises.\n\nScreaming Frog, lancé depuis votre bureau à Paris, crawle les pages `/fr/*` sans problème. Tout semble parfait. L'angle mort est total.\n\nLa correction :\n\n```typescript\n// middleware.ts — version safe pour le SEO\nexport function middleware(request: NextRequest) {\n  const userAgent = request.headers.get('user-agent') || '';\n  const isBot = /googlebot|bingbot|yandex|baiduspider/i.test(userAgent);\n  \n  // Ne JAMAIS rediriger les bots — leur servir le contenu demandé\n  if (isBot) {\n    return NextResponse.next();\n  }\n\n  const country = request.geo?.country || 'FR';\n  const pathname = request.nextUrl.pathname;\n\n  if (country === 'US' && !pathname.startsWith('/en')) {\n    return NextResponse.redirect(new URL(`/en${pathname}`, request.url));\n  }\n\n  return NextResponse.next();\n}\n```\n\nMieux encore : ne pas rediriger du tout, mais afficher un bandeau de suggestion de changement de langue. Les redirections géo-conditionnelles sont [explicitement déconseillées par Google](https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites#locale-adaptive-pages).\n\n## Les métriques de performance : le mirage des scores synthétiques\n\nLighthouse donne un score de performance de 92. PageSpeed Insights confirme. Les Core Web Vitals sont au vert dans Search Console. Pourtant, le Time to First Byte (TTFB) réel des visiteurs mobiles sur réseau 4G en zone périurbaine dépasse régulièrement 2,5 secondes.\n\n### Le problème des tests synthétiques\n\nLighthouse s'exécute sur un réseau local ou simulé, depuis un datacenter, avec des conditions stables. Les données CrUX (Chrome User Experience Report) reflètent les vrais utilisateurs, mais elles sont agrégées sur 28 jours et par origin — pas par page individuelle (sauf sur les pages à très fort trafic).\n\nL'angle mort : vous optimisez vos Core Web Vitals sur la base de données synthétiques qui ne reflètent pas l'expérience réelle. Un LCP de 1,8s sur Lighthouse peut correspondre à un LCP de 4,2s sur un Samsung Galaxy A13 en 4G.\n\n### Ce que révèle le Real User Monitoring\n\nLa seule approche fiable consiste à mesurer les performances réelles via l'API Performance Observer. Voici un snippet de RUM minimal :\n\n```javascript\n// rum-collector.js — collecte des Core Web Vitals réels\nimport { onLCP, onFID, onCLS, onINP, onTTFB } from 'web-vitals';\n\nfunction sendToAnalytics(metric) {\n  const payload = {\n    name: metric.name,\n    value: metric.value,\n    rating: metric.rating, // 'good', 'needs-improvement', 'poor'\n    delta: metric.delta,\n    id: metric.id,\n    url: window.location.pathname,\n    connection: navigator.connection?.effectiveType || 'unknown',\n    deviceMemory: navigator.deviceMemory || 'unknown',\n    timestamp: Date.now(),\n  };\n\n  // Beacon API pour ne pas bloquer le déchargement de la page\n  if (navigator.sendBeacon) {\n    navigator.sendBeacon('/api/rum', JSON.stringify(payload));\n  }\n}\n\nonLCP(sendToAnalytics);\nonINP(sendToAnalytics);\nonCLS(sendToAnalytics);\nonTTFB(sendToAnalytics);\n```\n\nAvec ces données terrain, vous découvrirez probablement que 15 à 25% de vos visiteurs ont une expérience dégradée que Lighthouse ne capture jamais. C'est une donnée que Google possède (via Chrome) mais que vos outils SEO ne remontent pas.\n\n## Le linking interne : l'angle mort quantitatif des crawlers\n\nScreaming Frog analyse votre linking interne. Il compte les liens, calcule la profondeur de crawl, identifie les pages orphelines. Ce qu'il ne fait pas : pondérer les liens par leur position dans la page, leur contexte sémantique, et leur probabilité de clic.\n\n### Le poids réel d'un lien interne\n\nUn lien dans votre footer présent sur 22 000 pages n'a pas la même valeur qu'un lien contextuel dans le corps d'un article de référence. Screaming Frog les compte de la même façon. Google ne les traite pas de la même façon.\n\nUn lien dans un menu de navigation replié (hamburger menu mobile) n'a pas le même poids qu'un lien visible dans le contenu principal. Un lien inséré dynamiquement via JavaScript après un scroll n'a pas le même poids qu'un lien présent dans le HTML initial.\n\nLes outils vous donnent le **graphe** de linking interne. Ils ne vous donnent pas la **topologie pondérée** — le flux réel de PageRank interne tel que Google le calcule. Cette information n'existe nulle part dans aucun outil tiers. La seule approximation disponible : les données de performance de Search Console (impressions, clics) croisées avec votre structure de liens.\n\nSi vous travaillez sur un site dont [les fondations techniques sont déjà fragiles](/blog/why-your-new-seo-vendor-can-t-build-on-a-broken-foundation-via-sejournal-taylordanrw), ces angles morts se cumulent et deviennent critiques.\n\n## Construire un système de vérité terrain\n\nL'enjeu n'est pas de jeter les outils. Screaming Frog reste indispensable pour les audits d'architecture. Search Console est la seule source de vérité côté Google. Ahrefs et Semrush sont précieux pour l'analyse concurrentielle et le suivi des backlinks.\n\nL'enjeu est de **combler les angles morts** avec des données que les outils ne collectent pas.\n\n### La stack de monitoring complète\n\n1. **Crawl tools** (Screaming Frog, Sitebulb) : audit d'architecture, détection des erreurs syntaxiques, inventaire technique.\n2. **Search Console** : vérité terrain côté Google — pages indexées, canonicals réels, erreurs de crawl, performance de recherche.\n3. **Logs serveur** : comportement réel de Googlebot — fréquence de crawl, pages ignorées, codes de réponse servis. C'est la donnée la plus sous-exploitée.\n4. **RUM (Real User Monitoring)** : performance réelle, pas synthétique. Web-vitals + collecteur maison ou outil dédié.\n5. **Monitoring continu** : détection des régressions en temps réel — meta disparues, changements de status code, SSR cassé. Un outil comme Seogard surveille ces signaux automatiquement et alerte avant que l'impact SEO ne se matérialise.\n\n### Le test de réalité hebdomadaire\n\nChaque semaine, prenez 10 pages stratégiques et faites le test de réalité :\n\n```bash\n# Pour chaque page stratégique, vérifier ce que Googlebot reçoit réellement\nfor url in \\\n  \"https://www.votresite.fr/categorie/chaussures-running\" \\\n  \"https://www.votresite.fr/produit/air-max-2026-noir\" \\\n  \"https://www.votresite.fr/guide/choisir-chaussures-trail\"; do\n  \n  echo \"=== $url ===\"\n  \n  # Status code\n  curl -s -o /dev/null -w \"%{http_code}\" \\\n    -A \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\" \\\n    \"$url\"\n  echo \"\"\n  \n  # Vérifier title et meta description dans le HTML brut\n  curl -s -A \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\" \\\n    \"$url\" | grep -ioP '(\u003Ctitle>.*?\u003C/title>|\u003Cmeta name=\"description\"[^>]*>)'\n  \n  # Vérifier canonical\n  curl -s -A \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\" \\\n    \"$url\" | grep -ioP '\u003Clink rel=\"canonical\"[^>]*>'\n  \n  echo \"---\"\ndone\n```\n\nCe script de 30 secondes vous en apprend plus sur votre SEO réel qu'un audit Screaming Frog de 4 heures. Non pas parce que Screaming Frog est mauvais, mais parce qu'il répond à une question différente.\n\nLes outils répondent à : \"Est-ce que mon site est techniquement correct ?\"\n\nLes données brutes répondent à : \"Est-ce que Google voit ce que je crois qu'il voit ?\"\n\nCe sont deux questions fondamentalement différentes. La deuxième est celle qui détermine votre trafic organique. Et c'est précisément celle que la plupart des équipes SEO ne posent jamais, aveuglées par le confort d'un dashboard vert. Les régressions silencieuses — un canonical qui dérive, un SSR qui casse après un déploiement, un backlink stratégique qui disparaît — ne génèrent aucune alerte dans un crawler tool parce qu'il n'est pas branché sur la réalité de production. Seul un monitoring continu sur les données brutes comble ce fossé.\n\n```","https://seogard.io/blog/what-s-the-biggest-technical-seo-blind-spot-from-over-relying-on-tools-ask-an-seo-via-sejournal-helenpollitt1","Actualités SEO","2026-04-23T06:02:47.381Z","2026-04-23","Les outils SEO créent des angles morts critiques. Voici ce que les données brutes révèlent — logs serveur, rendering réel, signaux que Screaming Frog ignore.","\u003Cp>Un site e-commerce de 22 000 pages produit. Screaming Frog remonte zéro erreur critique. Sitechecker affiche un score de 94/100. Pourtant, 8 400 pages n'ont reçu aucune visite de Googlebot depuis 97 jours. Le trafic organique a chuté de 31% en deux mois sans qu'aucune alerte ne se déclenche. Le problème n'était pas technique au sens classique — c'était un angle mort structurel que les outils de crawl ne sont tout simplement pas conçus pour détecter.\u003C/p>\n\u003Cp>Helen Pollitt a récemment soulevé cette question sur Search Engine Journal : quel est le plus gros angle mort du SEO technique quand on se repose trop sur les outils ? La réponse courte : les outils crawlent votre site comme des outils, pas comme Googlebot. La réponse longue mérite qu'on ouvre les logs serveur.\u003C/p>\n\u003Ch2>Le fossé fondamental entre un crawl tool et Googlebot\u003C/h2>\n\u003Cp>Screaming Frog, Sitebulb, Ahrefs Site Audit — ces outils envoient un user-agent HTTP, récupèrent le HTML, parsent le DOM, et génèrent un rapport. C'est utile. Mais c'est une simulation, pas une observation du comportement réel de Google.\u003C/p>\n\u003Ch3>Ce que fait un crawler tool\u003C/h3>\n\u003Cp>Un crawler tool parcourt votre site de manière exhaustive, en suivant chaque lien interne depuis un point d'entrée. Il respecte le \u003Ccode>robots.txt\u003C/code>, applique éventuellement un rendering JavaScript, et génère un inventaire structurel : status codes, titles, canonicals, hreflang, structured data. C'est un snapshot statique de votre architecture.\u003C/p>\n\u003Ch3>Ce que fait Googlebot\u003C/h3>\n\u003Cp>Googlebot ne crawle pas votre site de manière exhaustive. Il alloue un budget de crawl basé sur la popularité de vos pages, la fréquence de changement détectée, et la qualité perçue du site. Il rend le JavaScript avec un délai variable (parfois plusieurs jours). Il priorise certaines URLs, en ignore d'autres complètement. Et surtout, il réagit à des signaux que votre crawler tool ne voit pas : les backlinks entrants, le CTR dans les SERPs, les patterns de linking interne pondérés.\u003C/p>\n\u003Cp>Le fossé se résume à ça : un tool vous dit ce qui \u003Cstrong>existe\u003C/strong> sur votre site. Les logs vous disent ce que Google \u003Cstrong>choisit de voir\u003C/strong>.\u003C/p>\n\u003Ch3>La preuve dans les logs\u003C/h3>\n\u003Cp>Voici comment extraire cette donnée à partir de logs Apache bruts :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Extraire toutes les requêtes Googlebot sur les 90 derniers jours\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -i\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"googlebot\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> /var/log/apache2/access.log\u003C/span>\u003Cspan style=\"color:#79B8FF\">*\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  |\u003C/span>\u003Cspan style=\"color:#B392F0\"> awk\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '{print $7}'\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> uniq\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -rn\u003C/span>\u003Cspan style=\"color:#F97583\"> >\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> googlebot_urls_90d.txt\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Comparer avec le sitemap pour trouver les pages jamais crawlées\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">comm\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -23\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> &#x3C;(\u003C/span>\u003Cspan style=\"color:#B392F0\">sed\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 's|https://www.votresite.fr||' sitemap_urls.txt \u003C/span>\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#9ECBFF\">)\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">         &#x3C;(\u003C/span>\u003Cspan style=\"color:#B392F0\">awk\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '{print $2}' googlebot_urls_90d.txt \u003C/span>\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#9ECBFF\">)\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  >\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> pages_non_crawlees.txt\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">wc\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -l\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> pages_non_crawlees.txt\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Output: 8417 pages_non_crawlees.txt\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>8 417 pages dans le sitemap que Googlebot n'a pas visitées en 3 mois. Screaming Frog ne remontera jamais cette information parce que ce n'est pas son rôle. C'est la différence entre un diagnostic d'architecture et une observation du comportement de crawl réel.\u003C/p>\n\u003Cp>Pour une analyse approfondie de ce que les logs révèlent sur les crawlers — y compris les bots IA — consultez notre article sur \u003Ca href=\"/blog/why-log-file-analysis-matters-for-ai-crawlers-and-search-visibility\">l'analyse des fichiers de log pour les crawlers IA\u003C/a>.\u003C/p>\n\u003Ch2>Le rendering JavaScript : l'angle mort le plus coûteux\u003C/h2>\n\u003Cp>La majorité des crawlers tools proposent un mode \"JavaScript rendering\". Screaming Frog utilise un Chromium headless embarqué. Sitebulb fait de même. Le problème : leur rendering ne reproduit pas le comportement du Web Rendering Service (WRS) de Google.\u003C/p>\n\u003Ch3>Les différences concrètes\u003C/h3>\n\u003Cp>Le WRS de Google fonctionne en deux passes documentées par Google dans sa \u003Ca href=\"https://developers.google.com/search/docs/crawling-indexing/javascript/javascript-seo-basics\">documentation sur le rendu JavaScript\u003C/a> :\u003C/p>\n\u003Col>\n\u003Cli>\u003Cstrong>Première passe\u003C/strong> : Googlebot récupère le HTML brut, indexe ce qu'il peut, et met la page en file d'attente pour le rendering.\u003C/li>\n\u003Cli>\u003Cstrong>Deuxième passe\u003C/strong> : le WRS rend la page avec Chromium, exécute le JS, et met à jour l'index.\u003C/li>\n\u003C/ol>\n\u003Cp>Le délai entre les deux passes est variable. Sur un site à faible autorité, il peut dépasser une semaine. Pendant ce temps, Google indexe le HTML brut — qui, sur un SPA React ou une application Angular, peut être quasi vide.\u003C/p>\n\u003Ch3>Ce que votre tool ne teste pas\u003C/h3>\n\u003Cp>Screaming Frog rend la page instantanément. Il ne simule pas le délai. Il ne simule pas non plus les erreurs JavaScript qui surviennent uniquement dans l'environnement WRS (pas de \u003Ccode>localStorage\u003C/code>, pas de \u003Ccode>sessionStorage\u003C/code>, certaines APIs navigateur absentes).\u003C/p>\n\u003Cp>Voici un cas réel : un composant React qui charge les données produit côté client :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// ProductPage.tsx — composant problématique\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">const\u003C/span>\u003Cspan style=\"color:#B392F0\"> ProductPage\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> ({ \u003C/span>\u003Cspan style=\"color:#FFAB70\">productId\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> }\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { \u003C/span>\u003Cspan style=\"color:#FFAB70\">productId\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> string\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> }) \u003C/span>\u003Cspan style=\"color:#F97583\">=>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> [\u003C/span>\u003Cspan style=\"color:#79B8FF\">product\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#79B8FF\">setProduct\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#B392F0\"> useState\u003C/span>\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">Product\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#79B8FF\"> null\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>(\u003C/span>\u003Cspan style=\"color:#79B8FF\">null\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> [\u003C/span>\u003Cspan style=\"color:#79B8FF\">error\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#79B8FF\">setError\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#B392F0\"> useState\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#79B8FF\">false\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  useEffect\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(() \u003C/span>\u003Cspan style=\"color:#F97583\">=>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">    // Ce fetch dépend d'un cookie de session pour la localisation\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> locale\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> localStorage.\u003C/span>\u003Cspan style=\"color:#B392F0\">getItem\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'user_locale'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">||\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'fr-FR'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">    fetch\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`/api/products/${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">productId\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}?locale=${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">locale\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      headers: {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        'Authorization'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">`Bearer ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">sessionStorage\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">getItem\u003C/span>\u003Cspan style=\"color:#9ECBFF\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'api_token'\u003C/span>\u003Cspan style=\"color:#9ECBFF\">)\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    })\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      .\u003C/span>\u003Cspan style=\"color:#B392F0\">then\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">res\u003C/span>\u003Cspan style=\"color:#F97583\"> =>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> res.\u003C/span>\u003Cspan style=\"color:#B392F0\">json\u003C/span>\u003Cspan style=\"color:#E1E4E8\">())\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      .\u003C/span>\u003Cspan style=\"color:#B392F0\">then\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">data\u003C/span>\u003Cspan style=\"color:#F97583\"> =>\u003C/span>\u003Cspan style=\"color:#B392F0\"> setProduct\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(data))\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      .\u003C/span>\u003Cspan style=\"color:#B392F0\">catch\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(() \u003C/span>\u003Cspan style=\"color:#F97583\">=>\u003C/span>\u003Cspan style=\"color:#B392F0\"> setError\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#79B8FF\">true\u003C/span>\u003Cspan style=\"color:#E1E4E8\">));\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }, [productId]);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003Cspan style=\"color:#F97583\">!\u003C/span>\u003Cspan style=\"color:#E1E4E8\">product) \u003C/span>\u003Cspan style=\"color:#F97583\">return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> &#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">div\u003C/span>\u003Cspan style=\"color:#B392F0\"> className\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"loading-skeleton\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> />;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">div\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      &#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">h1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>{product.name}\u003C/span>\u003Cspan style=\"color:#F97583\">&#x3C;/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">h1\u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      &#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>{product.description}\u003C/span>\u003Cspan style=\"color:#F97583\">&#x3C;/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">p\u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {\u003C/span>\u003Cspan style=\"color:#6A737D\">/* ... */\u003C/span>\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    &#x3C;/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">div\u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  );\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">};\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Screaming Frog va rendre cette page avec succès dans la plupart des cas — il simule un navigateur complet. Mais le WRS de Google n'a pas accès à \u003Ccode>localStorage\u003C/code> ni \u003Ccode>sessionStorage\u003C/code>. Le fetch échoue silencieusement, le composant reste sur le skeleton loader, et Google indexe une page vide.\u003C/p>\n\u003Cp>Le fix est trivial en SSR :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// ProductPage.tsx — version SSR-compatible (Next.js App Router)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">export\u003C/span>\u003Cspan style=\"color:#F97583\"> async\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> generateMetadata\u003C/span>\u003Cspan style=\"color:#E1E4E8\">({ \u003C/span>\u003Cspan style=\"color:#FFAB70\">params\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> }\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { \u003C/span>\u003Cspan style=\"color:#FFAB70\">params\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { \u003C/span>\u003Cspan style=\"color:#FFAB70\">id\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> string\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> } }) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> product\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> getProduct\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(params.id, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'fr-FR'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">); \u003C/span>\u003Cspan style=\"color:#6A737D\">// locale par défaut côté serveur\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    title: product.name,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    description: product.description.\u003C/span>\u003Cspan style=\"color:#B392F0\">slice\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#79B8FF\">0\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#79B8FF\">155\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  };\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">export\u003C/span>\u003Cspan style=\"color:#F97583\"> default\u003C/span>\u003Cspan style=\"color:#F97583\"> async\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> ProductPage\u003C/span>\u003Cspan style=\"color:#E1E4E8\">({ \u003C/span>\u003Cspan style=\"color:#FFAB70\">params\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> }\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { \u003C/span>\u003Cspan style=\"color:#FFAB70\">params\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { \u003C/span>\u003Cspan style=\"color:#FFAB70\">id\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> string\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> } }) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> product\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> getProduct\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(params.id, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'fr-FR'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">div\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      &#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">h1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>{product.name}\u003C/span>\u003Cspan style=\"color:#F97583\">&#x3C;/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">h1\u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      &#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>{product.description}\u003C/span>\u003Cspan style=\"color:#F97583\">&#x3C;/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">p\u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {\u003C/span>\u003Cspan style=\"color:#6A737D\">/* Hydration côté client pour les éléments interactifs */\u003C/span>\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">      &#x3C;\u003C/span>\u003Cspan style=\"color:#E1E4E8\">AddToCartButton productId\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">{params.id} \u003C/span>\u003Cspan style=\"color:#F97583\">/>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    &#x3C;/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">div\u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  );\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Ce type de problème est invisible dans Screaming Frog mais catastrophique dans l'index Google. La seule façon de le détecter : comparer le HTML brut servi à Googlebot avec le DOM rendu, via l'outil d'inspection d'URL de Search Console ou via un test manuel avec \u003Ccode>curl\u003C/code> :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Voir exactement ce que Googlebot reçoit en première passe\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -A\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  -s\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> https://www.votresite.fr/produit/chaussure-running-x500\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  |\u003C/span>\u003Cspan style=\"color:#B392F0\"> grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -i\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"&#x3C;h1>\\|&#x3C;title>\\|&#x3C;meta name=\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\">description\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Si ce \u003Ccode>curl\u003C/code> renvoie un \u003Ccode>&#x3C;h1>\u003C/code> vide ou un skeleton loader, vous avez un problème que Screaming Frog ne verra pas.\u003C/p>\n\u003Cp>Pour aller plus loin sur les enjeux du rendering JavaScript et les fallbacks nécessaires, voir notre analyse sur \u003Ca href=\"/blog/no-javascript-fallbacks-in-2026-less-critical-still-necessary\">les fallbacks JavaScript en 2026\u003C/a>.\u003C/p>\n\u003Ch2>Les canonicals : quand Google ignore vos directives\u003C/h2>\n\u003Cp>Les outils SEO vérifient la syntaxe de vos canonicals. Ils s'assurent que la balise \u003Ccode>&#x3C;link rel=\"canonical\">\u003C/code> est présente, qu'elle pointe vers une URL valide, qu'elle est cohérente avec le hreflang. Ce qu'ils ne vérifient pas : est-ce que Google respecte effectivement votre canonical ?\u003C/p>\n\u003Ch3>Le scénario classique que les outils ratent\u003C/h3>\n\u003Cp>Un site e-commerce avec des filtres de facettes. Chaque combinaison couleur/taille/marque génère une URL distincte :\u003C/p>\n\u003Cpre>\u003Ccode>/chaussures?couleur=noir\n/chaussures?couleur=noir&#x26;taille=42\n/chaussures?couleur=noir&#x26;taille=42&#x26;marque=nike\n\u003C/code>\u003C/pre>\n\u003Cp>Vous avez configuré un canonical vers \u003Ccode>/chaussures\u003C/code> sur toutes ces pages. Screaming Frog confirme : canonical présent, syntaxe correcte, aucune erreur. Audit clean.\u003C/p>\n\u003Cp>Mais Google peut décider d'ignorer votre canonical. C'est documenté : Google traite le canonical comme un \u003Cstrong>signal\u003C/strong>, pas une directive. Si Google détecte que le contenu de \u003Ccode>/chaussures?couleur=noir\u003C/code> est significativement différent de \u003Ccode>/chaussures\u003C/code>, il peut choisir de l'indexer séparément — ou pire, choisir la version paramétrée comme canonical à la place de votre page principale.\u003C/p>\n\u003Cp>Google a d'ailleurs listé \u003Ca href=\"/blog/google-lists-9-scenarios-that-explain-how-it-picks-canonical-urls-via-sejournal-martinibuster\">9 scénarios expliquant comment il sélectionne les URLs canoniques\u003C/a>. Parmi eux : les signaux de linking interne. Si 200 pages internes linkent vers \u003Ccode>/chaussures?couleur=noir\u003C/code> et seulement 3 vers \u003Ccode>/chaussures\u003C/code>, Google peut inverser votre canonical.\u003C/p>\n\u003Ch3>Comment détecter le problème\u003C/h3>\n\u003Cp>Search Console est le seul outil fiable ici. Dans le rapport \"Pages\" > \"Indexation\", filtrez par \"Autre page ayant un canonical choisi par Google\" ou \"URL canonique alternative envoyée par l'utilisateur\". Cela vous montre les pages où Google a \u003Cstrong>activement décidé\u003C/strong> d'ignorer votre directive.\u003C/p>\n\u003Cp>Aucun crawler tool ne remonte cette donnée parce qu'elle n'existe que côté Google.\u003C/p>\n\u003Ch2>Les réponses conditionnelles : le cloaking involontaire\u003C/h2>\n\u003Cp>C'est probablement l'angle mort le plus insidieux. Votre serveur peut servir des réponses différentes selon le user-agent, l'IP source, les cookies, les headers \u003Ccode>Accept-Language\u003C/code>, ou même la charge serveur — et vous ne le savez peut-être pas.\u003C/p>\n\u003Ch3>Le CDN qui cache des 200 sur des 404\u003C/h3>\n\u003Cp>Scénario réel : un site média de 45 000 articles utilise Cloudflare avec un cache agressif. Un article est supprimé côté CMS, le serveur origin renvoie un 404. Mais Cloudflare a mis en cache la version 200 de la page. Googlebot, qui passe par les mêmes PoPs que les visiteurs classiques, reçoit un 200 avec du contenu périmé. L'article reste indexé indéfiniment.\u003C/p>\n\u003Cp>Screaming Frog crawle depuis votre IP — il peut recevoir la réponse du cache ou de l'origin selon la configuration. Il n'a aucun moyen de savoir ce que Googlebot reçoit réellement.\u003C/p>\n\u003Ch3>Les redirections conditionnelles\u003C/h3>\n\u003Cp>Autre cas classique : les redirections géo-localisées. Un middleware Next.js qui redirige selon la géolocalisation de l'IP :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// middleware.ts — piège à Googlebot\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { NextResponse } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'next/server'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#F97583\"> type\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { NextRequest } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'next/server'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">export\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> middleware\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">request\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#B392F0\"> NextRequest\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> country\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> request.geo?.country \u003C/span>\u003Cspan style=\"color:#F97583\">||\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'FR'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> pathname\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> request.nextUrl.pathname;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  // Redirection géo-conditionnelle\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (country \u003C/span>\u003Cspan style=\"color:#F97583\">===\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'US'\u003C/span>\u003Cspan style=\"color:#F97583\"> &#x26;&#x26;\u003C/span>\u003Cspan style=\"color:#F97583\"> !\u003C/span>\u003Cspan style=\"color:#E1E4E8\">pathname.\u003C/span>\u003Cspan style=\"color:#B392F0\">startsWith\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/en'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> NextResponse.\u003C/span>\u003Cspan style=\"color:#B392F0\">redirect\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#F97583\">new\u003C/span>\u003Cspan style=\"color:#B392F0\"> URL\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`/en${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">pathname\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, request.url));\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (country \u003C/span>\u003Cspan style=\"color:#F97583\">===\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'DE'\u003C/span>\u003Cspan style=\"color:#F97583\"> &#x26;&#x26;\u003C/span>\u003Cspan style=\"color:#F97583\"> !\u003C/span>\u003Cspan style=\"color:#E1E4E8\">pathname.\u003C/span>\u003Cspan style=\"color:#B392F0\">startsWith\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/de'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> NextResponse.\u003C/span>\u003Cspan style=\"color:#B392F0\">redirect\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#F97583\">new\u003C/span>\u003Cspan style=\"color:#B392F0\"> URL\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`/de${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">pathname\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, request.url));\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> NextResponse.\u003C/span>\u003Cspan style=\"color:#B392F0\">next\u003C/span>\u003Cspan style=\"color:#E1E4E8\">();\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Googlebot crawle principalement depuis les États-Unis. Ce middleware redirige systématiquement Googlebot vers \u003Ccode>/en/*\u003C/code>, même quand il tente de crawler vos pages \u003Ccode>/fr/*\u003C/code>. Résultat : vos pages françaises disparaissent de l'index français, remplacées par les versions anglaises.\u003C/p>\n\u003Cp>Screaming Frog, lancé depuis votre bureau à Paris, crawle les pages \u003Ccode>/fr/*\u003C/code> sans problème. Tout semble parfait. L'angle mort est total.\u003C/p>\n\u003Cp>La correction :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// middleware.ts — version safe pour le SEO\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">export\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> middleware\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">request\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#B392F0\"> NextRequest\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> userAgent\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> request.headers.\u003C/span>\u003Cspan style=\"color:#B392F0\">get\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'user-agent'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">||\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> ''\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> isBot\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> /\u003C/span>\u003Cspan style=\"color:#DBEDFF\">googlebot\u003C/span>\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003Cspan style=\"color:#DBEDFF\">bingbot\u003C/span>\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003Cspan style=\"color:#DBEDFF\">yandex\u003C/span>\u003Cspan style=\"color:#F97583\">|\u003C/span>\u003Cspan style=\"color:#DBEDFF\">baiduspider\u003C/span>\u003Cspan style=\"color:#9ECBFF\">/\u003C/span>\u003Cspan style=\"color:#F97583\">i\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">test\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(userAgent);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  // Ne JAMAIS rediriger les bots — leur servir le contenu demandé\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (isBot) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> NextResponse.\u003C/span>\u003Cspan style=\"color:#B392F0\">next\u003C/span>\u003Cspan style=\"color:#E1E4E8\">();\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> country\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> request.geo?.country \u003C/span>\u003Cspan style=\"color:#F97583\">||\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'FR'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> pathname\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> request.nextUrl.pathname;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (country \u003C/span>\u003Cspan style=\"color:#F97583\">===\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'US'\u003C/span>\u003Cspan style=\"color:#F97583\"> &#x26;&#x26;\u003C/span>\u003Cspan style=\"color:#F97583\"> !\u003C/span>\u003Cspan style=\"color:#E1E4E8\">pathname.\u003C/span>\u003Cspan style=\"color:#B392F0\">startsWith\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/en'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> NextResponse.\u003C/span>\u003Cspan style=\"color:#B392F0\">redirect\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#F97583\">new\u003C/span>\u003Cspan style=\"color:#B392F0\"> URL\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`/en${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">pathname\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, request.url));\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> NextResponse.\u003C/span>\u003Cspan style=\"color:#B392F0\">next\u003C/span>\u003Cspan style=\"color:#E1E4E8\">();\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Mieux encore : ne pas rediriger du tout, mais afficher un bandeau de suggestion de changement de langue. Les redirections géo-conditionnelles sont \u003Ca href=\"https://developers.google.com/search/docs/specialty/international/managing-multi-regional-sites#locale-adaptive-pages\">explicitement déconseillées par Google\u003C/a>.\u003C/p>\n\u003Ch2>Les métriques de performance : le mirage des scores synthétiques\u003C/h2>\n\u003Cp>Lighthouse donne un score de performance de 92. PageSpeed Insights confirme. Les Core Web Vitals sont au vert dans Search Console. Pourtant, le Time to First Byte (TTFB) réel des visiteurs mobiles sur réseau 4G en zone périurbaine dépasse régulièrement 2,5 secondes.\u003C/p>\n\u003Ch3>Le problème des tests synthétiques\u003C/h3>\n\u003Cp>Lighthouse s'exécute sur un réseau local ou simulé, depuis un datacenter, avec des conditions stables. Les données CrUX (Chrome User Experience Report) reflètent les vrais utilisateurs, mais elles sont agrégées sur 28 jours et par origin — pas par page individuelle (sauf sur les pages à très fort trafic).\u003C/p>\n\u003Cp>L'angle mort : vous optimisez vos Core Web Vitals sur la base de données synthétiques qui ne reflètent pas l'expérience réelle. Un LCP de 1,8s sur Lighthouse peut correspondre à un LCP de 4,2s sur un Samsung Galaxy A13 en 4G.\u003C/p>\n\u003Ch3>Ce que révèle le Real User Monitoring\u003C/h3>\n\u003Cp>La seule approche fiable consiste à mesurer les performances réelles via l'API Performance Observer. Voici un snippet de RUM minimal :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// rum-collector.js — collecte des Core Web Vitals réels\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { onLCP, onFID, onCLS, onINP, onTTFB } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'web-vitals'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">function\u003C/span>\u003Cspan style=\"color:#B392F0\"> sendToAnalytics\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">metric\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> payload\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    name: metric.name,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    value: metric.value,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    rating: metric.rating, \u003C/span>\u003Cspan style=\"color:#6A737D\">// 'good', 'needs-improvement', 'poor'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    delta: metric.delta,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    id: metric.id,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    url: window.location.pathname,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    connection: navigator.connection?.effectiveType \u003C/span>\u003Cspan style=\"color:#F97583\">||\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'unknown'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    deviceMemory: navigator.deviceMemory \u003C/span>\u003Cspan style=\"color:#F97583\">||\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'unknown'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    timestamp: Date.\u003C/span>\u003Cspan style=\"color:#B392F0\">now\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  };\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  // Beacon API pour ne pas bloquer le déchargement de la page\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (navigator.sendBeacon) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    navigator.\u003C/span>\u003Cspan style=\"color:#B392F0\">sendBeacon\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'/api/rum'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#79B8FF\">JSON\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">stringify\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(payload));\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">onLCP\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(sendToAnalytics);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">onINP\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(sendToAnalytics);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">onCLS\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(sendToAnalytics);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">onTTFB\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(sendToAnalytics);\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Avec ces données terrain, vous découvrirez probablement que 15 à 25% de vos visiteurs ont une expérience dégradée que Lighthouse ne capture jamais. C'est une donnée que Google possède (via Chrome) mais que vos outils SEO ne remontent pas.\u003C/p>\n\u003Ch2>Le linking interne : l'angle mort quantitatif des crawlers\u003C/h2>\n\u003Cp>Screaming Frog analyse votre linking interne. Il compte les liens, calcule la profondeur de crawl, identifie les pages orphelines. Ce qu'il ne fait pas : pondérer les liens par leur position dans la page, leur contexte sémantique, et leur probabilité de clic.\u003C/p>\n\u003Ch3>Le poids réel d'un lien interne\u003C/h3>\n\u003Cp>Un lien dans votre footer présent sur 22 000 pages n'a pas la même valeur qu'un lien contextuel dans le corps d'un article de référence. Screaming Frog les compte de la même façon. Google ne les traite pas de la même façon.\u003C/p>\n\u003Cp>Un lien dans un menu de navigation replié (hamburger menu mobile) n'a pas le même poids qu'un lien visible dans le contenu principal. Un lien inséré dynamiquement via JavaScript après un scroll n'a pas le même poids qu'un lien présent dans le HTML initial.\u003C/p>\n\u003Cp>Les outils vous donnent le \u003Cstrong>graphe\u003C/strong> de linking interne. Ils ne vous donnent pas la \u003Cstrong>topologie pondérée\u003C/strong> — le flux réel de PageRank interne tel que Google le calcule. Cette information n'existe nulle part dans aucun outil tiers. La seule approximation disponible : les données de performance de Search Console (impressions, clics) croisées avec votre structure de liens.\u003C/p>\n\u003Cp>Si vous travaillez sur un site dont \u003Ca href=\"/blog/why-your-new-seo-vendor-can-t-build-on-a-broken-foundation-via-sejournal-taylordanrw\">les fondations techniques sont déjà fragiles\u003C/a>, ces angles morts se cumulent et deviennent critiques.\u003C/p>\n\u003Ch2>Construire un système de vérité terrain\u003C/h2>\n\u003Cp>L'enjeu n'est pas de jeter les outils. Screaming Frog reste indispensable pour les audits d'architecture. Search Console est la seule source de vérité côté Google. Ahrefs et Semrush sont précieux pour l'analyse concurrentielle et le suivi des backlinks.\u003C/p>\n\u003Cp>L'enjeu est de \u003Cstrong>combler les angles morts\u003C/strong> avec des données que les outils ne collectent pas.\u003C/p>\n\u003Ch3>La stack de monitoring complète\u003C/h3>\n\u003Col>\n\u003Cli>\u003Cstrong>Crawl tools\u003C/strong> (Screaming Frog, Sitebulb) : audit d'architecture, détection des erreurs syntaxiques, inventaire technique.\u003C/li>\n\u003Cli>\u003Cstrong>Search Console\u003C/strong> : vérité terrain côté Google — pages indexées, canonicals réels, erreurs de crawl, performance de recherche.\u003C/li>\n\u003Cli>\u003Cstrong>Logs serveur\u003C/strong> : comportement réel de Googlebot — fréquence de crawl, pages ignorées, codes de réponse servis. C'est la donnée la plus sous-exploitée.\u003C/li>\n\u003Cli>\u003Cstrong>RUM (Real User Monitoring)\u003C/strong> : performance réelle, pas synthétique. Web-vitals + collecteur maison ou outil dédié.\u003C/li>\n\u003Cli>\u003Cstrong>Monitoring continu\u003C/strong> : détection des régressions en temps réel — meta disparues, changements de status code, SSR cassé. Un outil comme Seogard surveille ces signaux automatiquement et alerte avant que l'impact SEO ne se matérialise.\u003C/li>\n\u003C/ol>\n\u003Ch3>Le test de réalité hebdomadaire\u003C/h3>\n\u003Cp>Chaque semaine, prenez 10 pages stratégiques et faites le test de réalité :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Pour chaque page stratégique, vérifier ce que Googlebot reçoit réellement\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> url \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  \"https://www.votresite.fr/categorie/chaussures-running\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  \"https://www.votresite.fr/produit/air-max-2026-noir\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  \"https://www.votresite.fr/guide/choisir-chaussures-trail\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">; \u003C/span>\u003Cspan style=\"color:#F97583\">do\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"=== \u003C/span>\u003Cspan style=\"color:#E1E4E8\">$url\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> ===\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  # Status code\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -s\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -o\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> /dev/null\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -w\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"%{http_code}\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">    -A\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$url\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  # Vérifier title et meta description dans le HTML brut\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -s\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -A\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$url\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -ioP\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '(&#x3C;title>.*?&#x3C;/title>|&#x3C;meta name=\"description\"[^>]*>)'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  # Vérifier canonical\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -s\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -A\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$url\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -ioP\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '&#x3C;link rel=\"canonical\"[^>]*>'\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"---\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">done\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Ce script de 30 secondes vous en apprend plus sur votre SEO réel qu'un audit Screaming Frog de 4 heures. Non pas parce que Screaming Frog est mauvais, mais parce qu'il répond à une question différente.\u003C/p>\n\u003Cp>Les outils répondent à : \"Est-ce que mon site est techniquement correct ?\"\u003C/p>\n\u003Cp>Les données brutes répondent à : \"Est-ce que Google voit ce que je crois qu'il voit ?\"\u003C/p>\n\u003Cp>Ce sont deux questions fondamentalement différentes. La deuxième est celle qui détermine votre trafic organique. Et c'est précisément celle que la plupart des équipes SEO ne posent jamais, aveuglées par le confort d'un dashboard vert. Les régressions silencieuses — un canonical qui dérive, un SSR qui casse après un déploiement, un backlink stratégique qui disparaît — ne génèrent aucune alerte dans un crawler tool parce qu'il n'est pas branché sur la réalité de production. Seul un monitoring continu sur les données brutes comble ce fossé.\u003C/p>\n\u003Cpre>\u003Ccode>\u003C/code>\u003C/pre>",null,12,[18,19,20,21,22],"technical-seo","blind-spots","log-analysis","crawl-budget","rendering","Angles morts du SEO technique : ce que vos outils ne voient pas","Thu Apr 23 2026 06:02:47 GMT+0000 (Coordinated Universal Time)",[26,41,55],{"_id":27,"slug":28,"__v":6,"author":7,"canonical":29,"category":10,"createdAt":30,"date":31,"description":32,"image":15,"imageAlt":15,"readingTime":16,"tags":33,"title":39,"updatedAt":40},"69e864a1aa6b273b0cc314ff","the-hidden-bland-tax-that-could-erase-your-brand-from-ai-search","https://seogard.io/blog/the-hidden-bland-tax-that-could-erase-your-brand-from-ai-search","2026-04-22T06:03:13.538Z","2026-04-22","L'IA filtre les marques sans signaux distinctifs. Analyse technique du 'bland tax' et stratégies concrètes pour rester visible dans la recherche IA.",[34,35,36,37,38],"AI search","bland tax","brand authority","AEO","GEO","Le 'bland tax' : pourquoi l'IA efface les marques génériques","Wed Apr 22 2026 06:03:13 GMT+0000 (Coordinated Universal Time)",{"_id":42,"slug":43,"__v":6,"author":7,"canonical":44,"category":10,"createdAt":45,"date":31,"description":46,"image":15,"imageAlt":15,"readingTime":16,"tags":47,"title":53,"updatedAt":54},"69e8e323aa6b273b0c283fd0","seo-reporting-outgrew-data-studio-here-s-what-comes-next","https://seogard.io/blog/seo-reporting-outgrew-data-studio-here-s-what-comes-next","2026-04-22T15:02:59.713Z","Les dashboards rigides freinent le reporting SEO. APIs, AI coding tools et scripts custom remplacent Looker Studio pour des workflows plus rapides.",[48,49,50,51,52],"reporting","data studio","API","SEO technique","automatisation","SEO reporting après Data Studio : APIs, code et workflows flexibles","Wed Apr 22 2026 15:02:59 GMT+0000 (Coordinated Universal Time)",{"_id":56,"slug":57,"__v":6,"author":7,"canonical":58,"category":10,"createdAt":59,"date":31,"description":60,"image":15,"imageAlt":15,"readingTime":16,"tags":61,"title":65,"updatedAt":66},"69e90d58aa6b273b0c4a0096","the-ghost-citation-problem-via-sejournal-kevin-indig","https://seogard.io/blog/the-ghost-citation-problem-via-sejournal-kevin-indig","2026-04-22T18:03:04.818Z","Analyse technique du Ghost Citation Problem : comment les LLM mentionnent des marques sans lier, et comment détecter et contrer ce phénomène.",[62,63,34,38,64],"ghost citation","LLM","brand mentions","Ghost Citations : quand les LLM citent sans sourcer","Wed Apr 22 2026 18:03:04 GMT+0000 (Coordinated Universal Time)"]