[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fGaVeJCbfITQoKAjKPu5jKHnEcak2e0zmL6Z7Cq8Q360":3,"$fZ5pjZoshU8E4JCHYires4AtBfPrWRQYNa23cSqa1pb4":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},"69f98813aa6b273b0c8d2b0c","why-ai-search-skips-your-content-and-how-to-diagnose-where-it-s-failing-via-sejournal-jeffrey-coyle",0,"Equipe Seogard","Un site e-commerce de 22 000 pages produit. Googlebot crawle 8 000 pages par jour. GPTBot en visite 1 200. Pourtant, sur les 150 requêtes commerciales testées dans ChatGPT et Perplexity, le site n'est cité que 3 fois. Le contenu existe, il est crawlé, mais il est systématiquement ignoré par les moteurs de recherche IA. Le problème ne se situe pas là où vous pensez.\n\nL'article récemment publié par Search Engine Journal, sponsorisé par Siteimprove, pose la bonne question : pourquoi un contenu indexé par Google peut-il être invisible pour les LLM ? Mais la réponse mérite d'aller bien au-delà du diagnostic de surface. Il y a un pipeline technique complet entre le crawl d'un bot IA et la citation effective dans une réponse générée, et chaque étape est un point de rupture potentiel.\n\n## Le pipeline de visibilité IA : 5 étapes, 5 points de rupture\n\nLa visibilité dans les moteurs de recherche IA (ChatGPT Search, Perplexity, Gemini, Copilot) repose sur un pipeline fondamentalement différent de celui de Google Search. Voici les étapes, dans l'ordre :\n\n1. **Crawl** — Le bot IA (GPTBot, PerplexityBot, ClaudeBot) accède à la page\n2. **Extraction** — Le contenu textuel est extrait du HTML rendu\n3. **Chunking** — Le contenu est découpé en segments sémantiques\n4. **Embedding** — Chaque chunk est vectorisé dans un espace sémantique\n5. **Retrieval + Citation** — Lors d'une requête utilisateur, le système RAG (Retrieval-Augmented Generation) sélectionne les chunks les plus pertinents et décide de les citer ou non\n\nUn contenu peut passer l'étape 1 (le bot crawle la page avec succès) et échouer à l'étape 3 (le contenu est mal découpé car la structure HTML est ambiguë) ou à l'étape 5 (le chunk est récupéré mais jugé redondant avec une source plus autoritaire).\n\nLe diagnostic technique consiste à identifier précisément à quelle étape votre contenu décroche.\n\n## Étape 1 : vérifier que les bots IA crawlent réellement vos pages\n\n### Analyser les logs serveur\n\nLa première vérification est triviale mais souvent négligée. Vous devez confirmer que GPTBot, PerplexityBot et les autres accèdent effectivement à vos pages stratégiques — pas seulement à votre homepage et vos pages \"À propos\".\n\n```bash\n# Extraire les hits GPTBot des 30 derniers jours, groupés par URL\ngrep \"GPTBot\" /var/log/nginx/access.log \\\n  | awk '{print $7}' \\\n  | sort \\\n  | uniq -c \\\n  | sort -rn \\\n  | head -50\n\n# Même chose pour PerplexityBot\ngrep \"PerplexityBot\" /var/log/nginx/access.log \\\n  | awk '{print $7, $9}' \\\n  | sort \\\n  | uniq -c \\\n  | sort -rn \\\n  | head -50\n```\n\nCe que vous cherchez : la distribution des pages crawlées. Si GPTBot visite principalement vos pages de catégories et ignore vos pages produits ou vos articles de fond, le problème est un problème de découverte. Les bots IA suivent les liens de la même manière que Googlebot — votre maillage interne dicte ce qu'ils trouvent.\n\n### Le piège du robots.txt mal configuré\n\nUne analyse de [68 millions de visites de crawlers IA](/blog/68-million-ai-crawler-visits-show-what-drives-ai-search-visibility-via-sejournal-martinibuster) a montré que la distribution de crawl varie massivement d'un bot à l'autre. Certains sites bloquent GPTBot par précaution sans réaliser qu'ils se coupent de la visibilité ChatGPT Search.\n\nVérifiez votre `robots.txt` avec précision. Google a d'ailleurs récemment étendu sa documentation sur les [règles robots.txt non supportées](/blog/google-may-expand-unsupported-robots-txt-rules-list-via-sejournal-mattgsouthern), ce qui complexifie encore la gestion multi-bots.\n\n```nginx\n# robots.txt — Configuration recommandée pour les bots IA\n# Autoriser le crawl tout en bloquant les sections non pertinentes\n\nUser-agent: GPTBot\nAllow: /blog/\nAllow: /guides/\nAllow: /produits/\nDisallow: /compte/\nDisallow: /panier/\nDisallow: /api/\nCrawl-delay: 2\n\nUser-agent: PerplexityBot\nAllow: /blog/\nAllow: /guides/\nAllow: /produits/\nDisallow: /compte/\nDisallow: /panier/\nCrawl-delay: 2\n\nUser-agent: ClaudeBot\nAllow: /blog/\nAllow: /guides/\nAllow: /produits/\nDisallow: /compte/\nDisallow: /panier/\nCrawl-delay: 5\n\nUser-agent: Bytespider\nDisallow: /\n```\n\nNotez la distinction : autoriser les bots des systèmes que vous voulez cibler (GPTBot pour ChatGPT, PerplexityBot pour Perplexity), bloquer ceux qui n'apportent rien (Bytespider de ByteDance consomme du bandwidth sans retour mesurable pour la plupart des sites occidentaux). La hausse récente de [l'activité de crawl d'OpenAI](/blog/openai-crawl-activity-tripled-since-gpt-5-data-shows-via-sejournal-mattgsouthern) rend cette configuration d'autant plus critique.\n\n### Codes de réponse et temps de réponse\n\nLes bots IA sont moins tolérants que Googlebot sur les temps de réponse. GPTBot abandonne une requête plus rapidement. Si votre serveur met 3 secondes à répondre (acceptable pour Googlebot), GPTBot peut timeout et passer à la suite.\n\nDans vos logs, filtrez les réponses 5xx et les temps de réponse supérieurs à 2 secondes pour les user-agents IA. Un taux d'erreur de 15% sur GPTBot signifie que 15% de vos pages ne sont jamais ingérées.\n\n## Étape 2 : ce que le bot IA voit vs ce que vous pensez qu'il voit\n\nC'est le point de rupture le plus sous-estimé. Les bots IA ne rendent pas le JavaScript de la même manière que Googlebot (qui utilise un moteur Chromium complet). GPTBot et PerplexityBot se comportent davantage comme des crawlers headless basiques — ils récupèrent le HTML initial et extraient le texte.\n\n### Tester le rendu sans JavaScript\n\n```bash\n# Comparer le contenu visible avec et sans JS\n# 1. Récupérer le HTML brut (ce que GPTBot voit probablement)\ncurl -s -A \"GPTBot/1.0\" https://votre-site.fr/guide-technique \\\n  | python3 -c \"\nimport sys\nfrom html.parser import HTMLParser\n\nclass TextExtractor(HTMLParser):\n    def __init__(self):\n        super().__init__()\n        self.text = []\n        self.skip = False\n    def handle_starttag(self, tag, attrs):\n        if tag in ('script', 'style', 'noscript'):\n            self.skip = True\n    def handle_endtag(self, tag):\n        if tag in ('script', 'style', 'noscript'):\n            self.skip = False\n    def handle_data(self, data):\n        if not self.skip and data.strip():\n            self.text.append(data.strip())\n\ne = TextExtractor()\ne.feed(sys.stdin.read())\nprint('\\n'.join(e.text))\n\" > content_nojs.txt\n\n# 2. Récupérer le contenu rendu via Puppeteer/Playwright\nnpx playwright screenshot https://votre-site.fr/guide-technique \\\n  --wait-until networkidle\n\n# 3. Comparer les deux fichiers\nwc -w content_nojs.txt  # Si \u003C 200 mots, le contenu dépend du JS\n```\n\nSi la version sans JavaScript ne contient que le header, le footer et un `\u003Cdiv id=\"app\">\u003C/div>` vide, votre contenu est invisible pour les bots IA. Ce scénario est extrêmement fréquent sur les SPA React/Vue sans SSR.\n\n### Le cas concret : migration SPA vers SSR\n\nPrenez un média tech de 8 000 articles construit sur une SPA React. Après audit :\n- **Googlebot** : indexe 7 200 pages (rendu JS côté Google)\n- **GPTBot** : crawle 3 500 pages, mais n'extrait du contenu substantiel que sur 400 (les pages dont le contenu est dans le HTML initial — pages statiques legacy)\n- **Résultat Perplexity** : le site est cité sur 2 requêtes parmi 80 testées\n\nAprès migration vers Next.js avec SSR (Server-Side Rendering), le contenu est présent dans le HTML initial. En 6 semaines :\n- GPTBot extrait du contenu sur 3 200 pages\n- Les citations Perplexity passent de 2 à 17 sur le même panel de requêtes\n\nLe SSR n'est pas une option pour la visibilité IA — c'est un prérequis. Et les [régressions SSR silencieuses](/blog/why-tracking-parameters-in-internal-links-hurt-your-seo-and-how-to-fix-them) (un déploiement qui casse le rendu serveur sans que personne ne s'en aperçoive) sont le type exact de problème qu'un monitoring continu comme Seogard détecte avant que l'impact ne se matérialise.\n\n## Étape 3 : la structure sémantique détermine le chunking\n\nLes systèmes RAG ne lisent pas votre page comme un humain. Ils la découpent en chunks — des segments de 200 à 500 tokens en général — puis vectorisent chaque chunk indépendamment. La qualité de ce découpage dépend directement de votre structure HTML.\n\n### Pourquoi la hiérarchie H1-H6 compte (vraiment, cette fois)\n\nEn SEO classique, la hiérarchie des headings est un signal parmi d'autres. Pour les systèmes RAG, c'est le squelette du chunking. Un H2 suivi de 3 paragraphes = un chunk cohérent. Un mur de texte de 2 000 mots sans aucun heading = un chunk qui mélange 4 sujets différents et dont l'embedding vectoriel ne matche aucune requête précise.\n\n```html\n\u003C!-- ❌ Structure anti-chunking : tout le contenu dans un seul bloc -->\n\u003Carticle>\n  \u003Ch1>Guide complet de la migration HTTPS\u003C/h1>\n  \u003Cp>La migration HTTPS implique le changement de protocole...\n  [2000 mots sans aucun sous-titre, mélangeant certificats SSL,\n  redirections 301, HSTS, mixed content, impact SEO, monitoring...]\u003C/p>\n\u003C/article>\n\n\u003C!-- ✅ Structure optimisée pour le chunking RAG -->\n\u003Carticle>\n  \u003Ch1>Guide complet de la migration HTTPS\u003C/h1>\n\n  \u003Csection>\n    \u003Ch2>Choisir et installer le certificat SSL\u003C/h2>\n    \u003Cp>Le choix du certificat dépend de votre architecture.\n    Un certificat wildcard (*.example.fr) couvre tous les sous-domaines...\u003C/p>\n    \u003Ch3>Certificat DV vs OV vs EV : quel impact réel ?\u003C/h3>\n    \u003Cp>Pour le SEO, aucun. Google ne distingue pas les types\n    de certificats. Le choix est purement une question de confiance\n    utilisateur dans la barre d'adresse...\u003C/p>\n  \u003C/section>\n\n  \u003Csection>\n    \u003Ch2>Configurer les redirections 301\u003C/h2>\n    \u003Cp>Chaque URL HTTP doit rediriger vers son équivalent HTTPS\n    avec un code 301 permanent...\u003C/p>\n    \u003Cpre>\u003Ccode>\n    # Nginx — Redirection HTTP vers HTTPS\n    server {\n        listen 80;\n        server_name example.fr www.example.fr;\n        return 301 https://$server_name$request_uri;\n    }\n    \u003C/code>\u003C/pre>\n  \u003C/section>\n\n  \u003Csection>\n    \u003Ch2>Activer HSTS et gérer le mixed content\u003C/h2>\n    \u003Cp>Le header Strict-Transport-Security empêche les navigateurs\n    de revenir en HTTP après la première visite...\u003C/p>\n  \u003C/section>\n\u003C/article>\n```\n\nLa deuxième structure produit des chunks thématiquement cohérents. Quand un utilisateur demande à Perplexity \"comment configurer les redirections 301 pour une migration HTTPS\", le chunk de la section 2 aura un embedding beaucoup plus proche de la requête que le même contenu noyé dans un bloc monolithique.\n\n### Les balises sémantiques HTML5 comme signaux de découpage\n\nLes `\u003Csection>`, `\u003Carticle>`, `\u003Caside>`, `\u003Cnav>` ne sont pas décoratifs. Les extracteurs de contenu des systèmes RAG les utilisent comme délimiteurs. Un `\u003Caside>` sera probablement exclu du contenu principal. Un `\u003Cnav>` sera ignoré. Un `\u003Csection>` dans un `\u003Carticle>` sera traité comme une unité logique.\n\nC'est un aspect que les [signaux de visibilité IA](/blog/4-signals-that-now-define-visibility-in-ai-search) incluent de plus en plus : la clarté structurelle de votre HTML est un facteur de sélection en amont du modèle de langage lui-même.\n\n## Étape 4 : le contenu est extrait mais jamais sélectionné — le problème d'autorité topicale\n\nVotre contenu est crawlé, rendu correctement, bien structuré, et pourtant jamais cité. Le problème se situe alors à l'étape 5 du pipeline : le retrieval. Le système RAG récupère plusieurs chunks candidats pour une requête, puis le LLM sélectionne ceux qu'il va utiliser et citer.\n\n### Comment fonctionne la sélection des sources dans un système RAG\n\nUn système RAG typique (celui de Perplexity est le mieux documenté) fonctionne ainsi :\n\n1. La requête utilisateur est vectorisée\n2. Les N chunks les plus proches dans l'espace d'embedding sont récupérés (typiquement 20-50)\n3. Un re-ranker évalue la pertinence fine de chaque chunk\n4. Le LLM génère sa réponse en utilisant les top chunks comme contexte\n5. Le LLM décide quelles sources citer (et peut ignorer un chunk qu'il a pourtant utilisé)\n\nL'étape 3 (re-ranking) et l'étape 5 (décision de citation) sont celles où l'autorité perçue de la source intervient. Le re-ranker n'utilise pas le PageRank, mais il utilise des signaux corrélés :\n\n- **La cohérence thématique du domaine** : un site qui publie 200 articles sur la cybersécurité sera préféré à un site généraliste qui a 1 article sur le sujet\n- **La fraîcheur du contenu** : un article daté de 2024 sera préféré à un article non daté\n- **La densité informationnelle du chunk** : un paragraphe qui contient des données factuelles, des chiffres, des noms propres sera préféré à un paragraphe vague\n\nC'est exactement ce qu'analyse en profondeur l'article sur [pourquoi le bon contenu ne suffit plus](/blog/why-great-content-is-no-longer-enough-what-beats-it-in-ai-search-via-sejournal-taylordanrw) : les LLM ne cherchent pas le \"meilleur contenu\" au sens éditorial, ils cherchent la source la plus fiable pour une affirmation spécifique.\n\n### Le diagnostic pratique\n\nUtilisez Perplexity en mode \"Focus: Academic\" ou \"Focus: All\" sur vos requêtes cibles. Examinez les sources citées. Si vos concurrents sont cités et pas vous, analysez la différence structurelle :\n\n- Leurs pages contiennent-elles des données originales (études, benchmarks, chiffres propriétaires) ?\n- Leurs chunks sont-ils auto-suffisants (compréhensibles hors contexte) ?\n- Leur domaine a-t-il une couverture thématique plus profonde sur le sujet ?\n\nLa [question de la réputation](/blog/why-geo-is-a-reputation-problem) est centrale ici : les LLM héritent des biais de leurs données d'entraînement. Si votre marque n'est pas associée à votre domaine d'expertise dans le corpus d'entraînement, le re-ranker vous pénalise implicitement. La manière dont les [modèles IA comprennent votre marque](/blog/how-ai-models-understand-your-brand) détermine votre plafond de visibilité.\n\n## Étape 5 : le diagnostic technique complet — checklist actionable\n\nVoici le processus de diagnostic complet, étape par étape, applicable à un site de 5 000+ pages.\n\n### Phase 1 : Audit de crawlabilité IA (semaine 1)\n\n```typescript\n// Script Node.js pour auditer la crawlabilité IA d'un sitemap\nimport { parse } from 'node-html-parser';\n\ninterface CrawlResult {\n  url: string;\n  status: number;\n  contentLength: number;\n  wordCount: number;\n  hasH1: boolean;\n  headingStructure: string[];\n  hasStructuredData: boolean;\n  responseTime: number;\n}\n\nasync function auditUrl(url: string): Promise\u003CCrawlResult> {\n  const start = Date.now();\n  const response = await fetch(url, {\n    headers: {\n      'User-Agent': 'GPTBot/1.0 (+https://openai.com/gptbot)',\n    },\n    signal: AbortSignal.timeout(5000),\n  });\n\n  const html = await response.text();\n  const responseTime = Date.now() - start;\n  const root = parse(html);\n\n  // Extraire le texte visible (hors script/style)\n  const scripts = root.querySelectorAll('script, style, noscript');\n  scripts.forEach(s => s.remove());\n  const textContent = root.textContent.replace(/\\s+/g, ' ').trim();\n  const wordCount = textContent.split(' ').filter(w => w.length > 2).length;\n\n  // Analyser la structure des headings\n  const headings = root.querySelectorAll('h1, h2, h3, h4, h5, h6');\n  const headingStructure = headings.map(\n    h => `${h.tagName}: ${h.textContent.trim().substring(0, 60)}`\n  );\n\n  // Vérifier la présence de structured data\n  const jsonLd = root.querySelectorAll('script[type=\"application/ld+json\"]');\n\n  return {\n    url,\n    status: response.status,\n    contentLength: html.length,\n    wordCount,\n    hasH1: root.querySelector('h1') !== null,\n    headingStructure,\n    hasStructuredData: jsonLd.length > 0,\n    responseTime,\n  };\n}\n\nasync function auditSitemap(sitemapUrl: string) {\n  const response = await fetch(sitemapUrl);\n  const xml = await response.text();\n  const root = parse(xml);\n  const urls = root.querySelectorAll('loc').map(l => l.textContent);\n\n  console.log(`Auditing ${urls.length} URLs...`);\n\n  const results: CrawlResult[] = [];\n  for (const url of urls.slice(0, 500)) { // Limiter pour le test\n    try {\n      const result = await auditUrl(url);\n      results.push(result);\n\n      // Alertes immédiates\n      if (result.wordCount \u003C 100) {\n        console.warn(`⚠️  LOW CONTENT: ${url} (${result.wordCount} words)`);\n      }\n      if (result.responseTime > 2000) {\n        console.warn(`⚠️  SLOW: ${url} (${result.responseTime}ms)`);\n      }\n      if (!result.hasH1) {\n        console.warn(`⚠️  NO H1: ${url}`);\n      }\n    } catch (e) {\n      console.error(`❌ FAILED: ${url} — ${e.message}`);\n    }\n    // Rate limiting\n    await new Promise(r => setTimeout(r, 1000));\n  }\n\n  // Résumé\n  const avgWords = results.reduce((a, r) => a + r.wordCount, 0) / results.length;\n  const lowContent = results.filter(r => r.wordCount \u003C 100).length;\n  const slow = results.filter(r => r.responseTime > 2000).length;\n  const noStructuredData = results.filter(r => !r.hasStructuredData).length;\n\n  console.log(`\\n--- RÉSUMÉ ---`);\n  console.log(`Pages auditées: ${results.length}`);\n  console.log(`Mots moyens (sans JS): ${Math.round(avgWords)}`);\n  console.log(`Pages \u003C 100 mots (contenu JS-dépendant probable): ${lowContent}`);\n  console.log(`Pages > 2s de réponse: ${slow}`);\n  console.log(`Pages sans structured data: ${noStructuredData}`);\n}\n\nauditSitemap('https://votre-site.fr/sitemap.xml');\n```\n\nCe script simule ce que GPTBot voit réellement. Les pages avec moins de 100 mots en HTML brut sont quasi certainement des pages dont le contenu dépend du JavaScript côté client — elles sont invisibles pour les bots IA.\n\n### Phase 2 : Analyse de la couverture topicale (semaine 2)\n\nUtilisez Screaming Frog avec l'extraction custom pour mapper votre couverture thématique :\n\n1. Crawlez votre site avec extraction des H1, H2, et du premier paragraphe de chaque page\n2. Exportez en CSV\n3. Classez par cluster thématique (manuellement ou via embeddings)\n4. Identifiez les trous : quels sous-sujets de votre domaine ne sont couverts par aucune page ?\n\nLes LLM préfèrent les sources qui démontrent une couverture exhaustive d'un sujet. Si vous avez 3 articles sur \"migration cloud\" mais aucun sur \"migration cloud sécurité données sensibles\", \"migration cloud coûts cachés\", ou \"migration cloud réversibilité\", votre autorité topicale est perçue comme superficielle.\n\nC'est la logique décrite dans l'analyse sur [comment produire plus de contenu ne suffit plus](/blog/why-more-content-is-no-longer-a-reliable-way-to-grow-seo) : la profondeur prime sur le volume.\n\n### Phase 3 : Test de citation (semaine 3-4)\n\nIl n'existe pas encore d'API publique pour mesurer la visibilité dans les réponses LLM à grande échelle. La méthode manuelle reste la plus fiable :\n\n1. Constituez un panel de 50-100 requêtes représentatives de votre domaine\n2. Testez chaque requête dans ChatGPT (mode recherche web), Perplexity, et Gemini\n3. Notez si votre site est cité, à quelle position dans les sources, et quel contenu est extrait\n4. Comparez avec vos concurrents directs\n\nDes outils comme [ceux analysés par DebugBear](/blog/ai-search-success-how-to-benchmark-website-performance-in-your-industry-via-sejournal-debugbear) commencent à automatiser ce processus. Bing Webmaster Tools teste également un [rapport de citations IA](/blog/bing-previews-ai-citation-share-for-webmaster-tools-via-sejournal-mattgsouthern) qui devrait faciliter ce suivi.\n\n## Les structured data : pas un facteur de ranking, mais un facteur de compréhension\n\nLes données structurées (JSON-LD) ne sont pas directement utilisées par les systèmes RAG pour le ranking. Mais elles influencent la compréhension du contenu lors de l'extraction. Un `Article` avec `author`, `datePublished`, `dateModified` et `about` donne au système RAG des métadonnées exploitables pour le re-ranking.\n\n```html\n\u003Cscript type=\"application/ld+json\">\n{\n  \"@context\": \"https://schema.org\",\n  \"@type\": \"TechArticle\",\n  \"headline\": \"Migration HTTPS : guide technique pour sites e-commerce\",\n  \"author\": {\n    \"@type\": \"Person\",\n    \"name\": \"Marie Laurent\",\n    \"jobTitle\": \"Lead Security Engineer\",\n    \"url\": \"https://votre-site.fr/equipe/marie-laurent\"\n  },\n  \"datePublished\": \"2026-04-15\",\n  \"dateModified\": \"2026-05-01\",\n  \"about\": {\n    \"@type\": \"Thing\",\n    \"name\": \"HTTPS Migration\",\n    \"sameAs\": \"https://en.wikipedia.org/wiki/HTTPS\"\n  },\n  \"isPartOf\": {\n    \"@type\": \"WebSite\",\n    \"name\": \"VotreSite Tech Blog\",\n    \"url\": \"https://votre-site.fr\"\n  },\n  \"speakable\": {\n    \"@type\": \"SpeakableSpecification\",\n    \"cssSelector\": [\"article h1\", \"article > section:first-of-type\"]\n  }\n}\n\u003C/script>\n```\n\nLe champ `speakable` est particulièrement intéressant : bien que conçu initialement pour Google Assistant, il indique explicitement quelles parties de la page sont les plus \"citables\". C'est un signal que les systèmes RAG pourraient exploiter — et que Perplexity semble déjà prendre en compte selon les observations de plusieurs praticiens. Consultez la [documentation Google sur les Speakable](https://developers.google.com/search/docs/appearance/structured-data/speakable) pour les détails d'implémentation.\n\nLe point soulevé par l'article de SEJ est que votre site doit fonctionner comme une [source, pas un mégaphone](/blog/your-website-is-a-source-not-a-megaphone-via-sejournal-slobodanmanic). Les données structurées transforment votre page d'un document HTML en une entité compréhensible par les machines.\n\n## Les faux positifs du diagnostic : ce qui ne cause PAS le problème\n\nIl serait malhonnête de ne pas mentionner les fausses pistes courantes.\n\n### Le Domain Authority n'est pas le facteur principal\n\nDes expériences ont montré qu'une [fausse marque peut gagner en AI search](/blog/can-a-fake-brand-win-in-ai-search-new-experiment-says-yes). L'autorité de domaine au sens Moz/Ahrefs n'est pas directement utilisée par les systèmes RAG. Ce qui compte, c'est la pertinence et la densité informationnelle du chunk, combinées à la cohérence thématique du domaine.\n\n### La fréquence de publication n'est pas un levier direct\n\nPublier un article par jour ne vous rendra pas plus visible dans ChatGPT si chaque article manque de profondeur technique. Les LLM évaluent la qualité à l'échelle du chunk, pas à l'échelle du domaine. Un seul article technique exhaustif sur un sujet précis vaut plus que 20 articles superficiels.\n\n### Les meta descriptions ne sont pas utilisées par les LLM\n\nLes systèmes RAG extraient le contenu `\u003Cbody>`, pas les `\u003Cmeta>`. Vos meta descriptions n'ont aucun impact sur votre visibilité IA. Concentrez votre effort sur le contenu visible, les headings, et la structure sémantique.\n\nCela dit, comme l'analyse des [retombées CTR des AI Overviews](/blog/ai-overview-ctr-fell-61-but-clicks-didn-t-collapse-via-sejournal-mattgsouthern) l'a montré, les meta descriptions restent essentielles pour les résultats classiques qui coexistent avec les réponses IA.\n\n## Le monitoring continu comme filet de sécurité\n\nLe diagnostic ponctuel ne suffit pas. Les régressions SSR, les changements de structure HTML après un déploiement, les blocages robots.txt accidentels — tout cela arrive en continu sur un site actif.\n\nLe scénario classique : un développeur ajoute un lazy-loading agressif sur les images et le contenu below-the-fold. L'impact sur Googlebot est nul (il attend le rendu complet). L'impact sur GPTBot est immédiat — tout le contenu sous le premier écran disparaît du HTML initial. Le site perd 40% de son contenu visible pour les bots IA, et personne ne s'en aperçoit pendant 3 mois.\n\nUn monitoring technique automatisé qui vérifie quotidiennement le contenu visible dans le HTML brut (sans rendu JS) permet de détecter ce type de régression en quelques heures. C'est le type de surveillance que Seogard automatise : comparer le HTML rendu côté serveur avec le contenu attendu, et alerter immédiatement quand un delta significatif apparaît.\n\n---\n\nLa visibilité dans les moteurs de recherche IA n'est pas un nouveau canal marketing à \"optimiser\" — c'est un ensemble de contraintes techniques à satisfaire. Diagnostiquez chaque étape du pipeline (crawl, extraction, chunking, embedding, retrieval), identifiez votre point de rupture spécifique, et corrigez chirurgicalement. Le contenu qui est [compris comme de la donnée structurée](/blog/ai-sees-your-brand-as-math-not-messaging) par les LLM, pas comme de la","https://seogard.io/blog/why-ai-search-skips-your-content-and-how-to-diagnose-where-it-s-failing-via-sejournal-jeffrey-coyle","Actualités SEO","2026-05-05T06:02:59.262Z","2026-05-05","Votre contenu est crawlé mais jamais cité par ChatGPT ou Perplexity ? Diagnostic technique des points de rupture entre indexation classique et visibilité IA.","\u003Cp>Un site e-commerce de 22 000 pages produit. Googlebot crawle 8 000 pages par jour. GPTBot en visite 1 200. Pourtant, sur les 150 requêtes commerciales testées dans ChatGPT et Perplexity, le site n'est cité que 3 fois. Le contenu existe, il est crawlé, mais il est systématiquement ignoré par les moteurs de recherche IA. Le problème ne se situe pas là où vous pensez.\u003C/p>\n\u003Cp>L'article récemment publié par Search Engine Journal, sponsorisé par Siteimprove, pose la bonne question : pourquoi un contenu indexé par Google peut-il être invisible pour les LLM ? Mais la réponse mérite d'aller bien au-delà du diagnostic de surface. Il y a un pipeline technique complet entre le crawl d'un bot IA et la citation effective dans une réponse générée, et chaque étape est un point de rupture potentiel.\u003C/p>\n\u003Ch2>Le pipeline de visibilité IA : 5 étapes, 5 points de rupture\u003C/h2>\n\u003Cp>La visibilité dans les moteurs de recherche IA (ChatGPT Search, Perplexity, Gemini, Copilot) repose sur un pipeline fondamentalement différent de celui de Google Search. Voici les étapes, dans l'ordre :\u003C/p>\n\u003Col>\n\u003Cli>\u003Cstrong>Crawl\u003C/strong> — Le bot IA (GPTBot, PerplexityBot, ClaudeBot) accède à la page\u003C/li>\n\u003Cli>\u003Cstrong>Extraction\u003C/strong> — Le contenu textuel est extrait du HTML rendu\u003C/li>\n\u003Cli>\u003Cstrong>Chunking\u003C/strong> — Le contenu est découpé en segments sémantiques\u003C/li>\n\u003Cli>\u003Cstrong>Embedding\u003C/strong> — Chaque chunk est vectorisé dans un espace sémantique\u003C/li>\n\u003Cli>\u003Cstrong>Retrieval + Citation\u003C/strong> — Lors d'une requête utilisateur, le système RAG (Retrieval-Augmented Generation) sélectionne les chunks les plus pertinents et décide de les citer ou non\u003C/li>\n\u003C/ol>\n\u003Cp>Un contenu peut passer l'étape 1 (le bot crawle la page avec succès) et échouer à l'étape 3 (le contenu est mal découpé car la structure HTML est ambiguë) ou à l'étape 5 (le chunk est récupéré mais jugé redondant avec une source plus autoritaire).\u003C/p>\n\u003Cp>Le diagnostic technique consiste à identifier précisément à quelle étape votre contenu décroche.\u003C/p>\n\u003Ch2>Étape 1 : vérifier que les bots IA crawlent réellement vos pages\u003C/h2>\n\u003Ch3>Analyser les logs serveur\u003C/h3>\n\u003Cp>La première vérification est triviale mais souvent négligée. Vous devez confirmer que GPTBot, PerplexityBot et les autres accèdent effectivement à vos pages stratégiques — pas seulement à votre homepage et vos pages \"À propos\".\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 les hits GPTBot des 30 derniers jours, groupés par URL\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"GPTBot\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> /var/log/nginx/access.log\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:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  |\u003C/span>\u003Cspan style=\"color:#B392F0\"> uniq\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\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:#79B8FF\"> -rn\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  |\u003C/span>\u003Cspan style=\"color:#B392F0\"> head\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -50\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Même chose pour PerplexityBot\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"PerplexityBot\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> /var/log/nginx/access.log\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, $9}'\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:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  |\u003C/span>\u003Cspan style=\"color:#B392F0\"> uniq\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\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:#79B8FF\"> -rn\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  |\u003C/span>\u003Cspan style=\"color:#B392F0\"> head\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -50\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Ce que vous cherchez : la distribution des pages crawlées. Si GPTBot visite principalement vos pages de catégories et ignore vos pages produits ou vos articles de fond, le problème est un problème de découverte. Les bots IA suivent les liens de la même manière que Googlebot — votre maillage interne dicte ce qu'ils trouvent.\u003C/p>\n\u003Ch3>Le piège du robots.txt mal configuré\u003C/h3>\n\u003Cp>Une analyse de \u003Ca href=\"/blog/68-million-ai-crawler-visits-show-what-drives-ai-search-visibility-via-sejournal-martinibuster\">68 millions de visites de crawlers IA\u003C/a> a montré que la distribution de crawl varie massivement d'un bot à l'autre. Certains sites bloquent GPTBot par précaution sans réaliser qu'ils se coupent de la visibilité ChatGPT Search.\u003C/p>\n\u003Cp>Vérifiez votre \u003Ccode>robots.txt\u003C/code> avec précision. Google a d'ailleurs récemment étendu sa documentation sur les \u003Ca href=\"/blog/google-may-expand-unsupported-robots-txt-rules-list-via-sejournal-mattgsouthern\">règles robots.txt non supportées\u003C/a>, ce qui complexifie encore la gestion multi-bots.\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># robots.txt — Configuration recommandée pour les bots IA\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Autoriser le crawl tout en bloquant les sections non pertinentes\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">User-agent: \u003C/span>\u003Cspan style=\"color:#F97583\">GPTBot\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Allow: /blog/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Allow: /guides/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Allow: /produits/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Disallow: /compte/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Disallow: /panier/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Disallow: /api/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Crawl-delay: \u003C/span>\u003Cspan style=\"color:#F97583\">2\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">User-agent: \u003C/span>\u003Cspan style=\"color:#F97583\">PerplexityBot\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Allow: /blog/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Allow: /guides/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Allow: /produits/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Disallow: /compte/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Disallow: /panier/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Crawl-delay: \u003C/span>\u003Cspan style=\"color:#F97583\">2\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">User-agent: \u003C/span>\u003Cspan style=\"color:#F97583\">ClaudeBot\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Allow: /blog/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Allow: /guides/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Allow: /produits/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Disallow: /compte/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Disallow: /panier/\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Crawl-delay: \u003C/span>\u003Cspan style=\"color:#F97583\">5\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">User-agent: \u003C/span>\u003Cspan style=\"color:#F97583\">Bytespider\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">Disallow: /\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Notez la distinction : autoriser les bots des systèmes que vous voulez cibler (GPTBot pour ChatGPT, PerplexityBot pour Perplexity), bloquer ceux qui n'apportent rien (Bytespider de ByteDance consomme du bandwidth sans retour mesurable pour la plupart des sites occidentaux). La hausse récente de \u003Ca href=\"/blog/openai-crawl-activity-tripled-since-gpt-5-data-shows-via-sejournal-mattgsouthern\">l'activité de crawl d'OpenAI\u003C/a> rend cette configuration d'autant plus critique.\u003C/p>\n\u003Ch3>Codes de réponse et temps de réponse\u003C/h3>\n\u003Cp>Les bots IA sont moins tolérants que Googlebot sur les temps de réponse. GPTBot abandonne une requête plus rapidement. Si votre serveur met 3 secondes à répondre (acceptable pour Googlebot), GPTBot peut timeout et passer à la suite.\u003C/p>\n\u003Cp>Dans vos logs, filtrez les réponses 5xx et les temps de réponse supérieurs à 2 secondes pour les user-agents IA. Un taux d'erreur de 15% sur GPTBot signifie que 15% de vos pages ne sont jamais ingérées.\u003C/p>\n\u003Ch2>Étape 2 : ce que le bot IA voit vs ce que vous pensez qu'il voit\u003C/h2>\n\u003Cp>C'est le point de rupture le plus sous-estimé. Les bots IA ne rendent pas le JavaScript de la même manière que Googlebot (qui utilise un moteur Chromium complet). GPTBot et PerplexityBot se comportent davantage comme des crawlers headless basiques — ils récupèrent le HTML initial et extraient le texte.\u003C/p>\n\u003Ch3>Tester le rendu sans JavaScript\u003C/h3>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Comparer le contenu visible avec et sans JS\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># 1. Récupérer le HTML brut (ce que GPTBot voit probablement)\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\"> \"GPTBot/1.0\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> https://votre-site.fr/guide-technique\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  |\u003C/span>\u003Cspan style=\"color:#B392F0\"> python3\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">import sys\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">from html.parser import HTMLParser\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">class TextExtractor(HTMLParser):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    def __init__(self):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        super().__init__()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        self.text = []\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        self.skip = False\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    def handle_starttag(self, tag, attrs):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        if tag in ('script', 'style', 'noscript'):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            self.skip = True\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    def handle_endtag(self, tag):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        if tag in ('script', 'style', 'noscript'):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            self.skip = False\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    def handle_data(self, data):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        if not self.skip and data.strip():\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            self.text.append(data.strip())\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">e = TextExtractor()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">e.feed(sys.stdin.read())\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">print('\\n'.join(e.text))\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#F97583\"> >\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> content_nojs.txt\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># 2. Récupérer le contenu rendu via Puppeteer/Playwright\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">npx\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> playwright\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> screenshot\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> https://votre-site.fr/guide-technique\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  --wait-until\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> networkidle\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># 3. Comparer les deux fichiers\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">wc\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -w\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> content_nojs.txt\u003C/span>\u003Cspan style=\"color:#6A737D\">  # Si &#x3C; 200 mots, le contenu dépend du JS\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Si la version sans JavaScript ne contient que le header, le footer et un \u003Ccode>&#x3C;div id=\"app\">&#x3C;/div>\u003C/code> vide, votre contenu est invisible pour les bots IA. Ce scénario est extrêmement fréquent sur les SPA React/Vue sans SSR.\u003C/p>\n\u003Ch3>Le cas concret : migration SPA vers SSR\u003C/h3>\n\u003Cp>Prenez un média tech de 8 000 articles construit sur une SPA React. Après audit :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>Googlebot\u003C/strong> : indexe 7 200 pages (rendu JS côté Google)\u003C/li>\n\u003Cli>\u003Cstrong>GPTBot\u003C/strong> : crawle 3 500 pages, mais n'extrait du contenu substantiel que sur 400 (les pages dont le contenu est dans le HTML initial — pages statiques legacy)\u003C/li>\n\u003Cli>\u003Cstrong>Résultat Perplexity\u003C/strong> : le site est cité sur 2 requêtes parmi 80 testées\u003C/li>\n\u003C/ul>\n\u003Cp>Après migration vers Next.js avec SSR (Server-Side Rendering), le contenu est présent dans le HTML initial. En 6 semaines :\u003C/p>\n\u003Cul>\n\u003Cli>GPTBot extrait du contenu sur 3 200 pages\u003C/li>\n\u003Cli>Les citations Perplexity passent de 2 à 17 sur le même panel de requêtes\u003C/li>\n\u003C/ul>\n\u003Cp>Le SSR n'est pas une option pour la visibilité IA — c'est un prérequis. Et les \u003Ca href=\"/blog/why-tracking-parameters-in-internal-links-hurt-your-seo-and-how-to-fix-them\">régressions SSR silencieuses\u003C/a> (un déploiement qui casse le rendu serveur sans que personne ne s'en aperçoive) sont le type exact de problème qu'un monitoring continu comme Seogard détecte avant que l'impact ne se matérialise.\u003C/p>\n\u003Ch2>Étape 3 : la structure sémantique détermine le chunking\u003C/h2>\n\u003Cp>Les systèmes RAG ne lisent pas votre page comme un humain. Ils la découpent en chunks — des segments de 200 à 500 tokens en général — puis vectorisent chaque chunk indépendamment. La qualité de ce découpage dépend directement de votre structure HTML.\u003C/p>\n\u003Ch3>Pourquoi la hiérarchie H1-H6 compte (vraiment, cette fois)\u003C/h3>\n\u003Cp>En SEO classique, la hiérarchie des headings est un signal parmi d'autres. Pour les systèmes RAG, c'est le squelette du chunking. Un H2 suivi de 3 paragraphes = un chunk cohérent. Un mur de texte de 2 000 mots sans aucun heading = un chunk qui mélange 4 sujets différents et dont l'embedding vectoriel ne matche aucune requête précise.\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">&#x3C;!-- ❌ Structure anti-chunking : tout le contenu dans un seul bloc -->\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">article\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">h1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Guide complet de la migration HTTPS&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">h1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>La migration HTTPS implique le changement de protocole...\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  [2000 mots sans aucun sous-titre, mélangeant certificats SSL,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  redirections 301, HSTS, mixed content, impact SEO, monitoring...]&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">article\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">&#x3C;!-- ✅ Structure optimisée pour le chunking RAG -->\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">article\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">h1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Guide complet de la migration HTTPS&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">h1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">section\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">h2\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Choisir et installer le certificat SSL&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">h2\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Le choix du certificat dépend de votre architecture.\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    Un certificat wildcard (*.example.fr) couvre tous les sous-domaines...&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">h3\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Certificat DV vs OV vs EV : quel impact réel ?&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">h3\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Pour le SEO, aucun. Google ne distingue pas les types\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    de certificats. Le choix est purement une question de confiance\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    utilisateur dans la barre d'adresse...&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">section\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">section\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">h2\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Configurer les redirections 301&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">h2\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Chaque URL HTTP doit rediriger vers son équivalent HTTPS\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    avec un code 301 permanent...&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">pre\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">code\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    # Nginx — Redirection HTTP vers HTTPS\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    server {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        listen 80;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        server_name example.fr www.example.fr;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        return 301 https://$server_name$request_uri;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">code\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">pre\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">section\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">section\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">h2\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Activer HSTS et gérer le mixed content&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">h2\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>Le header Strict-Transport-Security empêche les navigateurs\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    de revenir en HTTP après la première visite...&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">p\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  &#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">section\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">article\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>La deuxième structure produit des chunks thématiquement cohérents. Quand un utilisateur demande à Perplexity \"comment configurer les redirections 301 pour une migration HTTPS\", le chunk de la section 2 aura un embedding beaucoup plus proche de la requête que le même contenu noyé dans un bloc monolithique.\u003C/p>\n\u003Ch3>Les balises sémantiques HTML5 comme signaux de découpage\u003C/h3>\n\u003Cp>Les \u003Ccode>&#x3C;section>\u003C/code>, \u003Ccode>&#x3C;article>\u003C/code>, \u003Ccode>&#x3C;aside>\u003C/code>, \u003Ccode>&#x3C;nav>\u003C/code> ne sont pas décoratifs. Les extracteurs de contenu des systèmes RAG les utilisent comme délimiteurs. Un \u003Ccode>&#x3C;aside>\u003C/code> sera probablement exclu du contenu principal. Un \u003Ccode>&#x3C;nav>\u003C/code> sera ignoré. Un \u003Ccode>&#x3C;section>\u003C/code> dans un \u003Ccode>&#x3C;article>\u003C/code> sera traité comme une unité logique.\u003C/p>\n\u003Cp>C'est un aspect que les \u003Ca href=\"/blog/4-signals-that-now-define-visibility-in-ai-search\">signaux de visibilité IA\u003C/a> incluent de plus en plus : la clarté structurelle de votre HTML est un facteur de sélection en amont du modèle de langage lui-même.\u003C/p>\n\u003Ch2>Étape 4 : le contenu est extrait mais jamais sélectionné — le problème d'autorité topicale\u003C/h2>\n\u003Cp>Votre contenu est crawlé, rendu correctement, bien structuré, et pourtant jamais cité. Le problème se situe alors à l'étape 5 du pipeline : le retrieval. Le système RAG récupère plusieurs chunks candidats pour une requête, puis le LLM sélectionne ceux qu'il va utiliser et citer.\u003C/p>\n\u003Ch3>Comment fonctionne la sélection des sources dans un système RAG\u003C/h3>\n\u003Cp>Un système RAG typique (celui de Perplexity est le mieux documenté) fonctionne ainsi :\u003C/p>\n\u003Col>\n\u003Cli>La requête utilisateur est vectorisée\u003C/li>\n\u003Cli>Les N chunks les plus proches dans l'espace d'embedding sont récupérés (typiquement 20-50)\u003C/li>\n\u003Cli>Un re-ranker évalue la pertinence fine de chaque chunk\u003C/li>\n\u003Cli>Le LLM génère sa réponse en utilisant les top chunks comme contexte\u003C/li>\n\u003Cli>Le LLM décide quelles sources citer (et peut ignorer un chunk qu'il a pourtant utilisé)\u003C/li>\n\u003C/ol>\n\u003Cp>L'étape 3 (re-ranking) et l'étape 5 (décision de citation) sont celles où l'autorité perçue de la source intervient. Le re-ranker n'utilise pas le PageRank, mais il utilise des signaux corrélés :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>La cohérence thématique du domaine\u003C/strong> : un site qui publie 200 articles sur la cybersécurité sera préféré à un site généraliste qui a 1 article sur le sujet\u003C/li>\n\u003Cli>\u003Cstrong>La fraîcheur du contenu\u003C/strong> : un article daté de 2024 sera préféré à un article non daté\u003C/li>\n\u003Cli>\u003Cstrong>La densité informationnelle du chunk\u003C/strong> : un paragraphe qui contient des données factuelles, des chiffres, des noms propres sera préféré à un paragraphe vague\u003C/li>\n\u003C/ul>\n\u003Cp>C'est exactement ce qu'analyse en profondeur l'article sur \u003Ca href=\"/blog/why-great-content-is-no-longer-enough-what-beats-it-in-ai-search-via-sejournal-taylordanrw\">pourquoi le bon contenu ne suffit plus\u003C/a> : les LLM ne cherchent pas le \"meilleur contenu\" au sens éditorial, ils cherchent la source la plus fiable pour une affirmation spécifique.\u003C/p>\n\u003Ch3>Le diagnostic pratique\u003C/h3>\n\u003Cp>Utilisez Perplexity en mode \"Focus: Academic\" ou \"Focus: All\" sur vos requêtes cibles. Examinez les sources citées. Si vos concurrents sont cités et pas vous, analysez la différence structurelle :\u003C/p>\n\u003Cul>\n\u003Cli>Leurs pages contiennent-elles des données originales (études, benchmarks, chiffres propriétaires) ?\u003C/li>\n\u003Cli>Leurs chunks sont-ils auto-suffisants (compréhensibles hors contexte) ?\u003C/li>\n\u003Cli>Leur domaine a-t-il une couverture thématique plus profonde sur le sujet ?\u003C/li>\n\u003C/ul>\n\u003Cp>La \u003Ca href=\"/blog/why-geo-is-a-reputation-problem\">question de la réputation\u003C/a> est centrale ici : les LLM héritent des biais de leurs données d'entraînement. Si votre marque n'est pas associée à votre domaine d'expertise dans le corpus d'entraînement, le re-ranker vous pénalise implicitement. La manière dont les \u003Ca href=\"/blog/how-ai-models-understand-your-brand\">modèles IA comprennent votre marque\u003C/a> détermine votre plafond de visibilité.\u003C/p>\n\u003Ch2>Étape 5 : le diagnostic technique complet — checklist actionable\u003C/h2>\n\u003Cp>Voici le processus de diagnostic complet, étape par étape, applicable à un site de 5 000+ pages.\u003C/p>\n\u003Ch3>Phase 1 : Audit de crawlabilité IA (semaine 1)\u003C/h3>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// Script Node.js pour auditer la crawlabilité IA d'un sitemap\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { parse } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'node-html-parser'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">interface\u003C/span>\u003Cspan style=\"color:#B392F0\"> CrawlResult\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">  url\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:#FFAB70\">  status\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> number\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">  contentLength\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> number\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">  wordCount\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> number\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">  hasH1\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> boolean\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">  headingStructure\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:#FFAB70\">  hasStructuredData\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> boolean\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">  responseTime\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> number\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\">async\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> auditUrl\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">url\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:#B392F0\"> Promise\u003C/span>\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#B392F0\">CrawlResult\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\"> start\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> 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:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> response\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> fetch\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(url, {\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\">      'User-Agent'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'GPTBot/1.0 (+https://openai.com/gptbot)'\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\">    signal: AbortSignal.\u003C/span>\u003Cspan style=\"color:#B392F0\">timeout\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#79B8FF\">5000\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\"> html\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> response.\u003C/span>\u003Cspan style=\"color:#B392F0\">text\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\"> responseTime\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> Date.\u003C/span>\u003Cspan style=\"color:#B392F0\">now\u003C/span>\u003Cspan style=\"color:#E1E4E8\">() \u003C/span>\u003Cspan style=\"color:#F97583\">-\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> start;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> root\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#B392F0\"> parse\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(html);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  // Extraire le texte visible (hors script/style)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> scripts\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> root.\u003C/span>\u003Cspan style=\"color:#B392F0\">querySelectorAll\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'script, style, noscript'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  scripts.\u003C/span>\u003Cspan style=\"color:#B392F0\">forEach\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">s\u003C/span>\u003Cspan style=\"color:#F97583\"> =>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> s.\u003C/span>\u003Cspan style=\"color:#B392F0\">remove\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\"> textContent\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> root.textContent.\u003C/span>\u003Cspan style=\"color:#B392F0\">replace\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\s\u003C/span>\u003Cspan style=\"color:#F97583\">+\u003C/span>\u003Cspan style=\"color:#9ECBFF\">/\u003C/span>\u003Cspan style=\"color:#F97583\">g\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">' '\u003C/span>\u003Cspan style=\"color:#E1E4E8\">).\u003C/span>\u003Cspan style=\"color:#B392F0\">trim\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\"> wordCount\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> textContent.\u003C/span>\u003Cspan style=\"color:#B392F0\">split\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">' '\u003C/span>\u003Cspan style=\"color:#E1E4E8\">).\u003C/span>\u003Cspan style=\"color:#B392F0\">filter\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">w\u003C/span>\u003Cspan style=\"color:#F97583\"> =>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> w.\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\u003C/span>\u003Cspan style=\"color:#F97583\"> >\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 2\u003C/span>\u003Cspan style=\"color:#E1E4E8\">).\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  // Analyser la structure des headings\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> headings\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> root.\u003C/span>\u003Cspan style=\"color:#B392F0\">querySelectorAll\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'h1, h2, h3, h4, h5, h6'\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\"> headingStructure\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> headings.\u003C/span>\u003Cspan style=\"color:#B392F0\">map\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">    h\u003C/span>\u003Cspan style=\"color:#F97583\"> =>\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> `${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">h\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">tagName\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}: ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">h\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">textContent\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">trim\u003C/span>\u003Cspan style=\"color:#9ECBFF\">().\u003C/span>\u003Cspan style=\"color:#B392F0\">substring\u003C/span>\u003Cspan style=\"color:#9ECBFF\">(\u003C/span>\u003Cspan style=\"color:#79B8FF\">0\u003C/span>\u003Cspan style=\"color:#9ECBFF\">, \u003C/span>\u003Cspan style=\"color:#79B8FF\">60\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\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  // Vérifier la présence de structured data\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> jsonLd\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> root.\u003C/span>\u003Cspan style=\"color:#B392F0\">querySelectorAll\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'script[type=\"application/ld+json\"]'\u003C/span>\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\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    url,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    status: response.status,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    contentLength: html.\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    wordCount,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    hasH1: root.\u003C/span>\u003Cspan style=\"color:#B392F0\">querySelector\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'h1'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">!==\u003C/span>\u003Cspan style=\"color:#79B8FF\"> null\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    headingStructure,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    hasStructuredData: jsonLd.\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\u003C/span>\u003Cspan style=\"color:#F97583\"> >\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 0\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    responseTime,\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\">async\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> auditSitemap\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">sitemapUrl\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\"> response\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> fetch\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(sitemapUrl);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> xml\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> response.\u003C/span>\u003Cspan style=\"color:#B392F0\">text\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\"> root\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#B392F0\"> parse\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(xml);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> urls\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> root.\u003C/span>\u003Cspan style=\"color:#B392F0\">querySelectorAll\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'loc'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">).\u003C/span>\u003Cspan style=\"color:#B392F0\">map\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">l\u003C/span>\u003Cspan style=\"color:#F97583\"> =>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> l.textContent);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  console.\u003C/span>\u003Cspan style=\"color:#B392F0\">log\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`Auditing ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">urls\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\u003C/span>\u003Cspan style=\"color:#9ECBFF\">} URLs...`\u003C/span>\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\"> results\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#B392F0\"> CrawlResult\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\">  for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003Cspan style=\"color:#F97583\">const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> url\u003C/span>\u003Cspan style=\"color:#F97583\"> of\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> urls.\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\">500\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)) { \u003C/span>\u003Cspan style=\"color:#6A737D\">// Limiter pour le test\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    try\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\"> result\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> auditUrl\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(url);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      results.\u003C/span>\u003Cspan style=\"color:#B392F0\">push\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(result);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">      // Alertes immédiates\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">      if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (result.wordCount \u003C/span>\u003Cspan style=\"color:#F97583\">&#x3C;\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 100\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        console.\u003C/span>\u003Cspan style=\"color:#B392F0\">warn\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`⚠️  LOW CONTENT: ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">url\u003C/span>\u003Cspan style=\"color:#9ECBFF\">} (${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">result\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">wordCount\u003C/span>\u003Cspan style=\"color:#9ECBFF\">} words)`\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\">      if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (result.responseTime \u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 2000\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        console.\u003C/span>\u003Cspan style=\"color:#B392F0\">warn\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`⚠️  SLOW: ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">url\u003C/span>\u003Cspan style=\"color:#9ECBFF\">} (${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">result\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">responseTime\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}ms)`\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\">      if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003Cspan style=\"color:#F97583\">!\u003C/span>\u003Cspan style=\"color:#E1E4E8\">result.hasH1) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        console.\u003C/span>\u003Cspan style=\"color:#B392F0\">warn\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`⚠️  NO H1: ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">url\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\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>\u003Cspan style=\"color:#F97583\">catch\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (e) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      console.\u003C/span>\u003Cspan style=\"color:#B392F0\">error\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`❌ FAILED: ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">url\u003C/span>\u003Cspan style=\"color:#9ECBFF\">} — ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">e\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#E1E4E8\">message\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\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:#6A737D\">    // Rate limiting\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    await\u003C/span>\u003Cspan style=\"color:#F97583\"> new\u003C/span>\u003Cspan style=\"color:#79B8FF\"> Promise\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">r\u003C/span>\u003Cspan style=\"color:#F97583\"> =>\u003C/span>\u003Cspan style=\"color:#B392F0\"> setTimeout\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(r, \u003C/span>\u003Cspan style=\"color:#79B8FF\">1000\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\">  // Résumé\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> avgWords\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> results.\u003C/span>\u003Cspan style=\"color:#B392F0\">reduce\u003C/span>\u003Cspan style=\"color:#E1E4E8\">((\u003C/span>\u003Cspan style=\"color:#FFAB70\">a\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#FFAB70\">r\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">=>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> a \u003C/span>\u003Cspan style=\"color:#F97583\">+\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> r.wordCount, \u003C/span>\u003Cspan style=\"color:#79B8FF\">0\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> results.\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\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\"> lowContent\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> results.\u003C/span>\u003Cspan style=\"color:#B392F0\">filter\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">r\u003C/span>\u003Cspan style=\"color:#F97583\"> =>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> r.wordCount \u003C/span>\u003Cspan style=\"color:#F97583\">&#x3C;\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 100\u003C/span>\u003Cspan style=\"color:#E1E4E8\">).\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\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\"> slow\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> results.\u003C/span>\u003Cspan style=\"color:#B392F0\">filter\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">r\u003C/span>\u003Cspan style=\"color:#F97583\"> =>\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> r.responseTime \u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 2000\u003C/span>\u003Cspan style=\"color:#E1E4E8\">).\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\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\"> noStructuredData\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> results.\u003C/span>\u003Cspan style=\"color:#B392F0\">filter\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">r\u003C/span>\u003Cspan style=\"color:#F97583\"> =>\u003C/span>\u003Cspan style=\"color:#F97583\"> !\u003C/span>\u003Cspan style=\"color:#E1E4E8\">r.hasStructuredData).\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  console.\u003C/span>\u003Cspan style=\"color:#B392F0\">log\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\n\u003C/span>\u003Cspan style=\"color:#9ECBFF\">--- RÉSUMÉ ---`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  console.\u003C/span>\u003Cspan style=\"color:#B392F0\">log\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`Pages auditées: ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">results\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  console.\u003C/span>\u003Cspan style=\"color:#B392F0\">log\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`Mots moyens (sans JS): ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">Math\u003C/span>\u003Cspan style=\"color:#9ECBFF\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">round\u003C/span>\u003Cspan style=\"color:#9ECBFF\">(\u003C/span>\u003Cspan style=\"color:#E1E4E8\">avgWords\u003C/span>\u003Cspan style=\"color:#9ECBFF\">)\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  console.\u003C/span>\u003Cspan style=\"color:#B392F0\">log\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`Pages &#x3C; 100 mots (contenu JS-dépendant probable): ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">lowContent\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  console.\u003C/span>\u003Cspan style=\"color:#B392F0\">log\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`Pages > 2s de réponse: ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">slow\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  console.\u003C/span>\u003Cspan style=\"color:#B392F0\">log\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`Pages sans structured data: ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">noStructuredData\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\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:#B392F0\">auditSitemap\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'https://votre-site.fr/sitemap.xml'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Ce script simule ce que GPTBot voit réellement. Les pages avec moins de 100 mots en HTML brut sont quasi certainement des pages dont le contenu dépend du JavaScript côté client — elles sont invisibles pour les bots IA.\u003C/p>\n\u003Ch3>Phase 2 : Analyse de la couverture topicale (semaine 2)\u003C/h3>\n\u003Cp>Utilisez Screaming Frog avec l'extraction custom pour mapper votre couverture thématique :\u003C/p>\n\u003Col>\n\u003Cli>Crawlez votre site avec extraction des H1, H2, et du premier paragraphe de chaque page\u003C/li>\n\u003Cli>Exportez en CSV\u003C/li>\n\u003Cli>Classez par cluster thématique (manuellement ou via embeddings)\u003C/li>\n\u003Cli>Identifiez les trous : quels sous-sujets de votre domaine ne sont couverts par aucune page ?\u003C/li>\n\u003C/ol>\n\u003Cp>Les LLM préfèrent les sources qui démontrent une couverture exhaustive d'un sujet. Si vous avez 3 articles sur \"migration cloud\" mais aucun sur \"migration cloud sécurité données sensibles\", \"migration cloud coûts cachés\", ou \"migration cloud réversibilité\", votre autorité topicale est perçue comme superficielle.\u003C/p>\n\u003Cp>C'est la logique décrite dans l'analyse sur \u003Ca href=\"/blog/why-more-content-is-no-longer-a-reliable-way-to-grow-seo\">comment produire plus de contenu ne suffit plus\u003C/a> : la profondeur prime sur le volume.\u003C/p>\n\u003Ch3>Phase 3 : Test de citation (semaine 3-4)\u003C/h3>\n\u003Cp>Il n'existe pas encore d'API publique pour mesurer la visibilité dans les réponses LLM à grande échelle. La méthode manuelle reste la plus fiable :\u003C/p>\n\u003Col>\n\u003Cli>Constituez un panel de 50-100 requêtes représentatives de votre domaine\u003C/li>\n\u003Cli>Testez chaque requête dans ChatGPT (mode recherche web), Perplexity, et Gemini\u003C/li>\n\u003Cli>Notez si votre site est cité, à quelle position dans les sources, et quel contenu est extrait\u003C/li>\n\u003Cli>Comparez avec vos concurrents directs\u003C/li>\n\u003C/ol>\n\u003Cp>Des outils comme \u003Ca href=\"/blog/ai-search-success-how-to-benchmark-website-performance-in-your-industry-via-sejournal-debugbear\">ceux analysés par DebugBear\u003C/a> commencent à automatiser ce processus. Bing Webmaster Tools teste également un \u003Ca href=\"/blog/bing-previews-ai-citation-share-for-webmaster-tools-via-sejournal-mattgsouthern\">rapport de citations IA\u003C/a> qui devrait faciliter ce suivi.\u003C/p>\n\u003Ch2>Les structured data : pas un facteur de ranking, mais un facteur de compréhension\u003C/h2>\n\u003Cp>Les données structurées (JSON-LD) ne sont pas directement utilisées par les systèmes RAG pour le ranking. Mais elles influencent la compréhension du contenu lors de l'extraction. Un \u003Ccode>Article\u003C/code> avec \u003Ccode>author\u003C/code>, \u003Ccode>datePublished\u003C/code>, \u003Ccode>dateModified\u003C/code> et \u003Ccode>about\u003C/code> donne au système RAG des métadonnées exploitables pour le re-ranking.\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">script\u003C/span>\u003Cspan style=\"color:#B392F0\"> type\u003C/span>\u003Cspan style=\"color:#E1E4E8\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"application/ld+json\"\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\">  \"@context\": \"https://schema.org\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \"@type\": \"TechArticle\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \"headline\": \"Migration HTTPS : guide technique pour sites e-commerce\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \"author\": {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"@type\": \"Person\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"name\": \"Marie Laurent\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"jobTitle\": \"Lead Security Engineer\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"url\": \"https://votre-site.fr/equipe/marie-laurent\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \"datePublished\": \"2026-04-15\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \"dateModified\": \"2026-05-01\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \"about\": {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"@type\": \"Thing\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"name\": \"HTTPS Migration\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"sameAs\": \"https://en.wikipedia.org/wiki/HTTPS\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \"isPartOf\": {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"@type\": \"WebSite\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"name\": \"VotreSite Tech Blog\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"url\": \"https://votre-site.fr\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \"speakable\": {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"@type\": \"SpeakableSpecification\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    \"cssSelector\": [\"article h1\", \"article > section:first-of-type\"]\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\">&#x3C;/\u003C/span>\u003Cspan style=\"color:#85E89D\">script\u003C/span>\u003Cspan style=\"color:#E1E4E8\">>\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Le champ \u003Ccode>speakable\u003C/code> est particulièrement intéressant : bien que conçu initialement pour Google Assistant, il indique explicitement quelles parties de la page sont les plus \"citables\". C'est un signal que les systèmes RAG pourraient exploiter — et que Perplexity semble déjà prendre en compte selon les observations de plusieurs praticiens. Consultez la \u003Ca href=\"https://developers.google.com/search/docs/appearance/structured-data/speakable\">documentation Google sur les Speakable\u003C/a> pour les détails d'implémentation.\u003C/p>\n\u003Cp>Le point soulevé par l'article de SEJ est que votre site doit fonctionner comme une \u003Ca href=\"/blog/your-website-is-a-source-not-a-megaphone-via-sejournal-slobodanmanic\">source, pas un mégaphone\u003C/a>. Les données structurées transforment votre page d'un document HTML en une entité compréhensible par les machines.\u003C/p>\n\u003Ch2>Les faux positifs du diagnostic : ce qui ne cause PAS le problème\u003C/h2>\n\u003Cp>Il serait malhonnête de ne pas mentionner les fausses pistes courantes.\u003C/p>\n\u003Ch3>Le Domain Authority n'est pas le facteur principal\u003C/h3>\n\u003Cp>Des expériences ont montré qu'une \u003Ca href=\"/blog/can-a-fake-brand-win-in-ai-search-new-experiment-says-yes\">fausse marque peut gagner en AI search\u003C/a>. L'autorité de domaine au sens Moz/Ahrefs n'est pas directement utilisée par les systèmes RAG. Ce qui compte, c'est la pertinence et la densité informationnelle du chunk, combinées à la cohérence thématique du domaine.\u003C/p>\n\u003Ch3>La fréquence de publication n'est pas un levier direct\u003C/h3>\n\u003Cp>Publier un article par jour ne vous rendra pas plus visible dans ChatGPT si chaque article manque de profondeur technique. Les LLM évaluent la qualité à l'échelle du chunk, pas à l'échelle du domaine. Un seul article technique exhaustif sur un sujet précis vaut plus que 20 articles superficiels.\u003C/p>\n\u003Ch3>Les meta descriptions ne sont pas utilisées par les LLM\u003C/h3>\n\u003Cp>Les systèmes RAG extraient le contenu \u003Ccode>&#x3C;body>\u003C/code>, pas les \u003Ccode>&#x3C;meta>\u003C/code>. Vos meta descriptions n'ont aucun impact sur votre visibilité IA. Concentrez votre effort sur le contenu visible, les headings, et la structure sémantique.\u003C/p>\n\u003Cp>Cela dit, comme l'analyse des \u003Ca href=\"/blog/ai-overview-ctr-fell-61-but-clicks-didn-t-collapse-via-sejournal-mattgsouthern\">retombées CTR des AI Overviews\u003C/a> l'a montré, les meta descriptions restent essentielles pour les résultats classiques qui coexistent avec les réponses IA.\u003C/p>\n\u003Ch2>Le monitoring continu comme filet de sécurité\u003C/h2>\n\u003Cp>Le diagnostic ponctuel ne suffit pas. Les régressions SSR, les changements de structure HTML après un déploiement, les blocages robots.txt accidentels — tout cela arrive en continu sur un site actif.\u003C/p>\n\u003Cp>Le scénario classique : un développeur ajoute un lazy-loading agressif sur les images et le contenu below-the-fold. L'impact sur Googlebot est nul (il attend le rendu complet). L'impact sur GPTBot est immédiat — tout le contenu sous le premier écran disparaît du HTML initial. Le site perd 40% de son contenu visible pour les bots IA, et personne ne s'en aperçoit pendant 3 mois.\u003C/p>\n\u003Cp>Un monitoring technique automatisé qui vérifie quotidiennement le contenu visible dans le HTML brut (sans rendu JS) permet de détecter ce type de régression en quelques heures. C'est le type de surveillance que Seogard automatise : comparer le HTML rendu côté serveur avec le contenu attendu, et alerter immédiatement quand un delta significatif apparaît.\u003C/p>\n\u003Chr>\n\u003Cp>La visibilité dans les moteurs de recherche IA n'est pas un nouveau canal marketing à \"optimiser\" — c'est un ensemble de contraintes techniques à satisfaire. Diagnostiquez chaque étape du pipeline (crawl, extraction, chunking, embedding, retrieval), identifiez votre point de rupture spécifique, et corrigez chirurgicalement. Le contenu qui est \u003Ca href=\"/blog/ai-sees-your-brand-as-math-not-messaging\">compris comme de la donnée structurée\u003C/a> par les LLM, pas comme de la\u003C/p>",null,12,[18,19,20,21,22],"AI search","LLM visibility","crawl budget","structured data","GEO","Pourquoi l'IA ignore votre contenu : diagnostic technique complet","Tue May 05 2026 06:02:59 GMT+0000 (Coordinated Universal Time)",[26,40,54],{"_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":38,"updatedAt":39},"6a041412aa6b273b0c40f181","how-to-build-local-pages-that-win-in-ai-powered-search-via-sejournal-lorenbaker","https://seogard.io/blog/how-to-build-local-pages-that-win-in-ai-powered-search-via-sejournal-lorenbaker","2026-05-13T06:02:58.743Z","2026-05-13","Guide technique pour construire des pages locales qui performent dans les AI Overviews et AI Mode. Schema, SSR, contenu structuré.",[34,18,35,36,37],"local SEO","pages locales","schema markup","SSR","Pages locales pour l'AI Search : architecture technique","Wed May 13 2026 06:02:58 GMT+0000 (Coordinated Universal Time)",{"_id":41,"slug":42,"__v":6,"author":7,"canonical":43,"category":10,"createdAt":44,"date":45,"description":46,"image":15,"imageAlt":15,"readingTime":47,"tags":48,"title":52,"updatedAt":53},"6a02c291aa6b273b0c2a74f9","the-tech-seo-audit-for-the-ai-search-era-how-to-maximize-your-ai-visibility-via-sejournal-jetoctopus","https://seogard.io/blog/the-tech-seo-audit-for-the-ai-search-era-how-to-maximize-your-ai-visibility-via-sejournal-jetoctopus","2026-05-12T06:02:57.339Z","2026-05-12","Comment adapter votre audit technique SEO aux exigences des AI Overviews, du crawl par les LLMs et du grounding. Méthodes, code et scénarios concrets.",14,[49,50,51,20,21],"tech seo audit","ai search","ai visibility","Audit SEO technique pour l'ère AI Search : guide avancé","Tue May 12 2026 06:02:57 GMT+0000 (Coordinated Universal Time)",{"_id":55,"slug":56,"__v":6,"author":7,"canonical":57,"category":10,"createdAt":58,"date":45,"description":59,"image":15,"imageAlt":15,"readingTime":16,"tags":60,"title":63,"updatedAt":64},"6a02fac0aa6b273b0c58d096","the-consensus-gap-via-sejournal-kevin-indig","https://seogard.io/blog/the-consensus-gap-via-sejournal-kevin-indig","2026-05-12T10:02:40.519Z","Une marque peut dominer dans un dashboard AI agrégé et être absente de deux moteurs sur trois. Analyse technique du Consensus Gap et méthodes pour le détecter.",[61,18,19,22,62],"consensus gap","multi-engine","The Consensus Gap : votre marque visible sur un LLM, invisible sur deux autres","Tue May 12 2026 10:02:40 GMT+0000 (Coordinated Universal Time)"]