Guide Sanity SEO
Sanity stores content as JSON and emits zero HTML — votre frontend decides votre SEO. Rendering modes, Portable Text, the SEO object, sitemaps, draft-mode noindex, JSON-LD, and plugins.
Langues
Sanity is a CMS headless que stores content as structured JSON in its Content Lake and produces aucun HTML — so votre frontend framework (Suivant.js, Astro, Remix) decides everything à propos de votre SEO. The unique biggest lever is rendering: SSG and SSR ship complet HTML and are safe; CSR is risky parce que LLM-crawler rendering contracts vary by provider. Portable Text is a JSON AST, pas HTML, so the frontend doit serialize it. Construire a reusable SEO object in le contenu model, generate sitemaps and JSON-LD programmatically, garder drafts out of the index with an X-Robots-Tag: noindex header, and utiliser sanity-plugin-seo (pas the deprecated Yoast pane). SEO success in Sanity comes from intentional structure, pas plugins.
TL;DR — Sanity is a placer to store content, pas a placer que publishes web pages. It hands votre content out as données (JSON), pas as finished HTML — so a separate website construit with something comme Suivant.js or Astro has to turn que données into pages. Que signifie none of the usual SEO stuff (titles, sitemaps, canonical tags) se produit automatically the façon it fait on WordPress. The biggest rule: construire votre pages on a server or at construire temps, pas entirely in the visitor’s navigateur, or moteur de recherches and AI outils may jamais voir votre content.
Ce que Sanity en réalité is
Personnes parfois assume Sanity is “a CMS like WordPress,” and that’s où the confusion starts. Sanity is a CMS headless. It fait two choses: it stores votre content (in something Sanity calls the Content Lake) and it donne content editors a placer to écrire (Sanity Studio). Ce que it fait pas do is produce a unique line of HTML. Votre content comes out as données structurées — JSON — via an API.
Evidence for this claim Sanity stores structured content in Content Lake and provides it to applications as data rather than finished site HTML. Scope: Sanity platform architecture; the frontend owns public rendering. Confidence: high · Verified: Sanity: Content LakeQue signifie a separate website — construit with a framework comme Suivant.js, Astro, or Remix — has to récupérer que JSON and construire the réel pages personnes and moteur de recherches voir. Sanity stores le contenu; votre frontend publishes it. Une fois vous internalize que un sentence, almost everything à propos de Sanity SEO rend sense.
The un decision que matters la plupart: rendering
Parce que votre frontend builds lune pages, how it builds les decides votre SEO. Là are two safe façons and un risky façon:
- At construire temps (SSG) — pages are pre-built into plain HTML fichiers. Fast and search-friendly.
- On a server, per requête (SSR) — le serveur builds the complet page and sends it. Aussi search-friendly, toujours fresh.
- In the visitor’s navigateur (CSR) — le serveur sends a near-empty shell and JavaScript fills it in afterward. Ce is the risky un.
Google peut eventually run JavaScript and lire a CSR page, but it’s slower and moins reliable — and today the robots d’exploration behind ChatGPT, Claude, and Perplexity typically don’t render JavaScript at tout, so ils simplement voir the vide shell. That’s pas a fixed rule, though: Google’s Gemini réponses reuse Googlebot’s propre rendering infrastructure, so behavior déjà varies by provider and isn’t guaranteed to stay the même. So si vous vouloir to montrer up in Google and obtenir cited by AI outils, construire votre HTML on le serveur or at construire temps.
Evidence for this claim Google can render JavaScript pages, but browser-only content depends on a separate rendering stage. Scope: Google Search only; this record does not support claims about named AI crawlers. Confidence: high · Verified: Google: JavaScript SEO basicsThe “where did my SEO settings go?” problem
On WordPress, a plugin comme Yoast quietly handled votre titles, meta descriptions, sitemap, and balise canonicals. Sanity has aucun tel chose. So someone has to deliberately:
- Ajouter SEO fields (title, description, social image) to le contenu in Sanity.
- Wire ceux fields into chaque page’s HTML in the frontend.
- Construire a sitemap, a robots.txt, and données structurées — tout in code.
None of ce is hard. It simplement won’t se produire on its propre. A lot of “my Sanity site has aucun SEO” stories are really “nobody construit the stuff a plugin utilisé to do.”
Two choses que quietly go incorrect
- Draft pages getting into Google. Sanity peut serve unpublished drafts via its API. Si someone shares a preview lien and a robot d’exploration trouve it, que draft peut obtenir indexé. Vous have to actively block que.
- Corps text that’s invisible. Sanity stores rich text in a special format appelé Portable Text — it’s données, pas HTML. Votre frontend has to convert it. On a CSR page, que conversion se produit in le navigateur, so AI robots d’exploration jamais voir votre article text.
Vouloir the complet version — the four rendering modes, the reusable SEO field setup, sitemaps, draft-mode protection, JSON-LD, and qui plugins to utiliser? Switch to the Avancé tab.
TL;DR — Sanity is content-neutral: it stores structured JSON in le contenu Lake and emits zero HTML, so the frontend’s rendering mode decides everything. SSG and SSR ship complet HTML and are safe; CSR is the risky un parce que LLM robots d’exploration don’t execute JavaScript, and Google deprecated dynamic rendering as a workaround. Portable Text is a JSON AST que the frontend doit serialize. Construire a reusable
seoobject in le contenu model with overrides (pas requirements) viacoalesce(), generate sitemaps and JSON-LD programmatically from existing fields, and garder drafts out of the index with anX-Robots-Tag: noindexheader on every preview réponse. Utilisersanity-plugin-seo— jamais the deprecated Yoast pane — but remember “SEO success in Sanity comes from intentional structure, not plugins.”
Sanity is content storage, pas a publisher
A utile premier principle: Sanity touches votre content, jamais votre rendering.
Le contenu Lake stores everything as structured JSON, queried with GROQ
(Sanity’s requête language) or REST. Sanity Studio — the editing UI — is a React
single-page app que usually lives on its propre .sanity.studio subdomain and isn’t
something vous index. Nothing in ce stack produces HTML.
So the entier SEO surface lives in votre frontend framework. As Webstacks put it, “Sanity handles content storage and editing, pendant que votre frontend framework handles SEO output.” That’s pas a limitation — it’s the whole headless model. Sanity’s propre team frames it bien: “Quand en utilisant Sanity as a CMS, you’re doing headless SEO. Although ce approach exige thoughtful technical implementation, it peut liberate votre content to aider vous reach plus utilisateurs à travers tout channels.” The fonctionner is réel, but it’s the même fonctionner as quelconque headless construire (voir SEO pour a CMS headless).
Rendering mode is the foundation
Parce que the frontend builds the HTML, the rendering decision is the unique la plupart consequential SEO choice on a Sanity site. Four modes:
SSG — Static Site Generation. Content is récupéré from Sanity at construire temps and baked into static HTML served from a CDN. Best-case SEO: fully-rendered HTML on premier requête, fast TTFB. Ideal pour blog posts, marketing pages, and product/landing pages. The tradeoff is freshness — modifié content nécessite a rebuild (ISR solves ce).
SSR — Rendu côté serveur. Content is récupéré per requête and the complet HTML is rendered on le serveur. Excellent SEO, toujours fresh. Utiliser it pour frequently mis à jour content. Tradeoff is infrastructure cost and slightly plus élevé TTFB que static fichiers.
ISR — Incremental Static Regeneration (Vercel/Suivant.js). Static pages regenerate in the background, ideally triggered by a Sanity webhook on publish so lune page rebuilds the moment an editor hits publish. Ce is the meilleur of SSG’s speed and SSR’s freshness pour content que changements on the order of hours or days.
CSR — Rendu côté client. An HTML shell ships, alors JavaScript récupère from Sanity and builds the DOM in le navigateur. Ce is the worst SEO option: Googlebot has to queue lune page pour a plus tard render wave, timing is unpredictable, and AI robots d’exploration and nombreux autre bots voir seulement the shell. CSR is acceptable seulement behind authentication pour content vous don’t vouloir indexé anyway.
And don’t reach pour the old shortcut: Google has deprecated dynamic rendering (serving prerendered HTML to bots, CSR to utilisateurs). Officially, “dynamic rendering was a workaround and pas a long-term solution,” and Google now recommends “server-side rendering, static rendering, or hydration.” Pour a Sanity site, que signifie SSG or SSR — pas a bot-detection hack. (Complet rendering treatment in JavaScript SEO.)
Evidence for this claim Google describes dynamic rendering as a workaround rather than a recommended long-term solution and recommends server-side rendering, static rendering, or hydration. Scope: Google Search guidance for JavaScript sites. Confidence: high · Verified: Google: Dynamic renderingPortable Text — votre corps copy is a JSON AST
Ce is the la plupart Sanity-specific chose on lune page. Sanity stores rich text as
Portable Text: a JSON abstract syntax tree, pas HTML. Corps copy in le contenu
Lake semble comme an array of typed blocks, pas <p> tags. Votre frontend has to
serialize it into HTML avant quelconque robot d’exploration peut lire it:
@portabletext/react— pour React/Suivant.js.@portabletext/to-html— framework-agnostic (Astro, Remix, anything).- The old
@sanity/block-content-to-reactis deprecated — don’t utiliser it.
Si vous render server-side or at construire temps, serialization se produit avant lune page is
sent and robots d’exploration obtenir complet HTML. Si vous render client-side, the serialization runs
in le navigateur. Parce que LLM-crawler rendering contracts vary by provider, CSR
Portable Text creates a coverage risk que raw HTML avoids. There’s aussi a handy GROQ
helper: pt::text(body) extracts tout the plain text from a Portable Text field as a
string, qui is perfect pour feeding JSON-LD descriptions sans a separate editor
field.
Content modeling pour le SEO — the reusable SEO object
The cleanest pattern, and the un Sanity’s propre course teaches, is a unique
reusable seo object ajouté to every document type — pas SEO fields copy-pasted per
type. The clé design principle from Sanity Apprendre: “Pour the benefit of content
authors, fields relevant to SEO ne doit pas toujours be requis. À la place, ils devrait
be utilisé to override some existing content, quand provided.”
En pratique que signifie SEO fields are overrides with fallbacks, implemented with
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.
Ajouter Sanity validation rules to enforce ceux character limites avant publish —
so editors catch problems the platform voudrait sinon let via. Utiliser a slug
type with a custom generation function, and utiliser références pour lien internes so
URL changements propagate automatically. Ajouter a hideFromSearch boolean and filter it out
of les deux le sitemap GROQ requête and lune page’s robots metadata.
Metadata, sitemaps, and canonicals — tout construit in the frontend
Metadata. In Suivant.js App Router, utiliser the exported generateMetadata() function
(pas inline <head> tags) so metadata doesn’t duplicate à travers nested layouts.
Construire un server-side helper que takes a GROQ result and renvoie the framework’s
metadata object — implement it une fois, utiliser it everywhere. Ouvrir Graph images peut be
generated dynamically with Suivant.js Edge OG generation, pulling content straight from
Sanity.
Sitemaps. There’s aucun auto-sitemap. Vous construire it from a GROQ requête → URL array →
XML (sitemap.ts in Suivant.js, @astrojs/sitemap in Astro). Toujours filter drafts and
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 with an index pour plus grand sites, and
trigger regeneration via a Sanity webhook on publish/unpublish so it jamais goes stale.
Canonicals. Définir URL canoniques from le contenu model, par défaut to a
self-referencing canonical, and construire absolute URLs from a unique SITE_URL so the
canonical jamais drifts. (Mechanics in
Canonicalization.)
Données structurées — generate it, don’t author it
The correct pattern is to generate JSON-LD programmatically from existing content fields at render temps — jamais construire a separate JSON-LD editor surface in Studio, qui simplement creates drift entre 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 façon to provide données structurées to moteur de recherches — fortunately données structurées is ce que Sanity fait meilleur.”
Utiliser pt::text(body) to pull plain text pour schema descriptions, the TypeScript
package schema-dts pour type safety, and render it with
<script type="application/ld+json">. Remarque que “the JSON-LD markup peut be
rendered anywhere in lune page — it doesn’t besoin to be stored à l’intérieur the
<head>.” Priority types pour content sites: Article/BlogPosting,
BreadcrumbList, FAQPage, Organization, WebSite.
Keeping drafts out of Google — the real-incident pitfall
Sanity’s perspective system contrôle draft visibility: published renvoie seulement
production content; drafts renvoie draft documents pour preview. Toujours utiliser the
published perspective in production API calls. But que alone isn’t suffisant,
parce que draft URLs leak. As un developer recounted, the danger is
“a client panicking parce que an unpublished landing page showed up dans la recherche Google
Console. Si a content editor shares que URL in Slack, and someone clicks it from a
navigateur that’s alors crawled (it se produit), the draft content peut fin up indexé.”
The reliable defense is a multi-layer un:
- Utiliser the
publishedperspective in production; jamais expose an unprotected preview endpoint. - Ajouter an
X-Robots-Tag: noindexHTTP header to every draft-mode/preview réponse — même si a draft URL leaks and obtient crawled, Googlebot respects the header and won’t index it. (Don’t rely on robots.txt pour ce; a header is plus reliable que a disallow pour preview pages.) - Validate the preview secret server-side; jamais reflect it in the redirection URL, and scope the preview-enable endpoint to votre Studio’s origin.
Robots, redirections, image SEO, and hreflang
robots.txt is a static frontend fichier (app/robots.ts in Suivant.js). Block Studio
paths seulement si they’re on the même domain (Disallow: /studio/); don’t essayer to block
preview pages with it.
Redirections are a genuine workflow win: store les as Sanity documents (from,
to, statusCode) so le contenu team peut manage redirections sans a developer
deploy, alors implement les in Suivant.js middleware.ts or a CDN/Worker couche (jamais
in Sanity itself). Ajouter validation rules to prevent loops and invalid paths.
Image SEO: utiliser Sanity’s image CDN with ?auto=format pour automatic WebP/AVIF,
manage texte alternatif at the asset level with document-level overrides, utiliser vanity
filenames au lieu de hashed URLs, and définir hotspot/crop so automatic crops garder
the subject — qui matters la plupart pour OG images.
Hreflang: model locale variants as separate Sanity documents referencing the canonical version, generate hreflang from a GROQ requête returning tout locale slugs, and give every locale page a self-referencing canonical — jamais canonical a non-English page to the English un.
Plugins — utile, pas a substitute
sanity-plugin-seo— the principal recommendation (22k+ downloads). Live SEO score, meta/OG preview, social cards, robots contrôler, hreflang, readability. The AI tier adds keyword suggestions and meta generation.sanity-plugin-seofields— an alternative: 39 schema.org types, an SEO Health Dashboard, and Suivant.js helper functions (buildSeoMeta()).sanity-plugin-seo-pane— DEPRECATED. Ce is the old Yoast integration, supprimé due to an outdated dependency. It encore montre up in old tutorials. Don’t utiliser it.
The honest framing, from Yanatiev: “SEO success in Sanity comes from intentional structure, pas plugins.” Plugins surface fields and give editorial feedback — ils don’t replace proper content modeling.
AI search and AEO
The 2026 wrinkle: LLM training and retrieval robots d’exploration (Anthropic, OpenAI, Courant
Explorer) typically don’t execute JavaScript today, so CSR Portable Text is largely
invisible to les regardless of si Googlebot peut render it — but ce is
provider-specific and pas a guaranteed contract. Google’s Gemini pipeline is the
notable exception, since it reuses Googlebot’s propre rendering infrastructure, and
autre providers’ behavior peut modifier. Treat “no rendering” as the safe assumption to
construire pour, pas a permanent law. Au-delà rendering, two Sanity-friendly
tactics: serve clean markdown via content negotiation quand Accept: text/markdown
is présent (Sanity’s @portabletext/markdown package converts Portable Text with aucun
supplémentaire authoring), and monitor Bing specifically since Bing’s index feeds
ChatGPT’s browse réponses. On llms.txt, Sanity’s propre Knut Melvær is skeptical —
“Probably don’t do llms.txt” pour grand sites, parce que the all-or-nothing scope and
file-size limites faire it impractical; per-page content negotiation is plus granular.
Roboto Studio’s summary is the correct mindset: “AEO and SEO live on the même plumbing,
so we treat les as un job.” (Plus in AI Search.)
The myths worth killing
- “Sanity does SEO automatically like WordPress + Yoast.” Aucun. Zero HTML, zero automatic anything.
- “Any rendering mode is fine if the content’s in Sanity.” Aucun. CSR breaks indexation and AI visibility; dynamic rendering is deprecated.
- “Drafts can’t be indexed.” Ils peut, si a preview URL leaks. Utiliser a
noindexheader. - “Portable Text is HTML.” It’s a JSON AST que the frontend doit serialize.
- “You need a JSON-LD editor in Studio.” Aucun — generate it from existing fields.
AI summary
A condensed prendre on the Avancé version:
- Sanity is content-neutral. It stores structured JSON in le contenu Lake (queried via GROQ/REST) and emits zero HTML. The frontend (Suivant.js, Astro, Remix) produces tout SEO output. “Sanity does SEO like WordPress” is a myth.
- Rendering mode is the foundation. SSG and SSR ship complet HTML and are safe; ISR (webhook-triggered on publish) adds freshness; CSR is risky. Google deprecated dynamic rendering — utiliser SSR/static/hydration.
- LLM-crawler rendering varies by provider — raw HTML maximizes Portable Text coverage.
- Portable Text is a JSON AST, pas HTML. Serialize it with
@portabletext/reactor@portabletext/to-html;@sanity/block-content-to-reactis deprecated. Utiliserpt::text(body)to extract plain text pour JSON-LD. - Content modeling: un reusable
seoobject à travers tout types, fields as overrides pas requirements viacoalesce(), validation rules enforcing limites, and ahideFromSearchflag filtered from les deux sitemap and robots metadata. - Sitemaps, metadata, canonicals, robots.txt are tout construit in the frontend.
Filter drafts from le sitemap GROQ requête, utiliser
_updatedAtpourlastModified, and regenerate via Sanity webhooks. - Generate JSON-LD programmatically from existing fields at render temps — jamais a
separate Studio editor. Utiliser
schema-dts; it peut render anywhere, pas simplement<head>. - Garder drafts out of the index: utiliser the
publishedperspective in production and ajouter anX-Robots-Tag: noindexheader to every preview réponse. A leaked draft URL has caused réel indexation incidents. - Plugins:
sanity-plugin-seo(principal) orsanity-plugin-seofields. The Yoastsanity-plugin-seo-paneis deprecated. “SEO success in Sanity comes from intentional structure, pas plugins.” - AEO: monitor Bing (feeds ChatGPT browse); serve markdown via content
negotiation; Sanity advises contre
llms.txtpour grand sites.
Documentation officielle
Primary-source documentation from the moteur de recherches and Sanity.
- Comprendre JavaScript SEO Basics — the explorer → render → index pipeline, JS canonicals, and pourquoi blocked fichiers don’t obtenir rendered. The core référence pour quelconque Sanity frontend.
- Dynamic Rendering (deprecated workaround) — pourquoi Google deprecated it and ce que to utiliser à la place (SSR, static rendering, hydration).
- Rendering pour Content-Driven Web Apps — SSR vs. SSG vs. CSR tradeoffs pour exactly the kind of content sites Sanity powers.
- Robots meta tag, data-nosnippet, and X-Robots-Tag — the
X-Robots-Tag: noindexHTTP header utilisé to garder draft/preview réponses out of the index. - Intro to robots.txt — ce que robots.txt fait and doesn’t do (it contrôle exploration, pas indexation of leaked drafts).
Bing / Microsoft
- The nouveau evergreen Bingbot (Microsoft Edge) — Bingbot rendering JavaScript via Edge; relevant since Bing’s index feeds ChatGPT browse.
- IndexNow / indexnow.org — the push protocol to wire to votre Sanity publish webhook.
Sanity
- SEO with Sanity — Sanity’s propre master SEO guide.
- SEO Optimization course — the complet Suivant.js SEO course (schema types, dynamic sitemaps, JSON-LD).
- Presenting and previewing content (perspectives) —
publishedvs.draftsperspectives, the basis of draft-mode safety.
Quotes from the source
On-the-record statements relevant to Sanity SEO. Chaque lien is a deep lien que jumps to the quoted passage on the source page.
Sanity — the headless SEO model
- “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.” — Sanity, SEO with Sanity. Jump to quote
- “SEO doesn’t have to be complicated. It’s a matter of taking content you’ve already responsibly structured with Sanity and rendering it in the format and places that search engines expect.” — Sanity Apprendre, SEO Optimization course. Jump to quote
- “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.” — Sanity Apprendre, SEO schema types and metadata. Jump to quote
- “JSON-LD is a powerful way to provide structured data to search engines—fortunately structured data is what Sanity does best.” — Sanity Apprendre, Generating JSON-LD dynamically. Jump to quote
Google — dynamic rendering is deprecated
- “Dynamic rendering was a workaround and not a long-term solution for problems with JavaScript-generated content in search engines.” — Recherche Google Central docs. Jump to quote
- Recommended à la place: “server-side rendering, static rendering, or hydration.” Jump to quote
Industry — frontend owns SEO; structure beats plugins
- “Sanity handles content storage and editing, while your frontend framework handles SEO output.” — Webstacks, Sanity SEO. Lire the guide
- “AEO and SEO live on the same plumbing, so we treat them as one job.” — Roboto Studio / Jono Alford, AEO & SEO meilleur practices pour Sanity. Lire the post
- “SEO success in Sanity comes from intentional structure, not plugins.” — Yanatiev, SEO meilleur practices pour Sanity CMS. Lire the post
- “Probably don’t do llms.txt.” — Knut Melvær, Sanity, How to serve content to agents. Lire the field guide
Sanity SEO checklist
A réussir construit autour how Sanity en réalité fonctionne — construire the choses the platform leaves to votre frontend, and lock bas the choses que quietly break.
Rendering & content (the foundation)
- Pages render leur content in HTML on premier requête (SSG or SSR), pas seulement après client-side JavaScript runs.
- Aucun SEO-critical page dépend on CSR (raw HTML maximizes LLM-crawler coverage).
- ISR (si utilisé) regenerates on a Sanity publish webhook, pas simplement a timer.
- Portable Text is serialized server-side with
@portabletext/reactor@portabletext/to-html(pas the deprecatedblock-content-to-react).
Content model
- Un reusable
seoobject on every document type — pas per-type duplication. - SEO fields are overrides via
coalesce(), with validation rules enforcing title/description length avant publish. - A
hideFromSearch(ornoIndex) boolean exists and is filtered from les deux le sitemap GROQ requête and lune page’s robots metadata.
Frontend outputs
- Metadata wired from GROQ into
generateMetadata()(or framework equivalent) — un reusable helper. - Sitemap generated from GROQ, drafts/hidden filtered,
_updatedAtutilisé pourlastModified, regenerated on a webhook. - Canonicals are absolute URLs from a unique
SITE_URL, per-page and self-referencing by par défaut. - robots.txt exists in the frontend;
.js/.cssne sont pas blocked. - JSON-LD generated programmatically from existing fields (Article, Breadcrumb, FAQ, Organization), verified with the Résultats enrichis Tester.
Draft / preview safety
- Production API calls utiliser the
publishedperspective. - Every draft/preview réponse sends an
X-Robots-Tag: noindexheader. - Preview secret validated server-side and scoped to the Studio origin.
AEO & monitoring
- Bing Webmaster Outils définir up (Bing feeds ChatGPT browse); IndexNow on publish.
- (Optional) markdown served via content negotiation pour AI robots d’exploration.
The mental models
1. Sanity stores, the frontend publishes. Le contenu Lake holds JSON; votre framework produces every byte of HTML and every SEO signal. Avant debugging quelconque Sanity SEO problem, demander: ce que is the frontend en réalité sending robots d’exploration? Almost everything resolves to que.
2. Rendering mode is the product. Pick by how le contenu changements:
- Mostly static (blog, docs, marketing) → SSG (rebuild or ISR on publish).
- Frequently modification, doit be fresh → SSR.
- Hours/days cadence, vouloir static speed → ISR (webhook-triggered).
- Behind a login, pas meant to be indexé → CSR is acceptable.
- Public content vous vouloir ranked or cited by AI → jamais CSR.
3. Overrides, pas requirements.
SEO fields par défaut to the principal content and seulement override quand an editor fills les
in — implemented with coalesce(). Ce garde the editing experience clean and
guarantees every page has something pour its title and description.
4. Generate, don’t author, the markup. Sitemaps, JSON-LD, hreflang, and canonicals are tout derived from existing fields in code at render temps. A separate editor surface pour quelconque of les simplement creates drift. “Derive from existing fields, at render time, in code.”
5. Defense in depth pour drafts.
published perspective in production is couche un; an X-Robots-Tag: noindex header
on every preview réponse is couche two. Jamais rely on a unique contrôler to garder
unpublished content out of the index.
Sanity SEO — cheat sheet
Rendering modes En un coup d’œil
| Mode | Où HTML is construit | SEO | Meilleur pour | Watch out pour |
|---|---|---|---|---|
| SSG | Construire temps → static fichiers | ✅ Meilleur | Blogs, docs, marketing | Stale jusqu’à rebuild |
| SSR | Server, per requête | ✅ Meilleur | Frequently-updated content | Plus élevé infra cost |
| ISR | Static + webhook regen | ✅ Bon | Hourly/daily content | Configurer the publish webhook |
| CSR | In le navigateur | ⚠️ Risky | Logged-in dashboards | Invisible to AI robots d’exploration |
What’s construit in the frontend (pas in Sanity)
| Output | How |
|---|---|
| Corps copy HTML | Serialize Portable Text (@portabletext/react / -to-html) |
| Meta tags | generateMetadata() from a GROQ result |
| Sitemap | GROQ requête → XML; filter drafts; _updatedAt pour lastmod |
| Canonicals | Absolute URLs from un SITE_URL, per-page |
| robots.txt | Static frontend fichier (robots.ts in Suivant.js) |
| JSON-LD | Generated from existing fields; schema-dts pour types |
| Redirections | Sanity documents → frontend middleware / Worker |
GROQ snippets worth memorizing
- Override with fallback:
coalesce(seo.title, title, "") - Plain text from Portable Text:
pt::text(body) - Sitemap filter:
*[... && defined(slug.current) && hideFromSearch != true]
Fast rules
- LLM-crawler rendering varies by provider → éviter CSR-only public content.
- Dynamic rendering is deprecated — utiliser SSR/static/hydration.
- Drafts:
publishedperspective +X-Robots-Tag: noindexheader. - Plugin:
sanity-plugin-seo✅ /sanity-plugin-seo-pane(Yoast) ❌ deprecated. - “SEO success in Sanity comes from intentional structure, not plugins.”
Draft or preview content appeared in Search Console
Utiliser ce runbook quand an unpublished Sanity document has a discoverable preview URL or montre up dans la recherche Google Console.
- Confirmer qui réponse leaked. Récupérer the reported URL sans Studio
credentials and inspect les deux the status and
X-Robots-Tagheader. Si it renvoie publié content, continuer to step 2. Si it exposes a draft, disable the preview entry point pendant que vous continuer. - Vérifier the production perspective. Trace lune page’s GROQ requête and confirmer
production uses the
publishedperspective. Si it usesdrafts, fix que requête premier; si it déjà usespublished, continuer to la réponse couche. - Ajouter the indexation backstop. Send
X-Robots-Tag: noindexon every preview and draft-mode réponse. Si the header is manquant on quelconque preview route, fix the shared preview middleware plutôt que patching un page. - Validate preview accès. Confirmer the preview secret is vérifié server-side, n’est pas reflected into the destination URL, and accepts requêtes seulement from the intended Studio origin. Si a public preview URL encore fonctionne, rotate the secret and fermer que route.
- Supprimer the indexé copy. Après la réponse is safe, utiliser Search Console’s
removal workflow quand the exposure is urgent, alors requête a fresh explorer. Si the
URL devrait jamais exist publicly, garder the
noindexréponse disponible long suffisant pour robots d’exploration to voir it plutôt que blocking it in robots.txt. - Vérifier the fix. Récupérer l’URL pendant que logged out and run Inspection d’URL. The
draft doit be absent from the corps and the preview réponse doit carry
noindex.
Sanity SEO mistakes to éviter
Expecting Sanity to emit SEO HTML
Pourquoi it’s incorrect: Sanity stores JSON; it ne fait pas publish titles, canonicals, sitemaps, or page HTML. Do ce à la place: faire the frontend responsible pour chaque output and vérifier the generated réponse plutôt que the Studio fields.
Choosing CSR pour public content
Pourquoi it’s incorrect: The initial réponse is an vide shell, and nombreux AI robots d’exploration do pas execute JavaScript at tout. Do ce à la place: ship public content with SSG, SSR, or webhook-triggered ISR.
Assuming unpublished signifie unindexable
Pourquoi it’s incorrect: A shared preview URL peut leak and be crawled. Do ce à la place:
utiliser the published perspective in production and send an X-Robots-Tag: noindex
header on every preview réponse.
Treating Portable Text as HTML
Pourquoi it’s incorrect: Portable Text is a JSON AST, so un-serialized content jamais
becomes crawlable corps copy. Do ce à la place: serialize it on le serveur with
@portabletext/react or @portabletext/to-html.
Maintaining JSON-LD in a separate editor
Pourquoi it’s incorrect: A second copy of product, article, or organization facts drifts from the visible page. Do ce à la place: derive JSON-LD from the même Sanity fields at render temps and validate the rendered output.
Vérifier si a Sanity page ships réel HTML
Run ce après modification rendering mode, Portable Text serialization, or page données chargement. It checks the initial réponse, avant client-side JavaScript peut fill gaps.
macOS / Linux — comparer normal and Googlebot réponses
URL="https://example.com/article-slug"
curl -sL "$URL" -o /tmp/sanity-page.html
curl -sL -A "Googlebot" "$URL" -o /tmp/sanity-googlebot.html
grep -Ei '<title>|rel="canonical"|<h1|application/ld\+json' /tmp/sanity-page.html
diff -u /tmp/sanity-page.html /tmp/sanity-googlebot.htmlThe premier command devrait trouver lune page’s réel title, canonical, H1, and JSON-LD in
raw HTML. A meaningful content difference in the diff deserves investigation;
robots d’exploration and utilisateurs ne doit pas recevoir différent canonical content.
Windows PowerShell — inspect the initial réponse
$url = "https://example.com/article-slug"
$html = (Invoke-WebRequest -Uri $url).Content
$html | Select-String -Pattern '<title>|rel="canonical"|<h1|application/ld\+json'DevTools Console — confirmer Portable Text became semantic elements
[...document.querySelectorAll('main article p, main article h2, main article li')]
.map((node) => node.textContent.trim())
.filter(Boolean)
.slice(0, 20)Run the snippet in le navigateur Console. It is a rendered-DOM vérifier, so pair it with
the curl tester: content appearing seulement ici but pas in the initial réponse is encore
client-rendered.
Outils pour Sanity SEO
- Inspection d’URL (Recherche Google Console) — voir how a unique URL was crawled and rendered. The rendered HTML indique vous si votre Portable Text en réalité made it in — essential pour catching CSR gaps on a Sanity frontend.
- Résultats enrichis Tester — confirmer votre programmatic JSON-LD is présent in the rendered output après quelconque rendering or template modifier.
- Screaming Frog SEO Spider — explorer with JavaScript rendering on/off to comparer raw HTML vs. rendered HTML; ce is how vous prove si votre content is server- rendered or client-rendered.
- Ahrefs Site Audit — surfaces manquant metadata, broken canonicals, redirection chains, and indexability problèmes à travers the whole frontend.
- Bing Webmaster Outils — submit votre sitemap and monitor Bing indexation (it feeds ChatGPT browse), plus où IndexNow submissions montrer up.
sanity-plugin-seo— in-Studio live SEO score, meta/OG preview, and robots contrôler so editors obtenir feedback at authoring temps.
Testez vos connaissances: Sanity SEO
Five rapide questions on how SEO fonctionne on a Sanity-backed site. Pick an réponse pour chaque, alors vérifier.
Ressources utiles
My connexe writing
- JavaScript SEO Problèmes & Meilleur Practices — my principal référence on rendering modes, qui decide everything on a Sanity frontend.
- The Beginner’s Guide to SEO technique — où rendering and exploration fit in the bigger picture.
My speaking
- JavaScript SEO — Ungagged 2019 (SlideShare) — my walkthrough of how headless/decoupled CMSes split the frontend from the backend, plus Googlebot’s stateless rendering. (Standing disclaimer: the dynamic-rendering recommendation in que deck is now outdated — Google deprecated it.)
On ce site
- SEO pour a CMS headless — the sibling guide; Sanity is a spécifique application of the même headless rules.
- JavaScript SEO — the rendering deep dive.
- Canonicalization — the consolidation mechanics behind votre frontend’s balise canonicals.
- AI Search — how AI robots d’exploration and réponse engines behave.
From autour the industry
- SEO with Sanity (Sanity) — Sanity’s propre master SEO guide; commencer ici pour platform-current behavior.
- SEO Optimization course (Sanity Apprendre) — the hands-on Suivant.js course covering the SEO object, dynamic sitemaps, and JSON-LD.
- Sanity SEO (Webstacks, Devon Wood) — agency guide making the “frontend handles SEO output” point clearly.
- AEO & SEO meilleur practices pour Sanity (Roboto Studio, Jono Alford) — the AEO angle and the “derive JSON-LD from existing fields” rule.
- SEO meilleur practices pour Sanity CMS (Yanatiev) — the “structure, not plugins” framing.
- How to serve content to agents: a field guide (Knut Melvær, Sanity) — content negotiation and the cas contre llms.txt pour grand sites.
- CMS headless SEO (Ahrefs, Despina Gavoyannis) — the broader headless playbook (content/code/design optimized independently) que Sanity sits à l’intérieur.
- turbo-start-sanity (Roboto Studio, GitHub) — an open-source Sanity SEO starter with réel
query.ts,seo-fields.ts, andseo.tsimplementations.
Journal des modifications
Mis à jour le 19 juil. 2026.
Résumé éditorial et détails enregistrés des changements.Détails des changements
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
-
Les notes détaillées des changements sont actuellement disponibles en anglais.
Comparaison complète indisponible — aucun instantané antérieur n’a été archivé pour cette révision.