[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fQyiiAdsf6y8wmmW4u2TgFWsU5QaoHHtcvCmPTEhkdnI":3,"$fh3nZtROzDZj2Mi_vExdPoK4BMlK7RihqTHTjbsynJ7c":25,"$fcTFjTaPPT1sVcnh1wWEGoTWMSaOD4bwmwntkMae6w5s":112},{"_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},"6a2a4fa0aa6b273b0cdf1eab","schema-org-now-shows-you-how-many-sites-are-using-each-schema-type",0,"Equipe Seogard","## Schema.org expose ses données d'adoption — et ça change la donne\n\nJusqu'à présent, choisir un type Schema.org relevait d'un mélange de documentation officielle, de reverse-engineering des SERP et d'intuition. Vous implémentiez `HowTo` ou `FAQPage` sans savoir si Google voyait ces types sur 500 sites ou 5 millions. Schema.org vient de combler ce vide : chaque page de type affiche désormais le nombre de domaines qui l'utilisent en production, données issues du corpus [Web Data Commons](https://webdatacommons.org/structureddata/). Ce n'est pas un gadget cosmétique — c'est la première fois qu'on dispose d'une donnée quantitative fiable pour prioriser son balisage structuré.\n\n## Ce qui a changé concrètement sur Schema.org\n\n### La nouvelle section \"Usage statistics\"\n\nRendez-vous sur n'importe quelle page de type — par exemple [https://schema.org/Product](https://schema.org/Product). Sous la description et la hiérarchie de propriétés, une section affiche désormais le nombre de domaines et de pages utilisant ce type, ventilé par format (JSON-LD, Microdata, RDFa).\n\nCes chiffres ne viennent pas de Google. Ils sont extraits du dataset Web Data Commons, un projet de l'Université de Mannheim qui parse les données structurées sur un échantillon massif du Common Crawl. Le dernier corpus couvre environ 3,3 milliards de pages HTML.\n\n### Ce que les chiffres révèlent (et ce qu'ils cachent)\n\nLes données exposent deux métriques : **le nombre de domaines** et **le nombre de pages**. La distinction est cruciale. Un e-commerce de 50 000 fiches produit avec `Product` sur chaque page compte pour un seul domaine mais 50 000 pages. Un réseau de 200 micro-sites avec une seule page `LocalBusiness` chacun compte pour 200 domaines mais 200 pages.\n\nLimitation importante : le Common Crawl n'est pas un miroir exact du web. Il sous-représente les sites derrière des paywalls, les SPA sans server-side rendering, et les pages profondes nécessitant une authentification. Si votre site SPA sert le JSON-LD uniquement côté client sans SSR, il est probable que le Common Crawl ne le capte pas — tout comme Googlebot dans certaines configurations. Un parallèle direct avec les problèmes de [rendering côté serveur et de contenu invisible au fetch HTTP brut](/blog/lazy-load-du-hero-h1-dans-une-section-v-if-invisible-au-fetch-http-brut).\n\n### Format de prédilection : JSON-LD domine\n\nLes données confirment ce que la communauté SEO technique soupçonnait : JSON-LD est devenu le format dominant pour la plupart des types à forte valeur SEO (`Product`, `Article`, `FAQPage`, `Organization`). Microdata persiste principalement sur des CMS legacy (WordPress pré-Yoast, Joomla). RDFa est marginal sauf sur certains sites institutionnels.\n\n## Exploiter ces données pour prioriser votre balisage\n\n### L'arbitrage adoption vs. différenciation\n\nLe réflexe naturel serait de dire : \"beaucoup de sites utilisent `Product`, donc je dois l'utiliser aussi.\" C'est vrai pour les types qui déclenchent des rich results — Google ne va pas désactiver les extraits enrichis pour `Product` quand des millions de sites en dépendent. Le signal est clair : forte adoption = type stable, supporté durablement.\n\nMais le raisonnement inverse est tout aussi intéressant. Un type peu adopté mais pertinent pour votre secteur représente une opportunité de différenciation dans le Knowledge Graph. Prenez `MedicalCondition` : si les données montrent quelques milliers de domaines seulement, mais que vous opérez un site santé avec 8 000 pages de conditions médicales, un balisage soigné vous donne un avantage structurel pour l'alimentation des AI Overviews et des panneaux de connaissance.\n\n### Matrice de décision concrète\n\nVoici comment structurer l'arbitrage pour un e-commerce de 15 000 produits avec un blog de 2 000 articles :\n\n| Type Schema.org | Adoption (domaines) | Rich result Google | Priorité |\n|---|---|---|---|\n| `Product` | Très élevée (~3M+) | Oui (Product snippet) | **P0** — non négociable |\n| `Article` | Très élevée (~5M+) | Oui (Article snippet) | **P0** — sur chaque article |\n| `BreadcrumbList` | Élevée (~1.5M+) | Oui (Breadcrumbs SERP) | **P0** — structure de navigation |\n| `FAQPage` | Modérée (~500K) | Restreint depuis 2023 | **P2** — uniquement si FAQ réelle |\n| `HowTo` | Modérée (~300K) | Restreint depuis 2023 | **P2** — guides pratiques |\n| `SpecialOffer` | Faible (~10K) | Non directement | **P1** — différenciation |\n\nLes types `FAQPage` et `HowTo` illustrent un point important : Google a [restreint leur éligibilité aux rich results en août 2023](https://developers.google.com/search/docs/appearance/structured-data/faqpage), mais ils restent utiles pour alimenter les systèmes d'IA générative. L'adoption modérée signifie que le type est compris et indexé — il vaut le coup si vous avez du [contenu FAQ pertinent](/blog/5-places-to-find-faq-content-that-improves-ai-visibility).\n\n## Requêter les données d'adoption par programmation\n\nLes statistiques affichées sur Schema.org sont utiles pour un check ponctuel. Pour un audit systématique, vous pouvez requêter directement le dataset Web Data Commons via leur endpoint SPARQL ou télécharger les fichiers bruts.\n\n### Accéder au dataset Web Data Commons\n\nWeb Data Commons publie ses extractions sur [webdatacommons.org/structureddata](https://webdatacommons.org/structureddata/). Les fichiers sont au format N-Quads, partitionnés par format (JSON-LD, Microdata, RDFa). Pour une analyse ciblée, le plus efficace est d'utiliser le résumé statistique qu'ils publient en TSV.\n\n```bash\n# Télécharger le résumé d'adoption par type (JSON-LD)\ncurl -O https://webdatacommons.org/structureddata/2024-09/stats/schema_org_subsets/jsonld_type_count.tsv\n\n# Filtrer les types Product, Article, FAQPage\ngrep -E \"^(Product|Article|FAQPage)\\t\" jsonld_type_count.tsv | sort -t$'\\t' -k2 -rn\n\n# Résultat typique (format : type \\t nombre_de_pages \\t nombre_de_domaines)\n# Product    287654321    3124567\n# Article    412987654    5234891\n# FAQPage     45678901     487234\n```\n\nLes URLs exactes des fichiers changent à chaque release. Vérifiez toujours la dernière version disponible sur la page du projet.\n\n### Script d'analyse comparative pour votre secteur\n\nSupposons que vous gérez un site média avec 12 000 articles et que vous voulez comparer votre adoption de types Schema.org avec la moyenne du web. Ce script Python croise votre export Screaming Frog avec les données WDC :\n\n```python\nimport csv\nfrom collections import Counter\n\n# 1. Parser l'export Screaming Frog (colonne \"Structured Data > Type\")\ndef parse_screaming_frog_export(filepath: str) -> Counter:\n    type_counts = Counter()\n    with open(filepath, 'r', encoding='utf-8') as f:\n        reader = csv.DictReader(f)\n        for row in reader:\n            sd_types = row.get('Structured Data 1 > Type', '')\n            if sd_types:\n                for t in sd_types.split(', '):\n                    type_counts[t.strip()] += 1\n    return type_counts\n\n# 2. Parser le résumé WDC\ndef parse_wdc_stats(filepath: str) -> dict:\n    stats = {}\n    with open(filepath, 'r') as f:\n        reader = csv.reader(f, delimiter='\\t')\n        for row in reader:\n            if len(row) >= 3:\n                stats[row[0]] = {\n                    'pages': int(row[1]),\n                    'domains': int(row[2])\n                }\n    return stats\n\n# 3. Comparer\nmy_types = parse_screaming_frog_export('screaming_frog_export.csv')\nwdc_stats = parse_wdc_stats('jsonld_type_count.tsv')\n\nprint(f\"{'Type':\u003C25} {'Vos pages':>12} {'WDC pages':>15} {'WDC domaines':>15}\")\nprint(\"-\" * 70)\n\nfor schema_type, count in my_types.most_common(20):\n    wdc = wdc_stats.get(schema_type, {'pages': 0, 'domains': 0})\n    print(f\"{schema_type:\u003C25} {count:>12,} {wdc['pages']:>15,} {wdc['domains']:>15,}\")\n```\n\nCe type d'analyse révèle les trous : si votre site média publie 12 000 `Article` mais zéro `VideoObject` alors que WDC montre 800K+ domaines avec `VideoObject`, vous passez peut-être à côté de rich results vidéo sur vos contenus embed.\n\n## Auditer et monitorer votre balisage structuré à l'échelle\n\n### Validation en masse avec Screaming Frog et jq\n\nScreaming Frog extrait les données structurées depuis la v17, mais sa sortie est parfois difficile à exploiter programmatiquement. Une approche complémentaire : crawler votre site avec un script qui extrait et valide le JSON-LD brut.\n\n```bash\n#!/bin/bash\n# extract_jsonld.sh — Extraire et valider le JSON-LD de chaque URL d'un sitemap\n\nSITEMAP_URL=\"https://www.votresite.fr/sitemap.xml\"\n\n# Extraire les URLs du sitemap\ncurl -s \"$SITEMAP_URL\" | grep -oP '(?\u003C=\u003Cloc>)[^\u003C]+' > urls.txt\n\necho \"URL,JSON-LD Types,Validation\" > report.csv\n\nwhile IFS= read -r url; do\n  # Fetch le HTML (user-agent Googlebot pour cohérence)\n  html=$(curl -s -A \"Mozilla/5.0 (compatible; Googlebot/2.1)\" \"$url\")\n  \n  # Extraire les blocs JSON-LD\n  jsonld=$(echo \"$html\" | python3 -c \"\nimport sys, re, json\nhtml = sys.stdin.read()\nblocks = re.findall(r'\u003Cscript type=\\\"application/ld\\+json\\\">(.*?)\u003C/script>', html, re.DOTALL)\ntypes = []\nfor b in blocks:\n    try:\n        data = json.loads(b)\n        if isinstance(data, list):\n            for item in data:\n                types.append(item.get('@type', 'UNKNOWN'))\n        else:\n            types.append(data.get('@type', 'UNKNOWN'))\n    except json.JSONDecodeError:\n        types.append('INVALID_JSON')\nprint(','.join(types) if types else 'NONE')\n\")\n  \n  # Vérifier si le JSON est valide\n  validation=\"OK\"\n  if echo \"$jsonld\" | grep -q \"INVALID_JSON\"; then\n    validation=\"ERREUR_JSON\"\n  elif echo \"$jsonld\" | grep -q \"NONE\"; then\n    validation=\"ABSENT\"\n  fi\n  \n  echo \"\\\"$url\\\",\\\"$jsonld\\\",\\\"$validation\\\"\" >> report.csv\n  \ndone \u003C urls.txt\n\necho \"Rapport généré : report.csv\"\necho \"Pages sans JSON-LD :\"\ngrep \"ABSENT\" report.csv | wc -l\necho \"Pages avec JSON invalide :\"\ngrep \"ERREUR_JSON\" report.csv | wc -l\n```\n\nSur un site e-commerce de 15 000 pages, ce script (exécuté en parallèle avec `xargs -P 10`) prend environ 45 minutes. Le rapport CSV révèle immédiatement les pages où le JSON-LD est absent (template mal configuré), invalide (virgule trailing, guillemets non échappés), ou utilisant un type inattendu.\n\n### Le piège du JSON-LD dynamique\n\nSur les stacks JavaScript modernes (Next.js, Nuxt, SvelteKit), le JSON-LD est souvent généré dynamiquement. Le problème classique : le bloc `\u003Cscript type=\"application/ld+json\">` dépend de données async qui peuvent échouer silencieusement.\n\nExemple concret sur Next.js App Router :\n\n```tsx\n// app/products/[slug]/page.tsx\nexport default async function ProductPage({ params }: { params: { slug: string } }) {\n  const product = await getProduct(params.slug);\n  \n  // Si getProduct retourne null (API timeout, 404, etc.),\n  // le JSON-LD n'est pas rendu — SANS erreur visible\n  return (\n    \u003C>\n      {product && (\n        \u003Cscript\n          type=\"application/ld+json\"\n          dangerouslySetInnerHTML={{\n            __html: JSON.stringify({\n              \"@context\": \"https://schema.org\",\n              \"@type\": \"Product\",\n              \"name\": product.name,\n              \"description\": product.description,\n              \"sku\": product.sku,\n              \"offers\": {\n                \"@type\": \"Offer\",\n                \"price\": product.price,\n                \"priceCurrency\": \"EUR\",\n                \"availability\": product.inStock \n                  ? \"https://schema.org/InStock\" \n                  : \"https://schema.org/OutOfStock\"\n              },\n              \"aggregateRating\": product.reviews?.length > 0 ? {\n                \"@type\": \"AggregateRating\",\n                \"ratingValue\": product.averageRating,\n                \"reviewCount\": product.reviews.length\n              } : undefined\n            })\n          }}\n        />\n      )}\n      {/* reste du composant */}\n    \u003C/>\n  );\n}\n```\n\nLe problème : si `getProduct` échoue sur 3 % de vos 15 000 pages produit à cause de timeouts API intermittents, vous avez 450 pages sans JSON-LD `Product`. Googlebot ne va pas vous alerter. La Search Console montre uniquement les erreurs de structure sur les pages **où elle détecte** du structured data — pas les pages où il manque. Ce type de régression silencieuse est exactement ce que détecte un outil de monitoring continu comme Seogard : il compare le JSON-LD attendu au JSON-LD réellement servi sur chaque URL crawlée, et alerte quand un bloc disparaît.\n\nCe genre de bug côté metadata rejoint une classe d'erreurs documentée sur les frameworks modernes. Les [metadata async qui throw silencieusement sur Next.js](/blog/next-js-metadata-async-qui-throw-la-page-sert-le-fallback-default-next-js) ou les [override silencieux de useSeometa sur Nuxt](/blog/nuxt-useseometa-le-child-override-silencieusement-les-meta-du-layout-parent) suivent exactement le même pattern : pas d'erreur visible, pas d'alerte framework, mais un impact SEO cumulatif.\n\n## Stratégie : utiliser les données d'adoption pour l'AI visibility\n\n### Le lien entre structured data et systèmes génératifs\n\nLes AI Overviews de Google et les systèmes comme Perplexity ou ChatGPT Search consomment les données structurées pour construire leurs réponses. La différence avec les rich results classiques : les systèmes d'IA n'ont pas besoin que Google \"supporte\" officiellement un type pour l'exploiter. Un `SoftwareApplication` bien balisé avec `applicationCategory`, `operatingSystem` et `offers` peut alimenter une réponse IA même si Google n'affiche pas de rich result dédié en SERP.\n\nLes données d'adoption de Schema.org deviennent un signal stratégique : si un type est largement adopté, les systèmes d'IA ont été entraînés sur suffisamment d'exemples pour le comprendre de manière fiable. À l'inverse, un type confidentiel avec moins de 1 000 domaines risque d'être mal interprété ou ignoré.\n\nCe raisonnement s'inscrit dans la tendance plus large de visibilité auprès des agents IA, un sujet sur lequel [l'identification des visiteurs IA et de leur provenance](/blog/your-next-ai-visitor-will-know-who-sent-it-via-sejournal-slobodanmanic) devient un enjeu de mesure, et où [le standard EntityMap propose une vue structurée de votre activité pour les systèmes IA](/blog/entitymap-the-open-standard-that-gives-ai-systems-a-structured-view-of-your-business-via-sejournal-dixon-jones).\n\n### Cas concret : un site SaaS B2B de 800 pages\n\nPrenons un éditeur SaaS B2B avec :\n- 1 page produit principale\n- 120 pages de fonctionnalités\n- 45 pages de tarifs/plans\n- 200 articles de blog\n- 80 pages de documentation\n- 30 pages de cas clients\n- ~325 pages légales, carrières, landing pages diverses\n\nAvant les données d'adoption Schema.org, l'équipe SEO balisait principalement `Organization` (homepage), `Article` (blog) et `BreadcrumbList` (toutes pages). Avec les données d'adoption, l'audit révèle des opportunités négligées :\n\n| Page type | Type Schema actuel | Type Schema recommandé | Adoption WDC |\n|---|---|---|---|\n| Fonctionnalités | Aucun | `SoftwareApplication` | ~180K domaines |\n| Cas clients | `Article` | `Review` + `Organization` | ~900K domaines |\n| Documentation | Aucun | `TechArticle` | ~25K domaines |\n| Tarifs | Aucun | `Offer` + `SoftwareApplication` | ~2.5M (Offer) |\n\n`TechArticle` avec seulement ~25K domaines est un pari : faible adoption signifie que les AI systems ont moins de données d'entraînement sur ce type. Mais pour un site de documentation technique, la pertinence sémantique est maximale. Le trade-off penche vers l'implémentation — le coût est faible (quelques lignes JSON-LD), et le signal de pertinence pour les LLM qui parcourent votre doc est réel.\n\n### Implémenter le JSON-LD conditionnel par template\n\nPour un site de cette taille, l'approche la plus maintenable est un composant centralisé qui reçoit le type et les données en props :\n\n```tsx\n// components/StructuredData.tsx\ninterface StructuredDataProps {\n  type: string;\n  data: Record\u003Cstring, unknown>;\n}\n\nexport function StructuredData({ type, data }: StructuredDataProps) {\n  const jsonLd = {\n    \"@context\": \"https://schema.org\",\n    \"@type\": type,\n    ...data,\n  };\n\n  // Validation minimale côté serveur\n  if (!type || !data || Object.keys(data).length === 0) {\n    console.warn(`[StructuredData] Missing data for type ${type}`);\n    // En production, envoyer une alerte vers votre monitoring\n    return null;\n  }\n\n  return (\n    \u003Cscript\n      type=\"application/ld+json\"\n      dangerouslySetInnerHTML={{\n        __html: JSON.stringify(jsonLd, null, 0),\n      }}\n    />\n  );\n}\n\n// Usage dans une page de documentation\n\u003CStructuredData\n  type=\"TechArticle\"\n  data={{\n    headline: doc.title,\n    description: doc.excerpt,\n    datePublished: doc.publishedAt,\n    dateModified: doc.updatedAt,\n    author: {\n      \"@type\": \"Organization\",\n      name: \"VotreSaaS\",\n    },\n    proficiencyLevel: \"Advanced\",\n    dependencies: doc.prerequisites?.join(\", \"),\n  }}\n/>\n```\n\nLe `console.warn` en développement est un filet de sécurité minimal. En production, remplacez-le par un envoi vers votre système de monitoring pour détecter les régressions quand un refactoring casse le passage de données au composant — un [pattern de régression fréquent lors des refactos de design system](/blog/design-system-composant-heading-qui-rend-div-selon-la-prop-as-mal-configuree).\n\n## Valider avec Google et au-delà\n\n### Rich Results Test vs. Schema Markup Validator\n\nGoogle propose le [Rich Results Test](https://search.google.com/test/rich-results) pour vérifier quels rich results votre page peut déclencher. Mais cet outil ne teste que les types que Google supporte — il ne vous dira rien sur `TechArticle` ou `SoftwareApplication` au-delà des propriétés que Google utilise.\n\nPour une validation complète de la conformité Schema.org (indépendamment de Google), utilisez le [Schema Markup Validator](https://validator.schema.org/). Il vérifie que vos propriétés correspondent aux spécifications Schema.org, y compris les types et propriétés que Google ignore mais que d'autres consommateurs (Bing, Apple, LLM) pourraient exploiter.\n\n### Vérification dans Search Console\n\nLa Search Console rapporte les types pour lesquels Google génère des rich results dans **Améliorations > [Type]**. Ce rapport montre les erreurs et avertissements par type. Mais il y a un angle mort majeur : si vous implémentez un type que Google ne supporte pas pour les rich results (comme `TechArticle`), il n'apparaîtra nulle part dans la Search Console. Pourtant, Google le crawle, le parse et l'utilise potentiellement dans ses systèmes internes.\n\nLa nouveauté de Google sur les [rapports dédiés à l'AI Search dans la Search Console](/blog/google-tests-dedicated-ai-search-reports-in-search-console-via-sejournal-mattgsouthern) pourrait à terme combler ce vide, en montrant quels types de données structurées alimentent les réponses IA.\n\n### Chrome DevTools pour le debug local\n\nPour vérifier le JSON-LD rendu côté client sans quitter votre navigateur :\n\n```javascript\n// Dans la console Chrome DevTools\nconst scripts = document.querySelectorAll('script[type=\"application/ld+json\"]');\nscripts.forEach((s, i) => {\n  try {\n    const data = JSON.parse(s.textContent);\n    console.group(`JSON-LD Block #${i + 1}: ${data['@type'] || 'Unknown'}`);\n    console.log(JSON.stringify(data, null, 2));\n    \n    // Vérifications basiques\n    if (!data['@context']) console.warn('⚠ Missing @context');\n    if (!data['@type']) console.warn('⚠ Missing @type');\n    if (data['@type'] === 'Product' && !data.offers) console.warn('⚠ Product without offers');\n    if (data['@type'] === 'Article' && !data.datePublished) console.warn('⚠ Article without datePublished');\n    \n    console.groupEnd();\n  } catch (e) {\n    console.error(`JSON-LD Block #${i + 1}: INVALID JSON`, e.message);\n  }\n});\n```\n\nExécutez ce snippet sur chaque template type de votre site. Si vous voyez \"INVALID JSON\" ou des warnings, vous avez un bug de sérialisation à corriger avant que Googlebot ne le rencontre.\n\n## Les limites de ces données d'adoption\n\n### Biais du Common Crawl\n\nLe Common Crawl ne crawle pas le web de manière uniforme. Les sites à forte autorité et avec des sitemaps bien configurés sont sur-représentés. Un site e-commerce de niche avec 500 pages pourrait ne pas figurer dans l'échantillon. Les chiffres d'adoption sont donc des **ordres de grandeur**, pas des valeurs absolues.\n\n### Décalage temporel\n\nLes données Web Data Commons sont publiées avec un décalage de plusieurs mois. Le dernier corpus disponible au moment de la publication de ces statistiques peut dater de 6 à 9 mois. Un type dont l'adoption a explosé récemment (suite à un nouveau rich result Google, par exemple) sera sous-représenté.\n\n### Adoption ≠ qualité\n\nUn type utilisé par 3 millions de domaines ne signifie pas 3 millions d'implémentations correctes. Beaucoup de sites utilisent des plugins WordPress qui génèrent du `Product` avec des champs obligatoires manquants, ou de l'`Article` sans `datePublished`. Les données d'adoption ne distinguent pas une implémentation propre d'un JSON-LD cassé.\n\n## La donnée d'adoption comme outil de priorisation\n\nLa transparence de Schema.org sur l'adoption réelle de chaque type transforme le balisage structuré d'un exercice de foi en une décision data-driven. Pour les équipes SEO qui gèrent des sites à fort volume de pages, la matrice adoption/pertinence permet enfin de prioriser les sprints d'implémentation sur des fondements quantitatifs.\n\nLe risque principal reste les régressions silencieuses : un JSON-LD qui disparaît après un déploiement, un type qui change suite à un refactoring de composant, une API qui timeout et laisse le bloc vide. Seogard détecte ces régressions en comparant le structured data attendu au structured data effectivement servi, page par page, à chaque crawl — le genre de filet de sécurité qui fait la différence entre une stratégie schema documentée et une stratégie schema réellement en production.","https://seogard.io/blog/schema-org-now-shows-you-how-many-sites-are-using-each-schema-type","Actualités SEO","2026-06-11T06:03:12.448Z","2026-06-11","Schema.org expose désormais le nombre de sites utilisant chaque type. Analyse technique, requêtes SPARQL et stratégies pour exploiter ces données d'adoption.","\u003Ch2>Schema.org expose ses données d'adoption — et ça change la donne\u003C/h2>\n\u003Cp>Jusqu'à présent, choisir un type Schema.org relevait d'un mélange de documentation officielle, de reverse-engineering des SERP et d'intuition. Vous implémentiez \u003Ccode>HowTo\u003C/code> ou \u003Ccode>FAQPage\u003C/code> sans savoir si Google voyait ces types sur 500 sites ou 5 millions. Schema.org vient de combler ce vide : chaque page de type affiche désormais le nombre de domaines qui l'utilisent en production, données issues du corpus \u003Ca href=\"https://webdatacommons.org/structureddata/\">Web Data Commons\u003C/a>. Ce n'est pas un gadget cosmétique — c'est la première fois qu'on dispose d'une donnée quantitative fiable pour prioriser son balisage structuré.\u003C/p>\n\u003Ch2>Ce qui a changé concrètement sur Schema.org\u003C/h2>\n\u003Ch3>La nouvelle section \"Usage statistics\"\u003C/h3>\n\u003Cp>Rendez-vous sur n'importe quelle page de type — par exemple \u003Ca href=\"https://schema.org/Product\">https://schema.org/Product\u003C/a>. Sous la description et la hiérarchie de propriétés, une section affiche désormais le nombre de domaines et de pages utilisant ce type, ventilé par format (JSON-LD, Microdata, RDFa).\u003C/p>\n\u003Cp>Ces chiffres ne viennent pas de Google. Ils sont extraits du dataset Web Data Commons, un projet de l'Université de Mannheim qui parse les données structurées sur un échantillon massif du Common Crawl. Le dernier corpus couvre environ 3,3 milliards de pages HTML.\u003C/p>\n\u003Ch3>Ce que les chiffres révèlent (et ce qu'ils cachent)\u003C/h3>\n\u003Cp>Les données exposent deux métriques : \u003Cstrong>le nombre de domaines\u003C/strong> et \u003Cstrong>le nombre de pages\u003C/strong>. La distinction est cruciale. Un e-commerce de 50 000 fiches produit avec \u003Ccode>Product\u003C/code> sur chaque page compte pour un seul domaine mais 50 000 pages. Un réseau de 200 micro-sites avec une seule page \u003Ccode>LocalBusiness\u003C/code> chacun compte pour 200 domaines mais 200 pages.\u003C/p>\n\u003Cp>Limitation importante : le Common Crawl n'est pas un miroir exact du web. Il sous-représente les sites derrière des paywalls, les SPA sans server-side rendering, et les pages profondes nécessitant une authentification. Si votre site SPA sert le JSON-LD uniquement côté client sans SSR, il est probable que le Common Crawl ne le capte pas — tout comme Googlebot dans certaines configurations. Un parallèle direct avec les problèmes de \u003Ca href=\"/blog/lazy-load-du-hero-h1-dans-une-section-v-if-invisible-au-fetch-http-brut\">rendering côté serveur et de contenu invisible au fetch HTTP brut\u003C/a>.\u003C/p>\n\u003Ch3>Format de prédilection : JSON-LD domine\u003C/h3>\n\u003Cp>Les données confirment ce que la communauté SEO technique soupçonnait : JSON-LD est devenu le format dominant pour la plupart des types à forte valeur SEO (\u003Ccode>Product\u003C/code>, \u003Ccode>Article\u003C/code>, \u003Ccode>FAQPage\u003C/code>, \u003Ccode>Organization\u003C/code>). Microdata persiste principalement sur des CMS legacy (WordPress pré-Yoast, Joomla). RDFa est marginal sauf sur certains sites institutionnels.\u003C/p>\n\u003Ch2>Exploiter ces données pour prioriser votre balisage\u003C/h2>\n\u003Ch3>L'arbitrage adoption vs. différenciation\u003C/h3>\n\u003Cp>Le réflexe naturel serait de dire : \"beaucoup de sites utilisent \u003Ccode>Product\u003C/code>, donc je dois l'utiliser aussi.\" C'est vrai pour les types qui déclenchent des rich results — Google ne va pas désactiver les extraits enrichis pour \u003Ccode>Product\u003C/code> quand des millions de sites en dépendent. Le signal est clair : forte adoption = type stable, supporté durablement.\u003C/p>\n\u003Cp>Mais le raisonnement inverse est tout aussi intéressant. Un type peu adopté mais pertinent pour votre secteur représente une opportunité de différenciation dans le Knowledge Graph. Prenez \u003Ccode>MedicalCondition\u003C/code> : si les données montrent quelques milliers de domaines seulement, mais que vous opérez un site santé avec 8 000 pages de conditions médicales, un balisage soigné vous donne un avantage structurel pour l'alimentation des AI Overviews et des panneaux de connaissance.\u003C/p>\n\u003Ch3>Matrice de décision concrète\u003C/h3>\n\u003Cp>Voici comment structurer l'arbitrage pour un e-commerce de 15 000 produits avec un blog de 2 000 articles :\u003C/p>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Type Schema.org\u003C/th>\n\u003Cth>Adoption (domaines)\u003C/th>\n\u003Cth>Rich result Google\u003C/th>\n\u003Cth>Priorité\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Product\u003C/code>\u003C/td>\n\u003Ctd>Très élevée (~3M+)\u003C/td>\n\u003Ctd>Oui (Product snippet)\u003C/td>\n\u003Ctd>\u003Cstrong>P0\u003C/strong> — non négociable\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>Article\u003C/code>\u003C/td>\n\u003Ctd>Très élevée (~5M+)\u003C/td>\n\u003Ctd>Oui (Article snippet)\u003C/td>\n\u003Ctd>\u003Cstrong>P0\u003C/strong> — sur chaque article\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>BreadcrumbList\u003C/code>\u003C/td>\n\u003Ctd>Élevée (~1.5M+)\u003C/td>\n\u003Ctd>Oui (Breadcrumbs SERP)\u003C/td>\n\u003Ctd>\u003Cstrong>P0\u003C/strong> — structure de navigation\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>FAQPage\u003C/code>\u003C/td>\n\u003Ctd>Modérée (~500K)\u003C/td>\n\u003Ctd>Restreint depuis 2023\u003C/td>\n\u003Ctd>\u003Cstrong>P2\u003C/strong> — uniquement si FAQ réelle\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>HowTo\u003C/code>\u003C/td>\n\u003Ctd>Modérée (~300K)\u003C/td>\n\u003Ctd>Restreint depuis 2023\u003C/td>\n\u003Ctd>\u003Cstrong>P2\u003C/strong> — guides pratiques\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>\u003Ccode>SpecialOffer\u003C/code>\u003C/td>\n\u003Ctd>Faible (~10K)\u003C/td>\n\u003Ctd>Non directement\u003C/td>\n\u003Ctd>\u003Cstrong>P1\u003C/strong> — différenciation\u003C/td>\n\u003C/tr>\n\u003C/tbody>\n\u003C/table>\n\u003Cp>Les types \u003Ccode>FAQPage\u003C/code> et \u003Ccode>HowTo\u003C/code> illustrent un point important : Google a \u003Ca href=\"https://developers.google.com/search/docs/appearance/structured-data/faqpage\">restreint leur éligibilité aux rich results en août 2023\u003C/a>, mais ils restent utiles pour alimenter les systèmes d'IA générative. L'adoption modérée signifie que le type est compris et indexé — il vaut le coup si vous avez du \u003Ca href=\"/blog/5-places-to-find-faq-content-that-improves-ai-visibility\">contenu FAQ pertinent\u003C/a>.\u003C/p>\n\u003Ch2>Requêter les données d'adoption par programmation\u003C/h2>\n\u003Cp>Les statistiques affichées sur Schema.org sont utiles pour un check ponctuel. Pour un audit systématique, vous pouvez requêter directement le dataset Web Data Commons via leur endpoint SPARQL ou télécharger les fichiers bruts.\u003C/p>\n\u003Ch3>Accéder au dataset Web Data Commons\u003C/h3>\n\u003Cp>Web Data Commons publie ses extractions sur \u003Ca href=\"https://webdatacommons.org/structureddata/\">webdatacommons.org/structureddata\u003C/a>. Les fichiers sont au format N-Quads, partitionnés par format (JSON-LD, Microdata, RDFa). Pour une analyse ciblée, le plus efficace est d'utiliser le résumé statistique qu'ils publient en TSV.\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 résumé d'adoption par type (JSON-LD)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">curl\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -O\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> https://webdatacommons.org/structureddata/2024-09/stats/schema_org_subsets/jsonld_type_count.tsv\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Filtrer les types Product, Article, FAQPage\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -E\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"^(Product|Article|FAQPage)\\t\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> jsonld_type_count.tsv\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> sort\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -t\u003C/span>\u003Cspan style=\"color:#9ECBFF\">$'\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\t\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -k2\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -rn\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Résultat typique (format : type \\t nombre_de_pages \\t nombre_de_domaines)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Product    287654321    3124567\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Article    412987654    5234891\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># FAQPage     45678901     487234\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Les URLs exactes des fichiers changent à chaque release. Vérifiez toujours la dernière version disponible sur la page du projet.\u003C/p>\n\u003Ch3>Script d'analyse comparative pour votre secteur\u003C/h3>\n\u003Cp>Supposons que vous gérez un site média avec 12 000 articles et que vous voulez comparer votre adoption de types Schema.org avec la moyenne du web. Ce script Python croise votre export Screaming Frog avec les données WDC :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> csv\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">from\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> collections \u003C/span>\u003Cspan style=\"color:#F97583\">import\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> Counter\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># 1. Parser l'export Screaming Frog (colonne \"Structured Data > Type\")\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C/span>\u003Cspan style=\"color:#B392F0\"> parse_screaming_frog_export\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(filepath: \u003C/span>\u003Cspan style=\"color:#79B8FF\">str\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) -> Counter:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    type_counts \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> Counter()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    with\u003C/span>\u003Cspan style=\"color:#79B8FF\"> open\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(filepath, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'r'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#FFAB70\">encoding\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'utf-8'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">as\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> f:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        reader \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> csv.DictReader(f)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">        for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> row \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> reader:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">            sd_types \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> row.get(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'Structured Data 1 > Type'\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:#F97583\">            if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> sd_types:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">                for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> t \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> sd_types.split(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">', '\u003C/span>\u003Cspan style=\"color:#E1E4E8\">):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">                    type_counts[t.strip()] \u003C/span>\u003Cspan style=\"color:#F97583\">+=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 1\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> type_counts\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># 2. Parser le résumé WDC\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">def\u003C/span>\u003Cspan style=\"color:#B392F0\"> parse_wdc_stats\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(filepath: \u003C/span>\u003Cspan style=\"color:#79B8FF\">str\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) -> \u003C/span>\u003Cspan style=\"color:#79B8FF\">dict\u003C/span>\u003Cspan style=\"color:#E1E4E8\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    stats \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    with\u003C/span>\u003Cspan style=\"color:#79B8FF\"> open\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(filepath, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'r'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">) \u003C/span>\u003Cspan style=\"color:#F97583\">as\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> f:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        reader \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> csv.reader(f, \u003C/span>\u003Cspan style=\"color:#FFAB70\">delimiter\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\t\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'\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\"> row \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> reader:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">            if\u003C/span>\u003Cspan style=\"color:#79B8FF\"> len\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(row) \u003C/span>\u003Cspan style=\"color:#F97583\">>=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 3\u003C/span>\u003Cspan style=\"color:#E1E4E8\">:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">                stats[row[\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\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                    'pages'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#79B8FF\">int\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(row[\u003C/span>\u003Cspan style=\"color:#79B8FF\">1\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                    'domains'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#79B8FF\">int\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(row[\u003C/span>\u003Cspan style=\"color:#79B8FF\">2\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\"> stats\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># 3. Comparer\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">my_types \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> parse_screaming_frog_export(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'screaming_frog_export.csv'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">wdc_stats \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> parse_wdc_stats(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'jsonld_type_count.tsv'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">print\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#F97583\">f\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#79B8FF\">{\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'Type'\u003C/span>\u003Cspan style=\"color:#F97583\">:&#x3C;25\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#79B8FF\"> {\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'Vos pages'\u003C/span>\u003Cspan style=\"color:#F97583\">:>12\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#79B8FF\"> {\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'WDC pages'\u003C/span>\u003Cspan style=\"color:#F97583\">:>15\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#79B8FF\"> {\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'WDC domaines'\u003C/span>\u003Cspan style=\"color:#F97583\">:>15\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">print\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"-\"\u003C/span>\u003Cspan style=\"color:#F97583\"> *\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 70\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">for\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> schema_type, count \u003C/span>\u003Cspan style=\"color:#F97583\">in\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> my_types.most_common(\u003C/span>\u003Cspan style=\"color:#79B8FF\">20\u003C/span>\u003Cspan style=\"color:#E1E4E8\">):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    wdc \u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> wdc_stats.get(schema_type, {\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'pages'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#79B8FF\">0\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#9ECBFF\">'domains'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#79B8FF\">0\u003C/span>\u003Cspan style=\"color:#E1E4E8\">})\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">    print\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#F97583\">f\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#79B8FF\">{\u003C/span>\u003Cspan style=\"color:#E1E4E8\">schema_type\u003C/span>\u003Cspan style=\"color:#F97583\">:&#x3C;25\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#79B8FF\"> {\u003C/span>\u003Cspan style=\"color:#E1E4E8\">count\u003C/span>\u003Cspan style=\"color:#F97583\">:>12,\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#79B8FF\"> {\u003C/span>\u003Cspan style=\"color:#E1E4E8\">wdc[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'pages'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]\u003C/span>\u003Cspan style=\"color:#F97583\">:>15,\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#79B8FF\"> {\u003C/span>\u003Cspan style=\"color:#E1E4E8\">wdc[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'domains'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]\u003C/span>\u003Cspan style=\"color:#F97583\">:>15,\u003C/span>\u003Cspan style=\"color:#79B8FF\">}\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">)\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Ce type d'analyse révèle les trous : si votre site média publie 12 000 \u003Ccode>Article\u003C/code> mais zéro \u003Ccode>VideoObject\u003C/code> alors que WDC montre 800K+ domaines avec \u003Ccode>VideoObject\u003C/code>, vous passez peut-être à côté de rich results vidéo sur vos contenus embed.\u003C/p>\n\u003Ch2>Auditer et monitorer votre balisage structuré à l'échelle\u003C/h2>\n\u003Ch3>Validation en masse avec Screaming Frog et jq\u003C/h3>\n\u003Cp>Screaming Frog extrait les données structurées depuis la v17, mais sa sortie est parfois difficile à exploiter programmatiquement. Une approche complémentaire : crawler votre site avec un script qui extrait et valide le JSON-LD brut.\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">#!/bin/bash\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># extract_jsonld.sh — Extraire et valider le JSON-LD de chaque URL d'un sitemap\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">SITEMAP_URL\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"https://www.votresite.fr/sitemap.xml\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\"># Extraire les URLs du sitemap\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:#9ECBFF\"> \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$SITEMAP_URL\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -oP\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> '(?&#x3C;=&#x3C;loc>)[^&#x3C;]+'\u003C/span>\u003Cspan style=\"color:#F97583\"> >\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> urls.txt\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"URL,JSON-LD Types,Validation\"\u003C/span>\u003Cspan style=\"color:#F97583\"> >\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> report.csv\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">while\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> IFS\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#79B8FF\"> read\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -r\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> url\u003C/span>\u003Cspan style=\"color:#E1E4E8\">; \u003C/span>\u003Cspan style=\"color:#F97583\">do\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  # Fetch le HTML (user-agent Googlebot pour cohérence)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  html\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$(\u003C/span>\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)\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\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:#6A737D\">  # Extraire les blocs JSON-LD\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  jsonld\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$(\u003C/span>\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$html\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\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, re, json\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">html = sys.stdin.read()\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">blocks = re.findall(r'&#x3C;script type=\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\">application/ld\\+json\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\">>(.*?)&#x3C;/script>', html, re.DOTALL)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">types = []\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">for b in blocks:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    try:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        data = json.loads(b)\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        if isinstance(data, list):\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            for item in data:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                types.append(item.get('@type', 'UNKNOWN'))\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        else:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">            types.append(data.get('@type', 'UNKNOWN'))\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    except json.JSONDecodeError:\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">        types.append('INVALID_JSON')\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">print(','.join(types) if types else 'NONE')\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\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\">  # Vérifier si le JSON est valide\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  validation\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"OK\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  if\u003C/span>\u003Cspan style=\"color:#79B8FF\"> echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$jsonld\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -q\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"INVALID_JSON\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">; \u003C/span>\u003Cspan style=\"color:#F97583\">then\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    validation\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"ERREUR_JSON\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  elif\u003C/span>\u003Cspan style=\"color:#79B8FF\"> echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$jsonld\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> grep\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -q\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"NONE\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">; \u003C/span>\u003Cspan style=\"color:#F97583\">then\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    validation\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"ABSENT\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  fi\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">  echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$url\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\">,\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$jsonld\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\">,\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">$validation\u003C/span>\u003Cspan style=\"color:#79B8FF\">\\\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"\u003C/span>\u003Cspan style=\"color:#F97583\"> >>\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> report.csv\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">done\u003C/span>\u003Cspan style=\"color:#F97583\"> &#x3C;\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> urls.txt\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Rapport généré : report.csv\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Pages sans JSON-LD :\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"ABSENT\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> report.csv\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> wc\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -l\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#79B8FF\">echo\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"Pages avec JSON invalide :\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">grep\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"ERREUR_JSON\"\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> report.csv\u003C/span>\u003Cspan style=\"color:#F97583\"> |\u003C/span>\u003Cspan style=\"color:#B392F0\"> wc\u003C/span>\u003Cspan style=\"color:#79B8FF\"> -l\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Sur un site e-commerce de 15 000 pages, ce script (exécuté en parallèle avec \u003Ccode>xargs -P 10\u003C/code>) prend environ 45 minutes. Le rapport CSV révèle immédiatement les pages où le JSON-LD est absent (template mal configuré), invalide (virgule trailing, guillemets non échappés), ou utilisant un type inattendu.\u003C/p>\n\u003Ch3>Le piège du JSON-LD dynamique\u003C/h3>\n\u003Cp>Sur les stacks JavaScript modernes (Next.js, Nuxt, SvelteKit), le JSON-LD est souvent généré dynamiquement. Le problème classique : le bloc \u003Ccode>&#x3C;script type=\"application/ld+json\">\u003C/code> dépend de données async qui peuvent échouer silencieusement.\u003C/p>\n\u003Cp>Exemple concret sur Next.js App Router :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// app/products/[slug]/page.tsx\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">export\u003C/span>\u003Cspan style=\"color:#F97583\"> default\u003C/span>\u003Cspan style=\"color:#F97583\"> async\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> ProductPage\u003C/span>\u003Cspan style=\"color:#E1E4E8\">({ \u003C/span>\u003Cspan style=\"color:#FFAB70\">params\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> }\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { \u003C/span>\u003Cspan style=\"color:#FFAB70\">params\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> { \u003C/span>\u003Cspan style=\"color:#FFAB70\">slug\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> string\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> } }) {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  const\u003C/span>\u003Cspan style=\"color:#79B8FF\"> product\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#F97583\"> await\u003C/span>\u003Cspan style=\"color:#B392F0\"> getProduct\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(params.slug);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  // Si getProduct retourne null (API timeout, 404, etc.),\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">  // le JSON-LD n'est pas rendu — SANS erreur visible\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">  return\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {product \u003C/span>\u003Cspan style=\"color:#F97583\">&#x26;&#x26;\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\">script\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">          type\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"application/ld+json\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">          dangerouslySetInnerHTML\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">{{\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">            __html: \u003C/span>\u003Cspan style=\"color:#79B8FF\">JSON\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">stringify\u003C/span>\u003Cspan style=\"color:#E1E4E8\">({\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">              \"@context\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"https://schema.org\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">              \"@type\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"Product\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">              \"name\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: product.name,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">              \"description\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: product.description,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">              \"sku\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: product.sku,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">              \"offers\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                \"@type\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"Offer\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                \"price\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: product.price,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                \"priceCurrency\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"EUR\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                \"availability\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: product.inStock \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">                  ?\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"https://schema.org/InStock\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> \u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">                  :\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> \"https://schema.org/OutOfStock\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">              },\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">              \"aggregateRating\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: product.reviews?.\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:#F97583\"> ?\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                \"@type\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"AggregateRating\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                \"ratingValue\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: product.averageRating,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">                \"reviewCount\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: product.reviews.\u003C/span>\u003Cspan style=\"color:#79B8FF\">length\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">              } \u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#79B8FF\"> undefined\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\">      )}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      {\u003C/span>\u003Cspan style=\"color:#6A737D\">/* reste du composant */\u003C/span>\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    &#x3C;/>\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  );\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">}\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Le problème : si \u003Ccode>getProduct\u003C/code> échoue sur 3 % de vos 15 000 pages produit à cause de timeouts API intermittents, vous avez 450 pages sans JSON-LD \u003Ccode>Product\u003C/code>. Googlebot ne va pas vous alerter. La Search Console montre uniquement les erreurs de structure sur les pages \u003Cstrong>où elle détecte\u003C/strong> du structured data — pas les pages où il manque. Ce type de régression silencieuse est exactement ce que détecte un outil de monitoring continu comme Seogard : il compare le JSON-LD attendu au JSON-LD réellement servi sur chaque URL crawlée, et alerte quand un bloc disparaît.\u003C/p>\n\u003Cp>Ce genre de bug côté metadata rejoint une classe d'erreurs documentée sur les frameworks modernes. Les \u003Ca href=\"/blog/next-js-metadata-async-qui-throw-la-page-sert-le-fallback-default-next-js\">metadata async qui throw silencieusement sur Next.js\u003C/a> ou les \u003Ca href=\"/blog/nuxt-useseometa-le-child-override-silencieusement-les-meta-du-layout-parent\">override silencieux de useSeometa sur Nuxt\u003C/a> suivent exactement le même pattern : pas d'erreur visible, pas d'alerte framework, mais un impact SEO cumulatif.\u003C/p>\n\u003Ch2>Stratégie : utiliser les données d'adoption pour l'AI visibility\u003C/h2>\n\u003Ch3>Le lien entre structured data et systèmes génératifs\u003C/h3>\n\u003Cp>Les AI Overviews de Google et les systèmes comme Perplexity ou ChatGPT Search consomment les données structurées pour construire leurs réponses. La différence avec les rich results classiques : les systèmes d'IA n'ont pas besoin que Google \"supporte\" officiellement un type pour l'exploiter. Un \u003Ccode>SoftwareApplication\u003C/code> bien balisé avec \u003Ccode>applicationCategory\u003C/code>, \u003Ccode>operatingSystem\u003C/code> et \u003Ccode>offers\u003C/code> peut alimenter une réponse IA même si Google n'affiche pas de rich result dédié en SERP.\u003C/p>\n\u003Cp>Les données d'adoption de Schema.org deviennent un signal stratégique : si un type est largement adopté, les systèmes d'IA ont été entraînés sur suffisamment d'exemples pour le comprendre de manière fiable. À l'inverse, un type confidentiel avec moins de 1 000 domaines risque d'être mal interprété ou ignoré.\u003C/p>\n\u003Cp>Ce raisonnement s'inscrit dans la tendance plus large de visibilité auprès des agents IA, un sujet sur lequel \u003Ca href=\"/blog/your-next-ai-visitor-will-know-who-sent-it-via-sejournal-slobodanmanic\">l'identification des visiteurs IA et de leur provenance\u003C/a> devient un enjeu de mesure, et où \u003Ca href=\"/blog/entitymap-the-open-standard-that-gives-ai-systems-a-structured-view-of-your-business-via-sejournal-dixon-jones\">le standard EntityMap propose une vue structurée de votre activité pour les systèmes IA\u003C/a>.\u003C/p>\n\u003Ch3>Cas concret : un site SaaS B2B de 800 pages\u003C/h3>\n\u003Cp>Prenons un éditeur SaaS B2B avec :\u003C/p>\n\u003Cul>\n\u003Cli>1 page produit principale\u003C/li>\n\u003Cli>120 pages de fonctionnalités\u003C/li>\n\u003Cli>45 pages de tarifs/plans\u003C/li>\n\u003Cli>200 articles de blog\u003C/li>\n\u003Cli>80 pages de documentation\u003C/li>\n\u003Cli>30 pages de cas clients\u003C/li>\n\u003Cli>~325 pages légales, carrières, landing pages diverses\u003C/li>\n\u003C/ul>\n\u003Cp>Avant les données d'adoption Schema.org, l'équipe SEO balisait principalement \u003Ccode>Organization\u003C/code> (homepage), \u003Ccode>Article\u003C/code> (blog) et \u003Ccode>BreadcrumbList\u003C/code> (toutes pages). Avec les données d'adoption, l'audit révèle des opportunités négligées :\u003C/p>\n\u003Ctable>\n\u003Cthead>\n\u003Ctr>\n\u003Cth>Page type\u003C/th>\n\u003Cth>Type Schema actuel\u003C/th>\n\u003Cth>Type Schema recommandé\u003C/th>\n\u003Cth>Adoption WDC\u003C/th>\n\u003C/tr>\n\u003C/thead>\n\u003Ctbody>\n\u003Ctr>\n\u003Ctd>Fonctionnalités\u003C/td>\n\u003Ctd>Aucun\u003C/td>\n\u003Ctd>\u003Ccode>SoftwareApplication\u003C/code>\u003C/td>\n\u003Ctd>~180K domaines\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Cas clients\u003C/td>\n\u003Ctd>\u003Ccode>Article\u003C/code>\u003C/td>\n\u003Ctd>\u003Ccode>Review\u003C/code> + \u003Ccode>Organization\u003C/code>\u003C/td>\n\u003Ctd>~900K domaines\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Documentation\u003C/td>\n\u003Ctd>Aucun\u003C/td>\n\u003Ctd>\u003Ccode>TechArticle\u003C/code>\u003C/td>\n\u003Ctd>~25K domaines\u003C/td>\n\u003C/tr>\n\u003Ctr>\n\u003Ctd>Tarifs\u003C/td>\n\u003Ctd>Aucun\u003C/td>\n\u003Ctd>\u003Ccode>Offer\u003C/code> + \u003Ccode>SoftwareApplication\u003C/code>\u003C/td>\n\u003Ctd>~2.5M (Offer)\u003C/td>\n\u003C/tr>\n\u003C/tbody>\n\u003C/table>\n\u003Cp>\u003Ccode>TechArticle\u003C/code> avec seulement ~25K domaines est un pari : faible adoption signifie que les AI systems ont moins de données d'entraînement sur ce type. Mais pour un site de documentation technique, la pertinence sémantique est maximale. Le trade-off penche vers l'implémentation — le coût est faible (quelques lignes JSON-LD), et le signal de pertinence pour les LLM qui parcourent votre doc est réel.\u003C/p>\n\u003Ch3>Implémenter le JSON-LD conditionnel par template\u003C/h3>\n\u003Cp>Pour un site de cette taille, l'approche la plus maintenable est un composant centralisé qui reçoit le type et les données en props :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// components/StructuredData.tsx\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">interface\u003C/span>\u003Cspan style=\"color:#B392F0\"> StructuredDataProps\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#FFAB70\">  type\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\">  data\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#B392F0\"> Record\u003C/span>\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#79B8FF\">string\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#79B8FF\">unknown\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\">export\u003C/span>\u003Cspan style=\"color:#F97583\"> function\u003C/span>\u003Cspan style=\"color:#B392F0\"> StructuredData\u003C/span>\u003Cspan style=\"color:#E1E4E8\">({ \u003C/span>\u003Cspan style=\"color:#FFAB70\">type\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#FFAB70\">data\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> }\u003C/span>\u003Cspan style=\"color:#F97583\">:\u003C/span>\u003Cspan style=\"color:#B392F0\"> StructuredDataProps\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\"> jsonLd\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"@context\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"https://schema.org\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">    \"@type\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: type,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    ...\u003C/span>\u003Cspan style=\"color:#E1E4E8\">data,\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\">  // Validation minimale côté serveur\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\">type \u003C/span>\u003Cspan style=\"color:#F97583\">||\u003C/span>\u003Cspan style=\"color:#F97583\"> !\u003C/span>\u003Cspan style=\"color:#E1E4E8\">data \u003C/span>\u003Cspan style=\"color:#F97583\">||\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> Object.\u003C/span>\u003Cspan style=\"color:#B392F0\">keys\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(data).\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\">    console.\u003C/span>\u003Cspan style=\"color:#B392F0\">warn\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`[StructuredData] Missing data for type ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">type\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">    // En production, envoyer une alerte vers votre monitoring\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    return\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\">  }\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\">    &#x3C;\u003C/span>\u003Cspan style=\"color:#85E89D\">script\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">      type\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"application/ld+json\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">      dangerouslySetInnerHTML\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">{{\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">        __html: \u003C/span>\u003Cspan style=\"color:#79B8FF\">JSON\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">stringify\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(jsonLd, \u003C/span>\u003Cspan style=\"color:#79B8FF\">null\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \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\">\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:#6A737D\">// Usage dans une page de documentation\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">&#x3C;\u003C/span>\u003Cspan style=\"color:#79B8FF\">StructuredData\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  type\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"TechArticle\"\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#B392F0\">  data\u003C/span>\u003Cspan style=\"color:#F97583\">=\u003C/span>\u003Cspan style=\"color:#E1E4E8\">{{\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    headline: doc.title,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    description: doc.excerpt,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    datePublished: doc.publishedAt,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    dateModified: doc.updatedAt,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    author: {\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#9ECBFF\">      \"@type\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"Organization\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">      name: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"VotreSaaS\"\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\">    proficiencyLevel: \u003C/span>\u003Cspan style=\"color:#9ECBFF\">\"Advanced\"\u003C/span>\u003Cspan style=\"color:#E1E4E8\">,\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    dependencies: doc.prerequisites?.\u003C/span>\u003Cspan style=\"color:#B392F0\">join\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:#E1E4E8\">  }}\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">/>\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Le \u003Ccode>console.warn\u003C/code> en développement est un filet de sécurité minimal. En production, remplacez-le par un envoi vers votre système de monitoring pour détecter les régressions quand un refactoring casse le passage de données au composant — un \u003Ca href=\"/blog/design-system-composant-heading-qui-rend-div-selon-la-prop-as-mal-configuree\">pattern de régression fréquent lors des refactos de design system\u003C/a>.\u003C/p>\n\u003Ch2>Valider avec Google et au-delà\u003C/h2>\n\u003Ch3>Rich Results Test vs. Schema Markup Validator\u003C/h3>\n\u003Cp>Google propose le \u003Ca href=\"https://search.google.com/test/rich-results\">Rich Results Test\u003C/a> pour vérifier quels rich results votre page peut déclencher. Mais cet outil ne teste que les types que Google supporte — il ne vous dira rien sur \u003Ccode>TechArticle\u003C/code> ou \u003Ccode>SoftwareApplication\u003C/code> au-delà des propriétés que Google utilise.\u003C/p>\n\u003Cp>Pour une validation complète de la conformité Schema.org (indépendamment de Google), utilisez le \u003Ca href=\"https://validator.schema.org/\">Schema Markup Validator\u003C/a>. Il vérifie que vos propriétés correspondent aux spécifications Schema.org, y compris les types et propriétés que Google ignore mais que d'autres consommateurs (Bing, Apple, LLM) pourraient exploiter.\u003C/p>\n\u003Ch3>Vérification dans Search Console\u003C/h3>\n\u003Cp>La Search Console rapporte les types pour lesquels Google génère des rich results dans \u003Cstrong>Améliorations > [Type]\u003C/strong>. Ce rapport montre les erreurs et avertissements par type. Mais il y a un angle mort majeur : si vous implémentez un type que Google ne supporte pas pour les rich results (comme \u003Ccode>TechArticle\u003C/code>), il n'apparaîtra nulle part dans la Search Console. Pourtant, Google le crawle, le parse et l'utilise potentiellement dans ses systèmes internes.\u003C/p>\n\u003Cp>La nouveauté de Google sur les \u003Ca href=\"/blog/google-tests-dedicated-ai-search-reports-in-search-console-via-sejournal-mattgsouthern\">rapports dédiés à l'AI Search dans la Search Console\u003C/a> pourrait à terme combler ce vide, en montrant quels types de données structurées alimentent les réponses IA.\u003C/p>\n\u003Ch3>Chrome DevTools pour le debug local\u003C/h3>\n\u003Cp>Pour vérifier le JSON-LD rendu côté client sans quitter votre navigateur :\u003C/p>\n\u003Cpre class=\"shiki github-dark\" style=\"background-color:#24292e;color:#e1e4e8\" tabindex=\"0\">\u003Ccode>\u003Cspan class=\"line\">\u003Cspan style=\"color:#6A737D\">// Dans la console Chrome DevTools\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\"> document.\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\">\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:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#FFAB70\">i\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\">  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\"> data\u003C/span>\u003Cspan style=\"color:#F97583\"> =\u003C/span>\u003Cspan style=\"color:#79B8FF\"> JSON\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">parse\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(s.textContent);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    console.\u003C/span>\u003Cspan style=\"color:#B392F0\">group\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">`JSON-LD Block #${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">i\u003C/span>\u003Cspan style=\"color:#F97583\"> +\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 1\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}: ${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">data\u003C/span>\u003Cspan style=\"color:#9ECBFF\">[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'@type'\u003C/span>\u003Cspan style=\"color:#9ECBFF\">] \u003C/span>\u003Cspan style=\"color:#F97583\">||\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'Unknown'}`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">    console.\u003C/span>\u003Cspan style=\"color:#B392F0\">log\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#79B8FF\">JSON\u003C/span>\u003Cspan style=\"color:#E1E4E8\">.\u003C/span>\u003Cspan style=\"color:#B392F0\">stringify\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(data, \u003C/span>\u003Cspan style=\"color:#79B8FF\">null\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, \u003C/span>\u003Cspan style=\"color:#79B8FF\">2\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\">    // Vérifications basiques\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\">data[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'@context'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]) console.\u003C/span>\u003Cspan style=\"color:#B392F0\">warn\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'⚠ Missing @context'\u003C/span>\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\">data[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'@type'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">]) console.\u003C/span>\u003Cspan style=\"color:#B392F0\">warn\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'⚠ Missing @type'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (data[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'@type'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">===\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'Product'\u003C/span>\u003Cspan style=\"color:#F97583\"> &#x26;&#x26;\u003C/span>\u003Cspan style=\"color:#F97583\"> !\u003C/span>\u003Cspan style=\"color:#E1E4E8\">data.offers) console.\u003C/span>\u003Cspan style=\"color:#B392F0\">warn\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'⚠ Product without offers'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#F97583\">    if\u003C/span>\u003Cspan style=\"color:#E1E4E8\"> (data[\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'@type'\u003C/span>\u003Cspan style=\"color:#E1E4E8\">] \u003C/span>\u003Cspan style=\"color:#F97583\">===\u003C/span>\u003Cspan style=\"color:#9ECBFF\"> 'Article'\u003C/span>\u003Cspan style=\"color:#F97583\"> &#x26;&#x26;\u003C/span>\u003Cspan style=\"color:#F97583\"> !\u003C/span>\u003Cspan style=\"color:#E1E4E8\">data.datePublished) console.\u003C/span>\u003Cspan style=\"color:#B392F0\">warn\u003C/span>\u003Cspan style=\"color:#E1E4E8\">(\u003C/span>\u003Cspan style=\"color:#9ECBFF\">'⚠ Article without datePublished'\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\">    console.\u003C/span>\u003Cspan style=\"color:#B392F0\">groupEnd\u003C/span>\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\">`JSON-LD Block #${\u003C/span>\u003Cspan style=\"color:#E1E4E8\">i\u003C/span>\u003Cspan style=\"color:#F97583\"> +\u003C/span>\u003Cspan style=\"color:#79B8FF\"> 1\u003C/span>\u003Cspan style=\"color:#9ECBFF\">}: INVALID JSON`\u003C/span>\u003Cspan style=\"color:#E1E4E8\">, e.message);\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">  }\u003C/span>\u003C/span>\n\u003Cspan class=\"line\">\u003Cspan style=\"color:#E1E4E8\">});\u003C/span>\u003C/span>\u003C/code>\u003C/pre>\n\u003Cp>Exécutez ce snippet sur chaque template type de votre site. Si vous voyez \"INVALID JSON\" ou des warnings, vous avez un bug de sérialisation à corriger avant que Googlebot ne le rencontre.\u003C/p>\n\u003Ch2>Les limites de ces données d'adoption\u003C/h2>\n\u003Ch3>Biais du Common Crawl\u003C/h3>\n\u003Cp>Le Common Crawl ne crawle pas le web de manière uniforme. Les sites à forte autorité et avec des sitemaps bien configurés sont sur-représentés. Un site e-commerce de niche avec 500 pages pourrait ne pas figurer dans l'échantillon. Les chiffres d'adoption sont donc des \u003Cstrong>ordres de grandeur\u003C/strong>, pas des valeurs absolues.\u003C/p>\n\u003Ch3>Décalage temporel\u003C/h3>\n\u003Cp>Les données Web Data Commons sont publiées avec un décalage de plusieurs mois. Le dernier corpus disponible au moment de la publication de ces statistiques peut dater de 6 à 9 mois. Un type dont l'adoption a explosé récemment (suite à un nouveau rich result Google, par exemple) sera sous-représenté.\u003C/p>\n\u003Ch3>Adoption ≠ qualité\u003C/h3>\n\u003Cp>Un type utilisé par 3 millions de domaines ne signifie pas 3 millions d'implémentations correctes. Beaucoup de sites utilisent des plugins WordPress qui génèrent du \u003Ccode>Product\u003C/code> avec des champs obligatoires manquants, ou de l'\u003Ccode>Article\u003C/code> sans \u003Ccode>datePublished\u003C/code>. Les données d'adoption ne distinguent pas une implémentation propre d'un JSON-LD cassé.\u003C/p>\n\u003Ch2>La donnée d'adoption comme outil de priorisation\u003C/h2>\n\u003Cp>La transparence de Schema.org sur l'adoption réelle de chaque type transforme le balisage structuré d'un exercice de foi en une décision data-driven. Pour les équipes SEO qui gèrent des sites à fort volume de pages, la matrice adoption/pertinence permet enfin de prioriser les sprints d'implémentation sur des fondements quantitatifs.\u003C/p>\n\u003Cp>Le risque principal reste les régressions silencieuses : un JSON-LD qui disparaît après un déploiement, un type qui change suite à un refactoring de composant, une API qui timeout et laisse le bloc vide. Seogard détecte ces régressions en comparant le structured data attendu au structured data effectivement servi, page par page, à chaque crawl — le genre de filet de sécurité qui fait la différence entre une stratégie schema documentée et une stratégie schema réellement en production.\u003C/p>",null,12,[18,19,20,21,22],"schema","structured-data","schema.org","json-ld","seo-technique","Schema.org affiche l'adoption réelle de chaque type : exploitez ces données","Thu Jun 11 2026 06:03:12 GMT+0000 (Coordinated Universal Time)",[26,41,56,71,84,99],{"_id":27,"slug":28,"__v":6,"author":7,"canonical":29,"category":10,"createdAt":30,"date":31,"description":32,"image":15,"imageAlt":15,"readingTime":16,"tags":33,"title":39,"updatedAt":40},"6a3238a5aa6b273b0c4e69eb","bing-rolls-out-ai-citation-share-in-webmaster-tools-via-sejournal-mattgsouthern","https://seogard.io/blog/bing-rolls-out-ai-citation-share-in-webmaster-tools-via-sejournal-mattgsouthern","2026-06-17T06:03:17.202Z","2026-06-17","Analyse technique du nouveau Citation Share dans Bing Webmaster Tools. Métriques AI, impact sur le trafic, et stratégies d'optimisation concrètes.",[34,35,36,37,38],"bing","citation share","webmaster tools","AI search","SEO technique","Bing AI Citation Share : ce que ça change pour le SEO technique","Wed Jun 17 2026 06:03:17 GMT+0000 (Coordinated Universal Time)",{"_id":42,"slug":43,"__v":6,"author":7,"canonical":44,"category":10,"createdAt":45,"date":46,"description":47,"image":15,"imageAlt":15,"readingTime":16,"tags":48,"title":54,"updatedAt":55},"6a30222eaa6b273b0ca1e7dc","what-ai-overview-click-data-reveals-about-consumer-search-behavior-5-strategic-insights-for-cmos-via-sejournal-gregjarboe","https://seogard.io/blog/what-ai-overview-click-data-reveals-about-consumer-search-behavior-5-strategic-insights-for-cmos-via-sejournal-gregjarboe","2026-06-15T16:02:54.519Z","2026-06-15","Les utilisateurs quotidiens d'AI Overview cliquent 3.5x plus sur les sources. Analyse technique des données et stratégies d'optimisation concrètes.",[49,50,51,52,53],"AI Overview","click data","search behavior","SGE","structured data","AI Overview Click Data : ce que les clics révèlent vraiment","Mon Jun 15 2026 16:02:54 GMT+0000 (Coordinated Universal Time)",{"_id":57,"slug":58,"__v":6,"author":7,"canonical":59,"category":10,"createdAt":60,"date":61,"description":62,"image":15,"imageAlt":15,"readingTime":16,"tags":63,"title":69,"updatedAt":70},"6a2e441caa6b273b0c22bc85","what-apple-s-gemini-powered-siri-means-for-search-visibility-via-sejournal-mattgsouthern","https://seogard.io/blog/what-apple-s-gemini-powered-siri-means-for-search-visibility-via-sejournal-mattgsouthern","2026-06-14T06:03:08.037Z","2026-06-14","Apple intègre Gemini dans Siri. Analyse technique des conséquences pour le crawl, le rendering, le structured data et la visibilité organique de vos pages.",[64,65,66,67,68],"siri","gemini","apple-intelligence","llm-seo","search-visibility","Siri + Gemini : impact concret sur la visibilité SEO","Sun Jun 14 2026 06:03:08 GMT+0000 (Coordinated Universal Time)",{"_id":72,"slug":73,"__v":6,"author":7,"canonical":74,"category":10,"createdAt":75,"date":76,"description":77,"image":15,"imageAlt":15,"readingTime":16,"tags":78,"title":82,"updatedAt":83},"6a2c2decaa6b273b0c6a5308","ai-overview-click-data-reveals-unexpected-user-behavior-patterns-for-marketers-via-sejournal-gregjarboe","https://seogard.io/blog/ai-overview-click-data-reveals-unexpected-user-behavior-patterns-for-marketers-via-sejournal-gregjarboe","2026-06-12T16:03:56.058Z","2026-06-12","Les utilisateurs quotidiens d'AI Overviews cliquent 3,5x plus sur les sources. Analyse technique des opportunités d'optimisation pour les sites à fort volume.",[79,50,80,81,53],"ai overview","seo technique","google search","AI Overviews : les données de clics révèlent un comportement inattendu","Fri Jun 12 2026 16:03:56 GMT+0000 (Coordinated Universal Time)",{"_id":85,"slug":86,"__v":6,"author":7,"canonical":87,"category":10,"createdAt":88,"date":89,"description":90,"image":15,"imageAlt":15,"readingTime":91,"tags":92,"title":97,"updatedAt":98},"6a283936aa6b273b0c255fdd","how-ai-forms-opinions-about-your-brand","https://seogard.io/blog/how-ai-forms-opinions-about-your-brand","2026-06-09T16:03:02.486Z","2026-06-09","Construisez une empreinte numérique que les LLMs comprennent : structured data, entités, corpus de citations. Guide technique pour Lead SEO.",14,[93,94,53,95,96],"AI visibility","brand authority","LLM optimization","entity SEO","Comment l'IA se forge une opinion sur votre marque","Tue Jun 09 2026 16:03:02 GMT+0000 (Coordinated Universal Time)",{"_id":100,"slug":101,"__v":6,"author":7,"canonical":102,"category":10,"createdAt":103,"date":104,"description":105,"image":15,"imageAlt":15,"readingTime":16,"tags":106,"title":110,"updatedAt":111},"6a265b17aa6b273b0c9a6fff","your-next-ai-visitor-will-know-who-sent-it-via-sejournal-slobodanmanic","https://seogard.io/blog/your-next-ai-visitor-will-know-who-sent-it-via-sejournal-slobodanmanic","2026-06-08T06:03:03.429Z","2026-06-08","Les agents AI arrivent avec le contexte utilisateur. Comment adapter votre contenu pour rester utile face au blended retrieval.",[107,108,38,109,53],"AI agents","blended retrieval","crawl AI","AI Visitors contextuels : préparer vos pages au blended retrieval","Mon Jun 08 2026 06:03:03 GMT+0000 (Coordinated Universal Time)",{"categories":113},[114,117,121,125,129,132,136,139,141,145,149,152,154,158,161,164,167,170,174,177],{"category":10,"slug":115,"count":116},"actualites-seo",169,{"category":118,"slug":119,"count":120},"Migration","migration",18,{"category":122,"slug":123,"count":124},"Rendering","rendering",9,{"category":126,"slug":127,"count":128},"Framework","framework",8,{"category":130,"slug":131,"count":128},"Performance","performance",{"category":133,"slug":134,"count":135},"Crawl","crawl",7,{"category":137,"slug":138,"count":135},"Meta Tags","meta-tags",{"category":140,"slug":22,"count":135},"SEO Technique",{"category":142,"slug":143,"count":144},"Architecture","architecture",6,{"category":146,"slug":147,"count":148},"Monitoring","monitoring",5,{"category":150,"slug":151,"count":148},"JavaScript SEO","javascript-seo",{"category":153,"slug":19,"count":148},"Structured Data",{"category":155,"slug":156,"count":157},"Outils","outils",4,{"category":159,"slug":160,"count":157},"Avancé","avance",{"category":162,"slug":163,"count":157},"Redirections","redirections",{"category":165,"slug":166,"count":157},"Refonte","refonte",{"category":168,"slug":169,"count":157},"E-commerce","e-commerce",{"category":171,"slug":172,"count":173},"Contenu","contenu",3,{"category":175,"slug":176,"count":173},"Headless","headless",{"category":178,"slug":179,"count":173},"IA & SEO","ia-seo"]