[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fPPYcV9fnMSi9yyH4K6VUNNIh6qta9dXexOM9iAZjH70":3,"$fWVTXGjUfudfuxO4VI7w6h2pNUq3DXr_o34jR8Q7XeNQ":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},"69d1c49c2656ec73a068479f","google-pages-are-getting-larger-it-still-matters-via-sejournal-mattgsouthern",0,"Equipe Seogard","Gary Illyes et Martin Splitt viennent de remettre sur la table un sujet que beaucoup considéraient réglé : le poids des pages web augmente, et Googlebot a toujours une limite dure de 15 Mo sur le HTML brut qu'il télécharge. Au-delà, il tronque. Tout ce qui se trouve après la coupure — liens internes, contenu, structured data — n'existe tout simplement pas pour l'index.\n\n## La limite de 15 Mo : ce que Googlebot télécharge vraiment\n\nLa confusion est fréquente. La limite de 15 Mo concerne le **HTML brut décompressé** que Googlebot récupère, pas le poids total de la page côté navigateur (images, CSS, JS inclus). Cette distinction est capitale.\n\n### Le mécanisme de troncature\n\nQuand Googlebot envoie une requête HTTP, il accepte la compression (`gzip`, `br`). Mais la limite s'applique au contenu **après décompression**. Une page de 3 Mo compressée qui se décompresse en 18 Mo sera tronquée à 15 Mo. La [documentation officielle de Google](https://developers.google.com/search/docs/crawling-indexing/googlebot) confirme cette mécanique.\n\nLe problème n'est pas binaire (indexé / non indexé). C'est un problème de **complétude d'indexation**. Si votre footer contient 200 liens internes de maillage et que la troncature intervient avant, ces liens ne transmettent aucun signal. Si votre schema JSON-LD est injecté en bas de page, il est invisible.\n\n### Qui est réellement concerné ?\n\nSur un site vitrine de 30 pages, personne ne s'approche de 15 Mo de HTML. Le problème touche des profils très spécifiques :\n\n- **Pages de catégorie e-commerce** avec des centaines de produits inline, des filtres générés côté serveur, et du structured data par produit\n- **Pages d'agrégation de contenu** (annuaires, comparateurs) qui embarquent des dizaines de blocs de données\n- **SPA rendues côté serveur** où le state initial est sérialisé dans un `\u003Cscript>` massif (Next.js, Nuxt) — un pattern qui peut facilement injecter 2 à 5 Mo de JSON dans le HTML\n\nVoici comment vérifier le poids HTML brut d'une page avec `curl` :\n\n```bash\n# Télécharger le HTML brut et mesurer sa taille décompressée\ncurl -s -H \"Accept-Encoding: gzip\" --compressed \"https://shop.example.com/category/electronics\" | wc -c\n\n# Résultat en octets — diviser par 1048576 pour avoir des Mo\n# Variante avec le User-Agent Googlebot pour détecter un éventuel cloaking\ncurl -s -A \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\" \\\n  --compressed \"https://shop.example.com/category/electronics\" | wc -c\n```\n\nSi le résultat dépasse 10 Mo, vous êtes dans la zone de risque. À 12-13 Mo, vous jouez avec le feu sur les sections de fin de page.\n\n## Le structured data comme vecteur de bloat silencieux\n\nMartin Splitt a explicitement pointé le structured data comme facteur aggravant. Ce n'est pas un hasard. Sur les gros sites e-commerce, le JSON-LD peut représenter **30 à 50 % du poids HTML total**.\n\n### L'effet multiplicateur du Product schema\n\nPrenons un cas concret. Un site e-commerce de 15 000 pages (mode / textile) affiche 60 produits par page de catégorie. Chaque produit embarque un bloc JSON-LD `Product` avec `offers`, `aggregateRating`, `brand`, `image`, et `review`. Un bloc individuel pèse environ 1,5 Ko.\n\n60 produits × 1,5 Ko = **90 Ko** de JSON-LD rien que pour les produits. Ça semble raisonnable. Mais ajoutez le `BreadcrumbList`, le `CollectionPage`, le `WebSite` avec `SearchAction`, le `Organization`, et surtout les `ItemList` avec références croisées — et vous dépassez facilement 200 Ko de structured data par page de catégorie.\n\nLe vrai problème survient quand le template inclut des données redondantes. Voici un pattern toxique fréquent :\n\n```html\n\u003C!-- Anti-pattern : duplication massive de structured data -->\n\u003Cscript type=\"application/ld+json\">\n{\n  \"@context\": \"https://schema.org\",\n  \"@type\": \"ItemList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"item\": {\n        \"@type\": \"Product\",\n        \"name\": \"T-shirt col rond coton bio homme bleu marine taille S\",\n        \"description\": \"Ce t-shirt en coton biologique certifié GOTS offre un confort incomparable au quotidien. Coupe droite, col rond classique, coutures renforcées. Disponible en 12 coloris et 6 tailles. Fabriqué au Portugal dans notre atelier partenaire depuis 2019...\",\n        \"image\": [\"https://cdn.example.com/img/tshirt-bleu-1.jpg\", \"https://cdn.example.com/img/tshirt-bleu-2.jpg\", \"https://cdn.example.com/img/tshirt-bleu-3.jpg\"],\n        \"brand\": {\"@type\": \"Brand\", \"name\": \"EcoWear\"},\n        \"offers\": {\n          \"@type\": \"AggregateOffer\",\n          \"lowPrice\": \"29.90\",\n          \"highPrice\": \"34.90\",\n          \"priceCurrency\": \"EUR\",\n          \"availability\": \"https://schema.org/InStock\",\n          \"seller\": {\"@type\": \"Organization\", \"name\": \"FashionStore\", \"url\": \"https://shop.example.com\"}\n        },\n        \"aggregateRating\": {\"@type\": \"AggregateRating\", \"ratingValue\": \"4.3\", \"reviewCount\": \"127\"},\n        \"review\": [\n          {\"@type\": \"Review\", \"author\": {\"@type\": \"Person\", \"name\": \"Jean D.\"}, \"reviewBody\": \"Très bon t-shirt, je recommande...\", \"reviewRating\": {\"@type\": \"Rating\", \"ratingValue\": \"5\"}},\n          {\"@type\": \"Review\", \"author\": {\"@type\": \"Person\", \"name\": \"Marie L.\"}, \"reviewBody\": \"Taille un peu grand mais belle qualité...\", \"reviewRating\": {\"@type\": \"Rating\", \"ratingValue\": \"4\"}}\n        ]\n      }\n    }\n    // ... × 60 produits\n  ]\n}\n\u003C/script>\n```\n\nAvec la description longue, les reviews inline, les images multiples, et le seller répété 60 fois, ce bloc JSON-LD peut atteindre **400 à 600 Ko** sur une seule page de catégorie.\n\n### La stratégie de réduction\n\nLa recommandation est simple : sur les pages de listing, ne mettez que l'`ItemList` avec des références minimales. Réservez le schema `Product` complet (avec reviews, offers détaillées) aux pages produit individuelles.\n\n```html\n\u003C!-- Pattern optimisé : ItemList léger sur les pages de catégorie -->\n\u003Cscript type=\"application/ld+json\">\n{\n  \"@context\": \"https://schema.org\",\n  \"@type\": \"ItemList\",\n  \"itemListElement\": [\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 1,\n      \"url\": \"https://shop.example.com/product/tshirt-coton-bio-bleu\"\n    },\n    {\n      \"@type\": \"ListItem\",\n      \"position\": 2,\n      \"url\": \"https://shop.example.com/product/tshirt-coton-bio-noir\"\n    }\n  ]\n}\n\u003C/script>\n```\n\nDe 500 Ko à 5 Ko. Même résultat pour Google en termes de compréhension de la structure de la page. Les rich snippets produit se déclenchent sur les pages produit individuelles, pas sur les listings.\n\n## Le state hydration : le coupable oublié des frameworks modernes\n\nGary Illyes a rappelé que les pages grossissent. Une part significative de cette croissance vient d'un artefact technique que peu de SEO surveillent : le **serialized state** injecté par les frameworks SSR.\n\n### Le mécanisme\n\nQuand Next.js, Nuxt, ou Remix effectuent le rendu côté serveur, ils doivent transmettre l'état de l'application au client pour l'hydration. Cet état est sérialisé en JSON et injecté dans une balise `\u003Cscript>` du HTML. Si votre page de catégorie charge 60 produits avec toutes leurs variantes, stock, prix par taille, avis — tout cet objet est **dupliqué** : une fois dans le HTML rendu, une fois dans le JSON d'hydration.\n\nSur un site e-commerce Next.js que nous avons audité, le `__NEXT_DATA__` pesait **3,2 Mo** sur les pages de catégorie principales. Le HTML visible en faisait 1,8 Mo. Total : 5 Mo de HTML, dont 64 % était du JSON invisible pour l'utilisateur mais bien compté par Googlebot.\n\nCe sujet est directement lié aux [problèmes d'hydration mismatch](/blog/hydration-mismatch-le-bug-invisible-qui-tue-votre-seo) et au [choix du mode de rendering](/blog/isr-ssr-ssg-quel-mode-de-rendering-pour-le-seo). Un SSR mal configuré ne se contente pas de casser le rendu — il gonfle aussi le poids du HTML crawlé.\n\n### Comment diagnostiquer et réduire\n\nDans Chrome DevTools, ouvrez l'onglet **Network**, filtrez par `Doc`, et regardez la taille de la réponse HTML (colonne \"Size\" vs \"Content\" pour voir compressé vs décompressé). Puis dans l'onglet **Elements**, cherchez les balises `\u003Cscript id=\"__NEXT_DATA__\">` ou `\u003Cscript>window.__NUXT__=` et copiez leur contenu pour en mesurer la taille.\n\nAvec Screaming Frog, configurez une extraction custom pour capturer la taille de ces blocs sur l'ensemble du site :\n\n```\n# Configuration Screaming Frog — Custom Extraction\n# Mode : Regex\n# Pour Next.js :\n\u003Cscript id=\"__NEXT_DATA__\" type=\"application/json\">([\\s\\S]*?)\u003C/script>\n\n# Pour Nuxt :\n\u003Cscript>window\\.__NUXT__=([\\s\\S]*?)\u003C/script>\n```\n\nExportez les résultats et triez par taille d'extraction. Les pages dont le state dépasse 500 Ko méritent une investigation.\n\nLes solutions techniques pour réduire le state sérialisé :\n\n- **Pagination côté serveur** : ne chargez que 20 produits au lieu de 60, avec lazy loading pour le reste\n- **Data pruning** : ne sérialisez que les champs nécessaires au premier rendu. Les données de stock détaillées, les variantes de taille, les reviews complètes peuvent être chargées en client-side après hydration\n- **Streaming SSR** (React 18+) : réduit le contenu initial en streamant les sections non critiques\n- **Partial hydration** (Astro, Qwik) : élimine le state d'hydration pour les composants statiques\n\n## Scénario réel : un média de 8 000 pages face à la troncature\n\nUn site média spécialisé (technologie B2B) publie des articles longs (3 000 à 5 000 mots), chacun enrichi de structured data `Article`, `FAQPage`, `BreadcrumbList`, et `Organization`. Le template embarque aussi un sidebar avec les 50 articles les plus récents (titre + URL + date + excerpt), un footer avec 150 liens de maillage thématique, et des blocs \"articles liés\" en bas de page.\n\n### Les chiffres avant optimisation\n\n- HTML moyen par page article : **2,1 Mo** décompressé\n- Pages de hub thématique (agrégation de 100+ articles) : **6,8 Mo**\n- 3 pages d'archive dépassaient **12 Mo**\n- Aucune page ne dépassait 15 Mo, mais les pages les plus lourdes avaient un crawl rate 40 % inférieur aux pages légères (vérifié via les logs serveur)\n\nLe problème n'était pas la troncature, mais le **crawl budget**. Google alloue un budget de crawl fini. Si chaque page pèse 3× ce qu'elle devrait, le crawler traite 3× moins de pages dans le même temps. Sur 8 000 pages, ça signifie un délai d'indexation des nouveaux contenus qui passe de 2-3 jours à 7-10 jours — critique pour un média qui joue sur la fraîcheur.\n\nCe constat rejoint directement les [observations de Google sur les limites de crawl et l'architecture de Googlebot](/blog/google-explains-googlebot-byte-limits-and-crawling-architecture-via-sejournal-mattgsouthern) et les [discussions récentes sur les crawl limits](/blog/google-core-update-crawl-limits-gemini-traffic-data-seo-pulse-via-sejournal-mattgsouthern).\n\n### Les optimisations appliquées\n\n**1. Lazy rendering du sidebar et footer**\n\nLe sidebar \"articles récents\" a été remplacé par un placeholder rendu côté client. Côté HTML crawlé, les 50 articles × (titre + excerpt + lien) représentaient 120 Ko. Remplacé par un `\u003Cdiv data-widget=\"recent-articles\">` de 50 octets, avec chargement via Intersection Observer.\n\n**2. Minification du structured data**\n\nLe `FAQPage` schema embarquait les réponses complètes en HTML (avec `\u003Cp>`, `\u003Ca>`, `\u003Cstrong>`). Les réponses ont été réduites aux 300 premiers caractères en texte brut. Perte de richesse des rich results : aucune (Google tronque de toute façon l'affichage FAQ dans les SERPs).\n\n**3. Pagination des archives**\n\nLes pages d'archive qui listaient 100+ articles en une seule page ont été paginées à 30 articles, avec `rel=\"next\"` / `rel=\"prev\"` (oui, Google dit ne plus les utiliser officiellement, mais Bing et d'autres crawlers le font, et ça structure proprement le [sitemap](/blog/google-answers-why-some-seos-split-their-sitemap-into-multiple-files-via-sejournal-martinibuster)).\n\n### Résultats après 6 semaines\n\n- HTML moyen : de 2,1 Mo à **780 Ko** (-63 %)\n- Pages de hub : de 6,8 Mo à **1,2 Mo**\n- Crawl rate (pages/jour dans les logs) : +85 %\n- Délai moyen d'indexation des nouveaux articles : de 8 jours à **2,5 jours**\n- Trafic organique : +12 % sur les articles publiés depuis moins de 30 jours\n\n## Auditer systématiquement le poids HTML de votre site\n\nLe poids HTML n'est pas un métrique que la Search Console expose directement. Il faut aller le chercher.\n\n### Avec Screaming Frog\n\nLancez un crawl complet et exportez le rapport **Internal > HTML**. La colonne \"Response Size\" donne le poids compressé, mais celle qui vous intéresse est **\"Content Size\"** (décompressé). Triez par ordre décroissant. Toute page au-dessus de 5 Mo mérite une analyse manuelle.\n\nConfigurez un seuil d'alerte custom à 3 Mo pour déclencher un flag dans vos rapports de crawl récurrents.\n\n### Avec un script de monitoring continu\n\nPour les sites avec des templates dynamiques (contenu éditorial, e-commerce avec stock variable), le poids HTML fluctue. Un crawl ponctuel ne suffit pas. Voici un script Node.js minimal pour monitorer le poids des pages critiques :\n\n```javascript\n// monitor-html-weight.mjs\nimport { gzip } from 'node:zlib';\nimport { promisify } from 'node:util';\n\nconst compress = promisify(gzip);\n\nconst URLS = [\n  'https://shop.example.com/category/electronics',\n  'https://shop.example.com/category/clothing',\n  'https://shop.example.com/product/flagship-phone-2026',\n  // Ajoutez vos pages templates critiques\n];\n\nconst THRESHOLD_BYTES = 5 * 1024 * 1024; // 5 Mo — seuil d'alerte\n\nasync function checkPageWeight(url) {\n  const response = await fetch(url, {\n    headers: {\n      'User-Agent': 'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)',\n      'Accept-Encoding': 'identity', // Pas de compression pour mesurer le raw\n    },\n  });\n\n  const html = await response.text();\n  const rawBytes = Buffer.byteLength(html, 'utf-8');\n  const compressed = await compress(Buffer.from(html));\n\n  return {\n    url,\n    rawSizeKB: Math.round(rawBytes / 1024),\n    compressedSizeKB: Math.round(compressed.length / 1024),\n    overThreshold: rawBytes > THRESHOLD_BYTES,\n    nextDataSize: extractNextDataSize(html),\n    jsonLdSize: extractJsonLdSize(html),\n  };\n}\n\nfunction extractNextDataSize(html) {\n  const match = html.match(/\u003Cscript id=\"__NEXT_DATA__\"[^>]*>([\\s\\S]*?)\u003C\\/script>/);\n  return match ? Math.round(Buffer.byteLength(match[1], 'utf-8') / 1024) : 0;\n}\n\nfunction extractJsonLdSize(html) {\n  const matches = html.matchAll(/\u003Cscript type=\"application\\/ld\\+json\">([\\s\\S]*?)\u003C\\/script>/g);\n  let total = 0;\n  for (const match of matches) {\n    total += Buffer.byteLength(match[1], 'utf-8');\n  }\n  return Math.round(total / 1024);\n}\n\nasync function main() {\n  const results = await Promise.all(URLS.map(checkPageWeight));\n\n  console.table(results.map(r => ({\n    URL: r.url.replace('https://shop.example.com', ''),\n    'Raw (KB)': r.rawSizeKB,\n    'Gzip (KB)': r.compressedSizeKB,\n    'NEXT_DATA (KB)': r.nextDataSize,\n    'JSON-LD (KB)': r.jsonLdSize,\n    'Alert': r.overThreshold ? '⚠ OVER 5MB' : 'OK',\n  })));\n}\n\nmain();\n```\n\nCe script mesure le HTML décompressé, isole le poids du state d'hydration et du JSON-LD, et flag les pages qui dépassent le seuil. Intégrez-le dans votre CI/CD ou en cron quotidien.\n\nPour un monitoring continu et automatisé de ces métriques — sans maintenir de scripts maison — un outil comme Seogard détecte automatiquement les régressions de poids HTML et alerte quand une page dépasse un seuil critique, ce qui évite de découvrir le problème 3 semaines plus tard lors d'un audit trimestriel.\n\n### Avec les logs serveur\n\nL'analyse des logs donne un angle complémentaire. Corréllez le `content-length` des réponses aux requêtes Googlebot avec la fréquence de crawl par URL. Sur un Nginx correctement configuré :\n\n```nginx\n# Format de log custom pour isoler les bots et le poids des réponses\nlog_format seo_audit '$remote_addr - $http_user_agent [$time_local] '\n                     '\"$request\" $status $body_bytes_sent '\n                     '\"$http_referer\" rt=$request_time';\n\n# Appliquer uniquement aux requêtes bot (pour ne pas polluer les logs)\nmap $http_user_agent $is_bot {\n    ~*googlebot  1;\n    ~*bingbot    1;\n    default      0;\n}\n\nserver {\n    # Log dédié SEO\n    access_log /var/log/nginx/seo_crawl.log seo_audit if=$is_bot;\n}\n```\n\nPuis analysez avec `awk` :\n\n```bash\n# Top 20 des pages les plus lourdes servies à Googlebot\ngrep \"Googlebot\" /var/log/nginx/seo_crawl.log \\\n  | awk '{print $NF, $7}' \\\n  | sort -rn \\\n  | head -20\n```\n\n## Compression : le filet de sécurité que vous négligez peut-être\n\nLa compression ne réduit pas le poids décompressé (celui qui compte pour la limite de 15 Mo), mais elle réduit le temps de transfert et donc l'impact sur le crawl budget. Googlebot supporte `gzip` et `br` (Brotli).\n\nBrotli offre un ratio de compression 15-25 % supérieur à gzip sur le HTML. Si votre reverse proxy ne le sert pas encore, c'est un quick win :\n\n```nginx\n# Configuration Brotli dans Nginx (module ngx_brotli requis)\nbrotli on;\nbrotli_comp_level 6;  # 4-6 = bon compromis performance/ratio\nbrotli_types text/html text/css application/javascript application/json\n             application/ld+json text/xml application/xml;\n\n# Conserver gzip en fallback\ngzip on;\ngzip_comp_level 6;\ngzip_types text/html text/css application/javascript application/json\n           application/ld+json text/xml application/xml;\n```\n\nLe point important : `application/ld+json` est explicitement listé. Sans cela, vos blocs de structured data inline ne bénéficient pas de la compression quand ils sont servis séparément (cas rare mais possible avec certaines architectures).\n\nAttention au trade-off : un `brotli_comp_level` à 11 (maximum) réduit la taille de 5-8 % de plus qu'un niveau 6, mais multiplie le temps CPU de compression par 10. Sur un site à fort trafic bot, le coût CPU peut devenir problématique. Niveau 4 à 6 est le sweet spot pour le crawl SEO.\n\n## Ce que Google ne dit pas : le lien entre poids HTML et rendering budget\n\nGary Illyes parle de la limite de crawl à 15 Mo. Mais il y a un second plafond, moins documenté : le **rendering budget**. Googlebot sépare le crawl (téléchargement du HTML) du rendering (exécution JavaScript via le Web Rendering Service).\n\nLe WRS a ses propres contraintes de ressources. Un HTML de 8 Mo qui déclenche en plus 3 Mo de JavaScript pour l'hydration met plus de pression sur le rendering pipeline. Google n'a jamais publié de limite explicite pour le rendering, mais les [observations sur le comportement de Googlebot face aux SPA lourdes](/blog/pourquoi-google-voit-une-page-blanche-sur-votre-spa) montrent que les pages qui combinent HTML lourd et JS lourd sont systématiquement en retard de rendering.\n\nLe lien est indirect mais réel : un HTML plus léger se rend plus vite, est traité plus tôt dans la file de rendering, et donc indexé plus rapidement. [Tester ce que Google voit réellement](/blog/comment-tester-ce-que-google-voit-reellement-sur-votre-site) sur vos pages les plus lourdes permet de vérifier si le rendering est complet ou partiel.\n\n## Ce qui compte pour vos pages en 2026\n\nLe message de Gary Illyes et Martin Splitt n'est pas nouveau, mais il reste d'actualité précisément parce que les frameworks modernes, le structured data proliférant, et les architectures SSR-first créent un bloat HTML invisible. Personne ne voit un HTML de 4 Mo dans un navigateur — mais Googlebot, lui, le télécharge entièrement.\n\nLes actions prioritaires : mesurez le poids HTML décompressé de vos templates critiques, isolez la part du structured data et du state d'hydration, et posez des seuils d'alerte automatisés. Les [meta tags bien calibrées](/blog/meta-tags-seo-le-guide-complet-2025) ne servent à rien si elles se trouvent dans les 10 % du HTML que Googlebot n'a jamais lu.\n\n```","https://seogard.io/blog/google-pages-are-getting-larger-it-still-matters-via-sejournal-mattgsouthern","Actualités SEO","2026-04-05T02:10:36.787Z","2026-04-05","Google rappelle sa limite de crawl à 15 Mo. Analyse technique du page bloat, de son impact SEO réel, et des stratégies concrètes pour rester sous le seuil.","\u003Cp>Gary Illyes et Martin Splitt viennent de remettre sur la table un sujet que beaucoup considéraient réglé : le poids des pages web augmente, et Googlebot a toujours une limite dure de 15 Mo sur le HTML brut qu'il télécharge. Au-delà, il tronque. Tout ce qui se trouve après la coupure — liens internes, contenu, structured data — n'existe tout simplement pas pour l'index.\u003C/p>\n\u003Ch2>La limite de 15 Mo : ce que Googlebot télécharge vraiment\u003C/h2>\n\u003Cp>La confusion est fréquente. La limite de 15 Mo concerne le \u003Cstrong>HTML brut décompressé\u003C/strong> que Googlebot récupère, pas le poids total de la page côté navigateur (images, CSS, JS inclus). Cette distinction est capitale.\u003C/p>\n\u003Ch3>Le mécanisme de troncature\u003C/h3>\n\u003Cp>Quand Googlebot envoie une requête HTTP, il accepte la compression (\u003Ccode>gzip\u003C/code>, \u003Ccode>br\u003C/code>). Mais la limite s'applique au contenu \u003Cstrong>après décompression\u003C/strong>. Une page de 3 Mo compressée qui se décompresse en 18 Mo sera tronquée à 15 Mo. La \u003Ca href=\"https://developers.google.com/search/docs/crawling-indexing/googlebot\">documentation officielle de Google\u003C/a> confirme cette mécanique.\u003C/p>\n\u003Cp>Le problème n'est pas binaire (indexé / non indexé). C'est un problème de \u003Cstrong>complétude d'indexation\u003C/strong>. Si votre footer contient 200 liens internes de maillage et que la troncature intervient avant, ces liens ne transmettent aucun signal. Si votre schema JSON-LD est injecté en bas de page, il est invisible.\u003C/p>\n\u003Ch3>Qui est réellement concerné ?\u003C/h3>\n\u003Cp>Sur un site vitrine de 30 pages, personne ne s'approche de 15 Mo de HTML. Le problème touche des profils très spécifiques :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>Pages de catégorie e-commerce\u003C/strong> avec des centaines de produits inline, des filtres générés côté serveur, et du structured data par produit\u003C/li>\n\u003Cli>\u003Cstrong>Pages d'agrégation de contenu\u003C/strong> (annuaires, comparateurs) qui embarquent des dizaines de blocs de données\u003C/li>\n\u003Cli>\u003Cstrong>SPA rendues côté serveur\u003C/strong> où le state initial est sérialisé dans un \u003Ccode>&#x3C;script>\u003C/code> massif (Next.js, Nuxt) — un pattern qui peut facilement injecter 2 à 5 Mo de JSON dans le HTML\u003C/li>\n\u003C/ul>\n\u003Cp>Voici comment vérifier le poids HTML brut d'une page avec \u003Ccode>curl\u003C/code> :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Télécharger le HTML brut et mesurer sa taille décompressée\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\"> -H\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Accept-Encoding: gzip\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> --compressed\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"https://shop.example.com/category/electronics\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> wc\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Résultat en octets — diviser par 1048576 pour avoir des Mo\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Variante avec le User-Agent Googlebot pour détecter un éventuel cloaking\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -s\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -A\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)\"\u003C/span>\u003Cspan style=\"color:#79B8FF\"> \\\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  --compressed\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"https://shop.example.com/category/electronics\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> wc\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -c\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Si le résultat dépasse 10 Mo, vous êtes dans la zone de risque. À 12-13 Mo, vous jouez avec le feu sur les sections de fin de page.\u003C/p>\n\u003Ch2>Le structured data comme vecteur de bloat silencieux\u003C/h2>\n\u003Cp>Martin Splitt a explicitement pointé le structured data comme facteur aggravant. Ce n'est pas un hasard. Sur les gros sites e-commerce, le JSON-LD peut représenter \u003Cstrong>30 à 50 % du poids HTML total\u003C/strong>.\u003C/p>\n\u003Ch3>L'effet multiplicateur du Product schema\u003C/h3>\n\u003Cp>Prenons un cas concret. Un site e-commerce de 15 000 pages (mode / textile) affiche 60 produits par page de catégorie. Chaque produit embarque un bloc JSON-LD \u003Ccode>Product\u003C/code> avec \u003Ccode>offers\u003C/code>, \u003Ccode>aggregateRating\u003C/code>, \u003Ccode>brand\u003C/code>, \u003Ccode>image\u003C/code>, et \u003Ccode>review\u003C/code>. Un bloc individuel pèse environ 1,5 Ko.\u003C/p>\n\u003Cp>60 produits × 1,5 Ko = \u003Cstrong>90 Ko\u003C/strong> de JSON-LD rien que pour les produits. Ça semble raisonnable. Mais ajoutez le \u003Ccode>BreadcrumbList\u003C/code>, le \u003Ccode>CollectionPage\u003C/code>, le \u003Ccode>WebSite\u003C/code> avec \u003Ccode>SearchAction\u003C/code>, le \u003Ccode>Organization\u003C/code>, et surtout les \u003Ccode>ItemList\u003C/code> avec références croisées — et vous dépassez facilement 200 Ko de structured data par page de catégorie.\u003C/p>\n\u003Cp>Le vrai problème survient quand le template inclut des données redondantes. Voici un pattern toxique fréquent :\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;!-- Anti-pattern : duplication massive de structured data -->\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:#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\": \"ItemList\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \"itemListElement\": [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      \"@type\": \"ListItem\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      \"position\": 1,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      \"item\": {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        \"@type\": \"Product\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        \"name\": \"T-shirt col rond coton bio homme bleu marine taille S\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        \"description\": \"Ce t-shirt en coton biologique certifié GOTS offre un confort incomparable au quotidien. Coupe droite, col rond classique, coutures renforcées. Disponible en 12 coloris et 6 tailles. Fabriqué au Portugal dans notre atelier partenaire depuis 2019...\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        \"image\": [\"https://cdn.example.com/img/tshirt-bleu-1.jpg\", \"https://cdn.example.com/img/tshirt-bleu-2.jpg\", \"https://cdn.example.com/img/tshirt-bleu-3.jpg\"],\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        \"brand\": {\"@type\": \"Brand\", \"name\": \"EcoWear\"},\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        \"offers\": {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          \"@type\": \"AggregateOffer\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          \"lowPrice\": \"29.90\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          \"highPrice\": \"34.90\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          \"priceCurrency\": \"EUR\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          \"availability\": \"https://schema.org/InStock\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          \"seller\": {\"@type\": \"Organization\", \"name\": \"FashionStore\", \"url\": \"https://shop.example.com\"}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        \"aggregateRating\": {\"@type\": \"AggregateRating\", \"ratingValue\": \"4.3\", \"reviewCount\": \"127\"},\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        \"review\": [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          {\"@type\": \"Review\", \"author\": {\"@type\": \"Person\", \"name\": \"Jean D.\"}, \"reviewBody\": \"Très bon t-shirt, je recommande...\", \"reviewRating\": {\"@type\": \"Rating\", \"ratingValue\": \"5\"}},\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">          {\"@type\": \"Review\", \"author\": {\"@type\": \"Person\", \"name\": \"Marie L.\"}, \"reviewBody\": \"Taille un peu grand mais belle qualité...\", \"reviewRating\": {\"@type\": \"Rating\", \"ratingValue\": \"4\"}}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        ]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    // ... × 60 produits\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>Avec la description longue, les reviews inline, les images multiples, et le seller répété 60 fois, ce bloc JSON-LD peut atteindre \u003Cstrong>400 à 600 Ko\u003C/strong> sur une seule page de catégorie.\u003C/p>\n\u003Ch3>La stratégie de réduction\u003C/h3>\n\u003Cp>La recommandation est simple : sur les pages de listing, ne mettez que l'\u003Ccode>ItemList\u003C/code> avec des références minimales. Réservez le schema \u003Ccode>Product\u003C/code> complet (avec reviews, offers détaillées) aux pages produit individuelles.\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;!-- Pattern optimisé : ItemList léger sur les pages de catégorie -->\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:#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\": \"ItemList\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \"itemListElement\": [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      \"@type\": \"ListItem\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      \"position\": 1,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      \"url\": \"https://shop.example.com/product/tshirt-coton-bio-bleu\"\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\">      \"@type\": \"ListItem\",\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      \"position\": 2,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      \"url\": \"https://shop.example.com/product/tshirt-coton-bio-noir\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  ]\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\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>De 500 Ko à 5 Ko. Même résultat pour Google en termes de compréhension de la structure de la page. Les rich snippets produit se déclenchent sur les pages produit individuelles, pas sur les listings.\u003C/p>\n\u003Ch2>Le state hydration : le coupable oublié des frameworks modernes\u003C/h2>\n\u003Cp>Gary Illyes a rappelé que les pages grossissent. Une part significative de cette croissance vient d'un artefact technique que peu de SEO surveillent : le \u003Cstrong>serialized state\u003C/strong> injecté par les frameworks SSR.\u003C/p>\n\u003Ch3>Le mécanisme\u003C/h3>\n\u003Cp>Quand Next.js, Nuxt, ou Remix effectuent le rendu côté serveur, ils doivent transmettre l'état de l'application au client pour l'hydration. Cet état est sérialisé en JSON et injecté dans une balise \u003Ccode>&#x3C;script>\u003C/code> du HTML. Si votre page de catégorie charge 60 produits avec toutes leurs variantes, stock, prix par taille, avis — tout cet objet est \u003Cstrong>dupliqué\u003C/strong> : une fois dans le HTML rendu, une fois dans le JSON d'hydration.\u003C/p>\n\u003Cp>Sur un site e-commerce Next.js que nous avons audité, le \u003Ccode>__NEXT_DATA__\u003C/code> pesait \u003Cstrong>3,2 Mo\u003C/strong> sur les pages de catégorie principales. Le HTML visible en faisait 1,8 Mo. Total : 5 Mo de HTML, dont 64 % était du JSON invisible pour l'utilisateur mais bien compté par Googlebot.\u003C/p>\n\u003Cp>Ce sujet est directement lié aux \u003Ca href=\"/blog/hydration-mismatch-le-bug-invisible-qui-tue-votre-seo\">problèmes d'hydration mismatch\u003C/a> et au \u003Ca href=\"/blog/isr-ssr-ssg-quel-mode-de-rendering-pour-le-seo\">choix du mode de rendering\u003C/a>. Un SSR mal configuré ne se contente pas de casser le rendu — il gonfle aussi le poids du HTML crawlé.\u003C/p>\n\u003Ch3>Comment diagnostiquer et réduire\u003C/h3>\n\u003Cp>Dans Chrome DevTools, ouvrez l'onglet \u003Cstrong>Network\u003C/strong>, filtrez par \u003Ccode>Doc\u003C/code>, et regardez la taille de la réponse HTML (colonne \"Size\" vs \"Content\" pour voir compressé vs décompressé). Puis dans l'onglet \u003Cstrong>Elements\u003C/strong>, cherchez les balises \u003Ccode>&#x3C;script id=\"__NEXT_DATA__\">\u003C/code> ou \u003Ccode>&#x3C;script>window.__NUXT__=\u003C/code> et copiez leur contenu pour en mesurer la taille.\u003C/p>\n\u003Cp>Avec Screaming Frog, configurez une extraction custom pour capturer la taille de ces blocs sur l'ensemble du site :\u003C/p>\n\u003Cpre>\u003Ccode># Configuration Screaming Frog — Custom Extraction\n# Mode : Regex\n# Pour Next.js :\n&#x3C;script id=\"__NEXT_DATA__\" type=\"application/json\">([\\s\\S]*?)&#x3C;/script>\n\n# Pour Nuxt :\n&#x3C;script>window\\.__NUXT__=([\\s\\S]*?)&#x3C;/script>\n\u003C/code>\u003C/pre>\n\u003Cp>Exportez les résultats et triez par taille d'extraction. Les pages dont le state dépasse 500 Ko méritent une investigation.\u003C/p>\n\u003Cp>Les solutions techniques pour réduire le state sérialisé :\u003C/p>\n\u003Cul>\n\u003Cli>\u003Cstrong>Pagination côté serveur\u003C/strong> : ne chargez que 20 produits au lieu de 60, avec lazy loading pour le reste\u003C/li>\n\u003Cli>\u003Cstrong>Data pruning\u003C/strong> : ne sérialisez que les champs nécessaires au premier rendu. Les données de stock détaillées, les variantes de taille, les reviews complètes peuvent être chargées en client-side après hydration\u003C/li>\n\u003Cli>\u003Cstrong>Streaming SSR\u003C/strong> (React 18+) : réduit le contenu initial en streamant les sections non critiques\u003C/li>\n\u003Cli>\u003Cstrong>Partial hydration\u003C/strong> (Astro, Qwik) : élimine le state d'hydration pour les composants statiques\u003C/li>\n\u003C/ul>\n\u003Ch2>Scénario réel : un média de 8 000 pages face à la troncature\u003C/h2>\n\u003Cp>Un site média spécialisé (technologie B2B) publie des articles longs (3 000 à 5 000 mots), chacun enrichi de structured data \u003Ccode>Article\u003C/code>, \u003Ccode>FAQPage\u003C/code>, \u003Ccode>BreadcrumbList\u003C/code>, et \u003Ccode>Organization\u003C/code>. Le template embarque aussi un sidebar avec les 50 articles les plus récents (titre + URL + date + excerpt), un footer avec 150 liens de maillage thématique, et des blocs \"articles liés\" en bas de page.\u003C/p>\n\u003Ch3>Les chiffres avant optimisation\u003C/h3>\n\u003Cul>\n\u003Cli>HTML moyen par page article : \u003Cstrong>2,1 Mo\u003C/strong> décompressé\u003C/li>\n\u003Cli>Pages de hub thématique (agrégation de 100+ articles) : \u003Cstrong>6,8 Mo\u003C/strong>\u003C/li>\n\u003Cli>3 pages d'archive dépassaient \u003Cstrong>12 Mo\u003C/strong>\u003C/li>\n\u003Cli>Aucune page ne dépassait 15 Mo, mais les pages les plus lourdes avaient un crawl rate 40 % inférieur aux pages légères (vérifié via les logs serveur)\u003C/li>\n\u003C/ul>\n\u003Cp>Le problème n'était pas la troncature, mais le \u003Cstrong>crawl budget\u003C/strong>. Google alloue un budget de crawl fini. Si chaque page pèse 3× ce qu'elle devrait, le crawler traite 3× moins de pages dans le même temps. Sur 8 000 pages, ça signifie un délai d'indexation des nouveaux contenus qui passe de 2-3 jours à 7-10 jours — critique pour un média qui joue sur la fraîcheur.\u003C/p>\n\u003Cp>Ce constat rejoint directement les \u003Ca href=\"/blog/google-explains-googlebot-byte-limits-and-crawling-architecture-via-sejournal-mattgsouthern\">observations de Google sur les limites de crawl et l'architecture de Googlebot\u003C/a> et les \u003Ca href=\"/blog/google-core-update-crawl-limits-gemini-traffic-data-seo-pulse-via-sejournal-mattgsouthern\">discussions récentes sur les crawl limits\u003C/a>.\u003C/p>\n\u003Ch3>Les optimisations appliquées\u003C/h3>\n\u003Cp>\u003Cstrong>1. Lazy rendering du sidebar et footer\u003C/strong>\u003C/p>\n\u003Cp>Le sidebar \"articles récents\" a été remplacé par un placeholder rendu côté client. Côté HTML crawlé, les 50 articles × (titre + excerpt + lien) représentaient 120 Ko. Remplacé par un \u003Ccode>&#x3C;div data-widget=\"recent-articles\">\u003C/code> de 50 octets, avec chargement via Intersection Observer.\u003C/p>\n\u003Cp>\u003Cstrong>2. Minification du structured data\u003C/strong>\u003C/p>\n\u003Cp>Le \u003Ccode>FAQPage\u003C/code> schema embarquait les réponses complètes en HTML (avec \u003Ccode>&#x3C;p>\u003C/code>, \u003Ccode>&#x3C;a>\u003C/code>, \u003Ccode>&#x3C;strong>\u003C/code>). Les réponses ont été réduites aux 300 premiers caractères en texte brut. Perte de richesse des rich results : aucune (Google tronque de toute façon l'affichage FAQ dans les SERPs).\u003C/p>\n\u003Cp>\u003Cstrong>3. Pagination des archives\u003C/strong>\u003C/p>\n\u003Cp>Les pages d'archive qui listaient 100+ articles en une seule page ont été paginées à 30 articles, avec \u003Ccode>rel=\"next\"\u003C/code> / \u003Ccode>rel=\"prev\"\u003C/code> (oui, Google dit ne plus les utiliser officiellement, mais Bing et d'autres crawlers le font, et ça structure proprement le \u003Ca href=\"/blog/google-answers-why-some-seos-split-their-sitemap-into-multiple-files-via-sejournal-martinibuster\">sitemap\u003C/a>).\u003C/p>\n\u003Ch3>Résultats après 6 semaines\u003C/h3>\n\u003Cul>\n\u003Cli>HTML moyen : de 2,1 Mo à \u003Cstrong>780 Ko\u003C/strong> (-63 %)\u003C/li>\n\u003Cli>Pages de hub : de 6,8 Mo à \u003Cstrong>1,2 Mo\u003C/strong>\u003C/li>\n\u003Cli>Crawl rate (pages/jour dans les logs) : +85 %\u003C/li>\n\u003Cli>Délai moyen d'indexation des nouveaux articles : de 8 jours à \u003Cstrong>2,5 jours\u003C/strong>\u003C/li>\n\u003Cli>Trafic organique : +12 % sur les articles publiés depuis moins de 30 jours\u003C/li>\n\u003C/ul>\n\u003Ch2>Auditer systématiquement le poids HTML de votre site\u003C/h2>\n\u003Cp>Le poids HTML n'est pas un métrique que la Search Console expose directement. Il faut aller le chercher.\u003C/p>\n\u003Ch3>Avec Screaming Frog\u003C/h3>\n\u003Cp>Lancez un crawl complet et exportez le rapport \u003Cstrong>Internal > HTML\u003C/strong>. La colonne \"Response Size\" donne le poids compressé, mais celle qui vous intéresse est \u003Cstrong>\"Content Size\"\u003C/strong> (décompressé). Triez par ordre décroissant. Toute page au-dessus de 5 Mo mérite une analyse manuelle.\u003C/p>\n\u003Cp>Configurez un seuil d'alerte custom à 3 Mo pour déclencher un flag dans vos rapports de crawl récurrents.\u003C/p>\n\u003Ch3>Avec un script de monitoring continu\u003C/h3>\n\u003Cp>Pour les sites avec des templates dynamiques (contenu éditorial, e-commerce avec stock variable), le poids HTML fluctue. Un crawl ponctuel ne suffit pas. Voici un script Node.js minimal pour monitorer le poids des pages critiques :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// monitor-html-weight.mjs\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { gzip } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'node:zlib'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { promisify } \u003C/span>\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'node:util'\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\"> compress\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#B392F0\"> promisify\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(gzip);\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\"> URLS\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> [\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  'https://shop.example.com/category/electronics'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  'https://shop.example.com/category/clothing'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">  'https://shop.example.com/product/flagship-phone-2026'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  // Ajoutez vos pages templates critiques\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\"> THRESHOLD_BYTES\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 5\u003C/span>\u003Cspan style=\"color:#F97583\"> *\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 1024\u003C/span>\u003Cspan style=\"color:#F97583\"> *\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 1024\u003C/span>\u003Cspan style=\"color:#E1E4E8\">; \u003C/span>\u003Cspan style=\"color:#6A737D\">// 5 Mo — seuil d'alerte\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\"> checkPageWeight\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">url\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\">'Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">      'Accept-Encoding'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'identity'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#6A737D\">// Pas de compression pour mesurer le raw\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\">  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\"> rawBytes\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> Buffer.\u003C/span>\u003Cspan style=\"color:#B392F0\">byteLength\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(html, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'utf-8'\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\"> compressed\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> compress\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(Buffer.\u003C/span>\u003Cspan style=\"color:#B392F0\">from\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(html));\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\">    rawSizeKB: Math.\u003C/span>\u003Cspan style=\"color:#B392F0\">round\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(rawBytes \u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 1024\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    compressedSizeKB: Math.\u003C/span>\u003Cspan style=\"color:#B392F0\">round\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(compressed.\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\u003C/span>\u003Cspan style=\"color:#F97583\"> /\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 1024\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    overThreshold: rawBytes \u003C/span>\u003Cspan style=\"color:#F97583\">>\u003C/span>\u003Cspan style=\"color:#79B8FF\"> THRESHOLD_BYTES\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    nextDataSize: \u003C/span>\u003Cspan style=\"color:#B392F0\">extractNextDataSize\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(html),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    jsonLdSize: \u003C/span>\u003Cspan style=\"color:#B392F0\">extractJsonLdSize\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(html),\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\">function\u003C/span>\u003Cspan style=\"color:#B392F0\"> extractNextDataSize\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">html\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\"> match\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> html.\u003C/span>\u003Cspan style=\"color:#B392F0\">match\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">/\u003C/span>\u003Cspan style=\"color:#DBEDFF\">&#x3C;script id=\"__NEXT_DATA__\"\u003C/span>\u003Cspan style=\"color:#79B8FF\">[\u003C/span>\u003Cspan style=\"color:#F97583\">^\u003C/span>\u003Cspan style=\"color:#79B8FF\">>]\u003C/span>\u003Cspan style=\"color:#F97583\">*\u003C/span>\u003Cspan style=\"color:#DBEDFF\">>(\u003C/span>\u003Cspan style=\"color:#79B8FF\">[\\s\\S]\u003C/span>\u003Cspan style=\"color:#F97583\">*?\u003C/span>\u003Cspan style=\"color:#DBEDFF\">)&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D;font-weight:bold\">\\/\u003C/span>\u003Cspan style=\"color:#DBEDFF\">script>\u003C/span>\u003Cspan style=\"color:#9ECBFF\">/\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> match \u003C/span>\u003Cspan style=\"color:#F97583\">?\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> Math.\u003C/span>\u003Cspan style=\"color:#B392F0\">round\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(Buffer.\u003C/span>\u003Cspan style=\"color:#B392F0\">byteLength\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(match[\u003C/span>\u003Cspan style=\"color:#79B8FF\">1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">], \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'utf-8'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 1024\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \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\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">function\u003C/span>\u003Cspan style=\"color:#B392F0\"> extractJsonLdSize\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#FFAB70\">html\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\"> matches\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> html.\u003C/span>\u003Cspan style=\"color:#B392F0\">matchAll\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">/\u003C/span>\u003Cspan style=\"color:#DBEDFF\">&#x3C;script type=\"application\u003C/span>\u003Cspan style=\"color:#85E89D;font-weight:bold\">\\/\u003C/span>\u003Cspan style=\"color:#DBEDFF\">ld\u003C/span>\u003Cspan style=\"color:#85E89D;font-weight:bold\">\\+\u003C/span>\u003Cspan style=\"color:#DBEDFF\">json\">(\u003C/span>\u003Cspan style=\"color:#79B8FF\">[\\s\\S]\u003C/span>\u003Cspan style=\"color:#F97583\">*?\u003C/span>\u003Cspan style=\"color:#DBEDFF\">)&#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D;font-weight:bold\">\\/\u003C/span>\u003Cspan style=\"color:#DBEDFF\">script>\u003C/span>\u003Cspan style=\"color:#9ECBFF\">/\u003C/span>\u003Cspan style=\"color:#F97583\">g\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  let\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> total \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:#F97583\">  for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003Cspan style=\"color:#F97583\">const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> match\u003C/span>\u003Cspan style=\"color:#F97583\"> of\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> matches) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    total \u003C/span>\u003Cspan style=\"color:#F97583\">+=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> Buffer.\u003C/span>\u003Cspan style=\"color:#B392F0\">byteLength\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(match[\u003C/span>\u003Cspan style=\"color:#79B8FF\">1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">], \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'utf-8'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> Math.\u003C/span>\u003Cspan style=\"color:#B392F0\">round\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(total \u003C/span>\u003Cspan style=\"color:#F97583\">/\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 1024\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\"> main\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\"> results\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#79B8FF\"> Promise\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">all\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#79B8FF\">URLS\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">map\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(checkPageWeight));\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\">table\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(results.\u003C/span>\u003Cspan style=\"color:#B392F0\">map\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\"> ({\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    URL: r.url.\u003C/span>\u003Cspan style=\"color:#B392F0\">replace\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'https://shop.example.com'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">''\u003C/span>\u003Cspan style=\"color:#E1E4E8\">),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'Raw (KB)'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: r.rawSizeKB,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'Gzip (KB)'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: r.compressedSizeKB,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'NEXT_DATA (KB)'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: r.nextDataSize,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'JSON-LD (KB)'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: r.jsonLdSize,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    'Alert'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: r.overThreshold \u003C/span>\u003Cspan style=\"color:#F97583\">?\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '⚠ OVER 5MB'\u003C/span>\u003Cspan style=\"color:#F97583\"> :\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'OK'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  })));\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">main\u003C/span>\u003Cspan style=\"color:#E1E4E8\">();\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Ce script mesure le HTML décompressé, isole le poids du state d'hydration et du JSON-LD, et flag les pages qui dépassent le seuil. Intégrez-le dans votre CI/CD ou en cron quotidien.\u003C/p>\n\u003Cp>Pour un monitoring continu et automatisé de ces métriques — sans maintenir de scripts maison — un outil comme Seogard détecte automatiquement les régressions de poids HTML et alerte quand une page dépasse un seuil critique, ce qui évite de découvrir le problème 3 semaines plus tard lors d'un audit trimestriel.\u003C/p>\n\u003Ch3>Avec les logs serveur\u003C/h3>\n\u003Cp>L'analyse des logs donne un angle complémentaire. Corréllez le \u003Ccode>content-length\u003C/code> des réponses aux requêtes Googlebot avec la fréquence de crawl par URL. Sur un Nginx correctement configuré :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Format de log custom pour isoler les bots et le poids des réponses\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">log_format \u003C/span>\u003Cspan style=\"color:#E1E4E8\">seo_audit \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'$\u003C/span>\u003Cspan style=\"color:#E1E4E8\">remote_addr\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> - $\u003C/span>\u003Cspan style=\"color:#E1E4E8\">http_user_agent\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> [$\u003C/span>\u003Cspan style=\"color:#E1E4E8\">time_local\u003C/span>\u003Cspan style=\"color:#9ECBFF\">] '\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                     '\"$\u003C/span>\u003Cspan style=\"color:#E1E4E8\">request\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\" $\u003C/span>\u003Cspan style=\"color:#E1E4E8\">status\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> $\u003C/span>\u003Cspan style=\"color:#E1E4E8\">body_bytes_sent\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                     '\"$\u003C/span>\u003Cspan style=\"color:#E1E4E8\">http_referer\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\" rt=$\u003C/span>\u003Cspan style=\"color:#E1E4E8\">request_time\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Appliquer uniquement aux requêtes bot (pour ne pas polluer les logs)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">map\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> $\u003C/span>\u003Cspan style=\"color:#FFAB70\">http_user_agent\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> $is_bot {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    ~*\u003C/span>\u003Cspan style=\"color:#E1E4E8\">googlebot  \u003C/span>\u003Cspan style=\"color:#79B8FF\">1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    ~*\u003C/span>\u003Cspan style=\"color:#E1E4E8\">bingbot    \u003C/span>\u003Cspan style=\"color:#79B8FF\">1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">    default\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\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">server\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">    # Log dédié SEO\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    access_log \u003C/span>\u003Cspan style=\"color:#E1E4E8\">/var/log/nginx/seo_crawl.log seo_audit if=$is_bot;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Puis analysez avec \u003Ccode>awk\u003C/code> :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Top 20 des pages les plus lourdes servies à Googlebot\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Googlebot\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> /var/log/nginx/seo_crawl.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 $NF, $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\"> -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\"> -20\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Ch2>Compression : le filet de sécurité que vous négligez peut-être\u003C/h2>\n\u003Cp>La compression ne réduit pas le poids décompressé (celui qui compte pour la limite de 15 Mo), mais elle réduit le temps de transfert et donc l'impact sur le crawl budget. Googlebot supporte \u003Ccode>gzip\u003C/code> et \u003Ccode>br\u003C/code> (Brotli).\u003C/p>\n\u003Cp>Brotli offre un ratio de compression 15-25 % supérieur à gzip sur le HTML. Si votre reverse proxy ne le sert pas encore, c'est un quick win :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Configuration Brotli dans Nginx (module ngx_brotli requis)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">brotli\u003C/span>\u003Cspan style=\"color:#79B8FF\"> on\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">brotli_comp_level\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 6\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;  \u003C/span>\u003Cspan style=\"color:#6A737D\"># 4-6 = bon compromis performance/ratio\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">brotli_types\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> text/html text/css application/javascript application/json\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">             application/ld+json\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> text/xml application/xml;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Conserver gzip en fallback\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">gzip \u003C/span>\u003Cspan style=\"color:#79B8FF\">on\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">gzip_comp_level \u003C/span>\u003Cspan style=\"color:#79B8FF\">6\u003C/span>\u003Cspan style=\"color:#E1E4E8\">;\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">gzip_types \u003C/span>\u003Cspan style=\"color:#E1E4E8\">text/html text/css application/javascript application/json\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">           application/ld+json text/xml application/xml;\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Le point important : \u003Ccode>application/ld+json\u003C/code> est explicitement listé. Sans cela, vos blocs de structured data inline ne bénéficient pas de la compression quand ils sont servis séparément (cas rare mais possible avec certaines architectures).\u003C/p>\n\u003Cp>Attention au trade-off : un \u003Ccode>brotli_comp_level\u003C/code> à 11 (maximum) réduit la taille de 5-8 % de plus qu'un niveau 6, mais multiplie le temps CPU de compression par 10. Sur un site à fort trafic bot, le coût CPU peut devenir problématique. Niveau 4 à 6 est le sweet spot pour le crawl SEO.\u003C/p>\n\u003Ch2>Ce que Google ne dit pas : le lien entre poids HTML et rendering budget\u003C/h2>\n\u003Cp>Gary Illyes parle de la limite de crawl à 15 Mo. Mais il y a un second plafond, moins documenté : le \u003Cstrong>rendering budget\u003C/strong>. Googlebot sépare le crawl (téléchargement du HTML) du rendering (exécution JavaScript via le Web Rendering Service).\u003C/p>\n\u003Cp>Le WRS a ses propres contraintes de ressources. Un HTML de 8 Mo qui déclenche en plus 3 Mo de JavaScript pour l'hydration met plus de pression sur le rendering pipeline. Google n'a jamais publié de limite explicite pour le rendering, mais les \u003Ca href=\"/blog/pourquoi-google-voit-une-page-blanche-sur-votre-spa\">observations sur le comportement de Googlebot face aux SPA lourdes\u003C/a> montrent que les pages qui combinent HTML lourd et JS lourd sont systématiquement en retard de rendering.\u003C/p>\n\u003Cp>Le lien est indirect mais réel : un HTML plus léger se rend plus vite, est traité plus tôt dans la file de rendering, et donc indexé plus rapidement. \u003Ca href=\"/blog/comment-tester-ce-que-google-voit-reellement-sur-votre-site\">Tester ce que Google voit réellement\u003C/a> sur vos pages les plus lourdes permet de vérifier si le rendering est complet ou partiel.\u003C/p>\n\u003Ch2>Ce qui compte pour vos pages en 2026\u003C/h2>\n\u003Cp>Le message de Gary Illyes et Martin Splitt n'est pas nouveau, mais il reste d'actualité précisément parce que les frameworks modernes, le structured data proliférant, et les architectures SSR-first créent un bloat HTML invisible. Personne ne voit un HTML de 4 Mo dans un navigateur — mais Googlebot, lui, le télécharge entièrement.\u003C/p>\n\u003Cp>Les actions prioritaires : mesurez le poids HTML décompressé de vos templates critiques, isolez la part du structured data et du state d'hydration, et posez des seuils d'alerte automatisés. Les \u003Ca href=\"/blog/meta-tags-seo-le-guide-complet-2025\">meta tags bien calibrées\u003C/a> ne servent à rien si elles se trouvent dans les 10 % du HTML que Googlebot n'a jamais lu.\u003C/p>\n\u003Cpre>\u003Ccode>\u003C/code>\u003C/pre>",null,12,[18,19,20,21,22],"google","crawl budget","page weight","structured data","performance SEO","Limite de 15 Mo de Googlebot : pourquoi le poids des pages compte encore","Sun Apr 05 2026 02:23:26 GMT+0000 (Coordinated Universal Time)",[26,42,55],{"_id":27,"slug":28,"__v":6,"author":7,"canonical":29,"category":10,"createdAt":30,"date":31,"description":32,"image":15,"imageAlt":15,"readingTime":33,"tags":34,"title":40,"updatedAt":41},"69d481e1f4fa19862862f691","how-to-design-content-that-ai-systems-prefer-and-promote","https://seogard.io/blog/how-to-design-content-that-ai-systems-prefer-and-promote","2026-04-07T04:02:41.265Z","2026-04-07","Comment le passage-level retrieval fonctionne et pourquoi un contenu answer-first, structuré par blocs, maximise vos chances d'être surfacé par les IA.",14,[35,36,37,38,39],"AI content design","passage retrieval","answer-first","structured content","SEO technique","Structurer le contenu pour les systèmes IA : passage retrieval et answer-first","Tue Apr 07 2026 04:02:41 GMT+0000 (Coordinated Universal Time)",{"_id":43,"slug":44,"__v":6,"author":7,"canonical":45,"category":10,"createdAt":46,"date":31,"description":47,"image":15,"imageAlt":15,"readingTime":16,"tags":48,"title":53,"updatedAt":54},"69d4ba23f4fa19862878e7ce","chatgpt-now-crawls-3-6x-more-than-googlebot-what-24m-requests-reveal","https://seogard.io/blog/chatgpt-now-crawls-3-6x-more-than-googlebot-what-24m-requests-reveal","2026-04-07T08:02:43.199Z","Analyse technique de 24M de requêtes de crawl : pourquoi ChatGPT-User dépasse Googlebot et comment adapter votre infrastructure serveur.",[49,50,19,51,52],"chatgpt","googlebot","log analysis","AI crawlers","ChatGPT crawle 3.6x plus que Googlebot : analyse de 24M de requêtes","Tue Apr 07 2026 08:02:43 GMT+0000 (Coordinated Universal Time)",{"_id":56,"slug":57,"__v":6,"author":7,"canonical":58,"category":10,"createdAt":59,"date":60,"description":61,"image":15,"imageAlt":15,"readingTime":16,"tags":62,"title":67,"updatedAt":68},"69d3db11f4fa19862809a070","seo-in-2026-higher-standards-ai-influence-and-a-web-still-catching-up","https://seogard.io/blog/seo-in-2026-higher-standards-ai-influence-and-a-web-still-catching-up","2026-04-06T16:10:57.670Z","2026-04-06","Analyse technique des évolutions SEO 2026 : gestion des bots IA, LLMs.txt, structured data avancé et monitoring des régressions critiques.",[63,64,21,65,66],"seo 2026","AI SEO","LLMs.txt","technical SEO","SEO en 2026 : standards relevés, IA omniprésente, web en retard","Mon Apr 06 2026 16:10:57 GMT+0000 (Coordinated Universal Time)"]