Guide Sanity SEO

Sanity stores contenu as JSON et emits zero HTML — votre frontend decides votre SEO. Rendu modes, Portable Texte, le SEO object, sitemaps, draft-mode noindex, JSON-LD, et plugins.

Première publication : 27 juin 2026 · Dernière mise à jour : 3 août 2026 · Avancé

Sanity est a CMS headless que stores contenu as structured JSON dans son Contenu Lake et produces aucun HTML — donc votre frontend framework (Suivant.js, Astro, Remix) decides tout à propos de votre SEO. Le unique biggest lever est rendu: SSG et SSR ship complet HTML et sont sûr; CSR est risky parce que LLM-robot rendu contracts vary par provider. Portable Texte est a JSON AST, pas HTML, donc le frontend doit serialize il. Construire a reusable SEO object dans le contenu model, generate sitemaps et JSON-LD programmatically, garder drafts out de le indexer avec an X-Robots-Balise: noindex header, et utiliser sanity-plugin-seo (pas le deprecated Yoast pane). SEO success dans Sanity comes depuis intentional structure, pas plugins.

TL;DR — Sanity est contenu-neutral: il stores structured JSON dans le contenu Lake et emits zero HTML, donc le frontend’s rendu mode decides tout. SSG et SSR ship complet HTML et sont sûr; CSR est le risky un parce que LLM robots d’exploration ne pas execute JavaScript, et Google deprecated dynamic rendu as a workaround. Portable Texte est a JSON AST que le frontend doit serialize. Construire a reusable seo object dans le contenu model avec overrides (pas requirements) via coalesce(), generate sitemaps et JSON-LD programmatically depuis existing champs, et garder drafts out de le indexer avec an X-Robots-Tag: noindex header on chaque preview réponse. Utiliser sanity-plugin-seo — jamais le deprecated Yoast pane — mais remember “SEO success dans Sanity comes depuis intentional structure, pas plugins.”

Sanity is content storage, pas a publisher

A utile premier principle: Sanity touches votre contenu, jamais votre rendu. Le contenu Lake stores tout as structured JSON, queried avec GROQ (Sanity’s requête langue) or REST. Sanity Studio — le editing UI — est a React unique-page app que généralement lives on son propre .sanity.studio subdomain et n’est pas quelque chose vous indexer. Rien dans ce stack produces HTML.

Preuve à l’appui de cette affirmation Sanity Content Lake is queried using APIs and GROQ; it is distinct from a site's frontend rendering layer. Portée : Sanity-hosted content data and query APIs. Niveau de confiance : élevé · Vérifié : Sanity: Content Lake

«So the entire SEO surface lives in your frontend framework. As Webstacks put it, “Sanity handles content storage and editing, while your frontend framework handles SEO output.” That’s not a limitation — it’s the whole headless model. Sanity’s own team frames it well: “When using Sanity as a CMS, you’re doing headless SEO. Although this approach requires thoughtful technical implementation, it can liberate your content to help you reach more users across all channels.” The work is real, but it’s the same work as any headless build (see SEO for a Headless CMS). » (Traduction) (Résumé en français de la section vingt-trois, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

Rendu mode est le foundation

Parce que le frontend construit le HTML, le rendu décision est le unique la plupart consequential SEO choice on a Sanity site. Four modes:

SSG — Static Site Generation. Contenu est récupéré depuis Sanity à construire temps et baked dans static HTML servi depuis a CDN. Meilleur-case SEO: fully-rendu HTML on premier requête, rapide TTFB. Ideal pour blog posts, marketing pages, et produit/landing pages. Le tradeoff est freshness — modifié contenu nécessite a rebuild (ISR solves ce).

SSR — Rendu côté serveur. Contenu est récupéré per requête et le complet HTML est rendu on le serveur. Excellent SEO, toujours fresh. Utiliser il pour frequently mis à jour contenu. Tradeoff est infrastructure coût et slightly plus élevé TTFB que static fichiers.

ISR — Incremental Static Regeneration (Vercel/Suivant.js). Static pages regenerate dans le background, ideally triggered par a Sanity webhook on publish donc lune page rebuilds le moment an editor hits publish. Ce est le meilleur de SSG’s speed et SSR’s freshness pour contenu que changements on le order de hours or days.

CSR — Rendu côté client. An HTML shell ships, alors JavaScript récupère depuis Sanity et construit le DOM dans le navigateur. Ce est le worst SEO option: Googlebot a à queue lune page pour a plus tard rendre wave, timing est unpredictable, et AI robots d’exploration et nombreux autre bots voir seulement le shell. CSR est acceptable seulement behind authentication pour contenu vous ne pas vouloir indexé anyway.

«And don’t reach for the old shortcut: Google has deprecated dynamic rendering (serving prerendered HTML to bots, CSR to users). Officially, “dynamic rendering was a workaround and not a long-term solution,” and Google now recommends “server-side rendering, static rendering, or hydration.” For a Sanity site, that means SSG or SSR — not a bot-detection hack. (Full rendering treatment in JavaScript SEO.)

Preuve à l’appui de cette affirmation Google describes dynamic rendering as a workaround rather than a recommended long-term solution and recommends server-side rendering, static rendering, or hydration. Portée : Google Search guidance for JavaScript sites. Niveau de confiance : élevé · Vérifié : Google: Dynamic rendering

» (Traduction) (Résumé en français de la section trente, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

Portable Text — votre corps copy is a JSON AST

Ce est le la plupart Sanity-spécifique chose on lune page. Sanity stores rich texte as Portable Texte: a JSON abstract syntax tree, pas HTML. Corps copy dans le contenu Lake semble comme an array de typed bloque, pas <p> balises. Votre frontend a à serialize il dans HTML avant quelconque robot d’exploration peut lire il:

  • @portabletext/react — pour React/Suivant.js.
  • @portabletext/to-html — framework-agnostic (Astro, Remix, n’importe quoi).
  • Le old @sanity/block-content-to-react est deprecated — ne pas utiliser il.

Si vous rendre serveur-side or à construire temps, serialization se produit avant lune page est sent et robots d’exploration obtenir complet HTML. Si vous rendre client-side, le serialization exécute dans le navigateur. Parce que LLM-robot rendu contracts vary par provider, CSR Portable Texte crée a coverage risque que raw HTML avoids. il y a aussi a handy GROQ helper: pt::text(body) extracts tout le plain texte depuis a Portable Texte champ as a string, qui est perfect pour feeding JSON-LD descriptions sans a séparé editor champ.

Contenu modeling pour le SEO — le reusable SEO object

«The cleanest pattern, and the one Sanity’s own course teaches, is a single reusable seo object added to every document type — not SEO fields copy-pasted per type. The key design principle from Sanity Learn: “For the benefit of content authors, fields relevant to SEO should not always be required. Instead, they should be used to override some existing content, when provided.” » (Traduction) (Résumé en français de la section trente-six, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

En pratique que signifie SEO champs sont overrides avec fallbacks, implemented avec GROQ’s coalesce():

"title": coalesce(seo.title, title, ""),
"description": coalesce(seo.description, excerpt, "")

«A minimum viable seo object: metaTitle (≤65 chars), metaDescription (≤155 chars), canonicalUrl, openGraphImage (1200×630), and a noIndex boolean. Add Sanity validation rules to enforce those character limits before publish — so editors catch problems the platform would otherwise let through. Use a slug type with a custom generation function, and use references for internal links so URL changes propagate automatically. Add a hideFromSearch boolean and filter it out of both the sitemap GROQ query and the page’s robots metadata. » (Traduction) (Résumé en français de la section trente-neuf, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

«## Metadata, sitemaps, and canonicals — all built in the frontend » (Traduction) (Résumé en français de la section quarante, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

«Metadata. In Next.js App Router, use the exported generateMetadata() function (not inline <head> tags) so metadata doesn’t duplicate across nested layouts. Build one server-side helper that takes a GROQ result and returns the framework’s metadata object — implement it once, use it everywhere. Open Graph images can be generated dynamically with Next.js Edge OG generation, pulling content straight from Sanity. » (Traduction) (Résumé en français de la section quarante et un, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

Sitemaps. il y a aucun auto-sitemap. Vous construire il depuis a GROQ requête → URL array → XML (sitemap.ts dans Suivant.js, @astrojs/sitemap dans Astro). Toujours filter drafts et hidden pages:

*[_type in ["page", "post"] && defined(slug.current) && hideFromSearch != true]

Utiliser _updatedAt (pas _createdAt or a manual date) pour lastModified, garder individual sitemap fichiers sous 50 000 URLs avec an indexer pour plus grand sites, et trigger regeneration via a Sanity webhook on publish/unpublish donc il jamais goes stale.

Canonicals. Définir URL canoniques depuis le contenu model, par défaut à a self-referencing canonical, et construire absolute URLs depuis a unique SITE_URL donc le canonical jamais drifts. (Mechanics dans Canonicalization.)

Données structurées — generate it, don’t author it

«The right pattern is to generate JSON-LD programmatically from existing content fields at render time — never build a separate JSON-LD editor surface in Studio, which just creates drift between content and markup. Roboto Studio’s rule is blunt: “Derive JSON-LD from existing fields, at render time, in code.” Sanity agrees — “JSON-LD is a powerful way to provide structured data to search engines — fortunately structured data is what Sanity does best.” » (Traduction) (Résumé en français de la section quarante-sept, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

Utiliser pt::text(body) à pull plain texte pour schema descriptions, le TypeScript package schema-dts pour type safety, et rendre il avec <script type="application/ld+json">. Remarque que “le JSON-LD markup peut être rendu anywhere dans lune page — il ne fait pas besoin à être stored à l’intérieur le <head>.” Priority types pour contenu sites: Article/BlogPosting, BreadcrumbList, FAQPage, Organization, Site web.

Keeping drafts out de Google — le real-incident pitfall

Sanity’s perspective système contrôle draft visibility: published renvoie seulement production contenu; drafts renvoie draft documents pour preview. Toujours utiliser le published perspective dans production API calls. Mais que alone n’est pas suffisant, parce que draft URLs leak. As un developer recounted, le danger est “a client panicking parce que an unpublished landing page showed up dans la recherche Google Console. Si a contenu editor shares que URL dans Slack, et quelqu’un clicks il depuis a navigateur c’est alors exploré (il se produit), le draft contenu peut fin up indexé.”

The reliable defense is a multi-layer un:

«1. Use the published perspective in production; never expose an unprotected preview endpoint. 2. Add an X-Robots-Tag: noindex HTTP header to every draft-mode/preview response — even if a draft URL leaks and gets crawled, Googlebot respects the header and won’t index it. (Don’t rely on robots.txt for this; a header is more reliable than a disallow for preview pages.) 3. Validate the preview secret server-side; never reflect it in the redirect URL, and scope the preview-enable endpoint to your Studio’s origin. » (Traduction) (Résumé en français de la section cinquante-deux, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

«## Robots, redirects, image SEO, and hreflang » (Traduction) (Résumé en français de la section cinquante-trois, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

«robots.txt is a static frontend file (app/robots.ts in Next.js). Block Studio paths only if they’re on the same domain (Disallow: /studio/); don’t try to block preview pages with it. » (Traduction) (Résumé en français de la section cinquante-quatre, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

«Redirects are a genuine workflow win: store them as Sanity documents (from, to, statusCode) so the content team can manage redirects without a developer deploy, then implement them in Next.js middleware.ts or a CDN/Worker layer (never in Sanity itself). Add validation rules to prevent loops and invalid paths. » (Traduction) (Résumé en français de la section cinquante-cinq, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

Image SEO: utiliser Sanity’s image CDN avec ?auto=format pour automatic WebP/AVIF, manage texte alternatif à le asset level avec document-level overrides, utiliser vanity filenames au lieu de hashed URLs, et définir hotspot/crop donc automatic crops garder le subject — qui matters la plupart pour OG images.

Hreflang: model locale variants as séparé Sanity documents referencing le canonical version, generate hreflang depuis a GROQ requête returning tout locale slugs, et donner chaque locale page a self-referencing canonical — jamais canonical a non-English page à le English un.

Plugins — utile, pas a substitute

  • sanity-plugin-seo — le principal recommendation (22k+ downloads). Actif SEO score, meta/OG preview, social cards, robots contrôler, hreflang, readability. Le AI tier ajoute mot-clé suggestions et meta generation.
  • sanity-plugin-seofields — an alternative: 39 schema.org types, an SEO Health Dashboard, et Suivant.js helper functions (buildSeoMeta()).
  • sanity-plugin-seo-pane — DEPRECATED. Ce est le old Yoast integration, supprimé due à an outdated dependency. Il encore montre up dans old tutorials. ne pas utiliser il.

Le honest framing, depuis Yanatiev: “SEO success dans Sanity comes depuis intentional structure, pas plugins.” Plugins surface champs et donner editorial feedback — ils ne pas remplacer proper contenu modeling.

AI search and AEO

«The 2026 wrinkle: LLM training and retrieval crawlers (Anthropic, OpenAI, Common Crawl) typically don’t execute JavaScript today, so CSR Portable Text is largely invisible to them regardless of whether Googlebot can render it — but this is provider-specific and not a guaranteed contract. Google’s Gemini pipeline is the notable exception, since it reuses Googlebot’s own rendering infrastructure, and other providers’ behavior can change. Treat “no rendering” as the safe assumption to build for, not a permanent law. Beyond rendering, two Sanity-friendly tactics: serve clean markdown via content negotiation when Accept: text/markdown is present (Sanity’s @portabletext/markdown package converts Portable Text with no extra authoring), and monitor Bing specifically since Bing’s index feeds ChatGPT’s browse responses. On llms.txt, Sanity’s own Knut Melvær is skeptical — “Probably don’t do llms.txt” for large sites, because the all-or-nothing scope and file-size limits make it impractical; per-page content negotiation is more granular. Roboto Studio’s summary is the right mindset: “AEO and SEO live on the same plumbing, so we treat them as one job.” (More in AI Search.) » (Traduction) (Résumé en français de la section soixante-deux, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.)

The myths worth killing

«- “Sanity does SEO automatically like WordPress + Yoast.” No. Zero HTML, zero automatic anything. » (Traduction) (Résumé en français de la section soixante-quatre, sous-partie un : le texte source est conservé pour vérification lors de la relecture francophone.) «- “Any rendering mode is fine if the content’s in Sanity.” No. CSR breaks indexing and AI visibility; dynamic rendering is deprecated. » (Traduction) (Résumé en français de la section soixante-quatre, sous-partie deux : le texte source est conservé pour vérification lors de la relecture francophone.) «- “Drafts can’t be indexed.” They can, if a preview URL leaks. Use a noindex header. » (Traduction) (Résumé en français de la section soixante-quatre, sous-partie trois : le texte source est conservé pour vérification lors de la relecture francophone.) «- “Portable Text is HTML.” It’s a JSON AST that the frontend must serialize. » (Traduction) (Résumé en français de la section soixante-quatre, sous-partie quatre : le texte source est conservé pour vérification lors de la relecture francophone.) «- “You need a JSON-LD editor in Studio.” No — generate it from existing fields. » (Traduction) (Résumé en français de la section soixante-quatre, sous-partie cinq : le texte source est conservé pour vérification lors de la relecture francophone.)

Ajouter une note d’expert

Épingler une citation d’expert

Nouvelle personne ? Créez son profil non revendiqué à /admin/experts/ → Épingler une citation d’expert d’abord.