Sanity SEO
Sanity stores content as JSON and emits zero HTML — your frontend decides your SEO. Rendering modes, Portable Text, the SEO object, sitemaps, draft-mode noindex, JSON-LD, and plugins.
Sanity is a headless CMS that stores content as structured JSON in its Content Lake and produces no HTML — so your frontend framework (Next.js, Astro, Remix) decides everything about your SEO. The single biggest lever is rendering: SSG and SSR ship complete HTML and are safe; CSR is risky because LLM-crawler rendering contracts vary by provider. Portable Text is a JSON AST, not HTML, so the frontend must serialize it. Build a reusable SEO object in the content model, generate sitemaps and JSON-LD programmatically, keep drafts out of the index with an X-Robots-Tag: noindex header, and use sanity-plugin-seo (not the deprecated Yoast pane). SEO success in Sanity comes from intentional structure, not plugins.
TL;DR — Sanity is a place to store content, not a place that publishes web pages. It hands your content out as data (JSON), not as finished HTML — so a separate website built with something like Next.js or Astro has to turn that data into pages. That means none of the usual SEO stuff (titles, sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing., canonical tags) happens automatically the way it does on WordPress. The biggest rule: build your pages on a server or at build time, not entirely in the visitor’s browser, or search engines and AI tools may never see your content.
What Sanity actually is
People sometimes assume Sanity is “a CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. like WordPress,” and that’s where the confusion starts. Sanity is a headless CMSA headless CMS decouples content storage and editing (the backend) from how that content is rendered and delivered (the frontend), serving content over an API instead of a built-in templated 'head'. Its SEO outcomes come almost entirely from how the separate frontend renders pages.. It does two things: it stores your content (in something Sanity calls the Content Lake) and it gives content editors a place to write (Sanity Studio). What it does not do is produce a single line of HTML. Your content comes out as structured dataStructured data is a standardized way of labeling page content (using the schema.org vocabulary in JSON-LD, Microdata, or RDFa) so search engines can understand its meaning. It's not a direct ranking factor — its value is rich results and entity understanding. — JSON — through 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 LakeThat means a separate website — built with a framework like Next.js, Astro, or Remix — has to fetch that JSON and build the actual pages people and search engines see. Sanity stores the content; your frontend publishes it. Once you internalize that one sentence, almost everything about Sanity SEOSanity SEO is the set of technical and content practices that make a website built on Sanity.io rank and get cited. Sanity stores content as structured JSON and produces zero HTML, so every SEO output — meta tags, sitemaps, canonicals, structured data — is built in the frontend that consumes Sanity's API. makes sense.
The one decision that matters most: rendering
Because your frontend builds the pages, how it builds them decides your SEO. There are two safe ways and one risky way:
- At build time (SSG) — pages are pre-built into plain HTML files. Fast and search-friendly.
- On a server, per request (SSR) — the server builds the full page and sends it. Also search-friendly, always fresh.
- In the visitor’s browser (CSR) — the server sends a near-empty shell and JavaScript fills it in afterward. This is the risky one.
Google can eventually run JavaScript and read a CSR page, but it’s slower and less reliable — and today the crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. behind ChatGPT, Claude, and Perplexity typically don’t render JavaScriptMaking sure search engines can crawl, render, and index content that depends on JavaScript. at all, so they just see the empty shell. That’s not a fixed rule, though: Google’s Gemini answers reuse GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer.’s own renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. infrastructure, so behavior already varies by provider and isn’t guaranteed to stay the same. So if you want to show up in Google and get cited by AIAn AI citation is the visible source link an AI answer engine shows next to its generated text — the clickable reference that credits the web page it used. A citation's presence is a separate thing from whether the cited page actually supports the statement, and from being retrieved (read behind the scenes) or merely mentioned (named without a link); citation is driven more by brand mentions and being retrievable than by traditional ranking. tools, build your HTML on the server or at build time.
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 like Yoast quietly handled your titles, meta descriptionsThe meta description is an HTML head tag — `<meta name=\"description\" content=\"…\">` — that suggests a short summary of the page for the search snippet. It's not a Google ranking factor, and Google rewrites it the majority of the time, but a good one can still lift click-through., sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing., and canonical tagsA rel=\"canonical\" annotation — in the HTML <head> or an HTTP Link header — that tells search engines which URL is the preferred version of duplicate or near-duplicate content.. Sanity has no such thing. So someone has to deliberately:
- Add SEO fields (title, description, social image) to the content in Sanity.
- Wire those fields into each page’s HTML in the frontend.
- Build a sitemap, a robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere., and structured data — all in code.
None of this is hard. It just won’t happen on its own. A lot of “my Sanity site has no SEO” stories are really “nobody built the stuff a plugin used to do.”
Two things that quietly go wrong
- Draft pages getting into Google. Sanity can serve unpublished drafts through its API. If someone shares a preview link and a crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. finds it, that draft can get indexed. You have to actively block that.
- Body text that’s invisible. Sanity stores rich text in a special format called Portable Text — it’s data, not HTML. Your frontend has to convert it. On a CSR page, that conversion happens in the browser, so AI crawlersAI crawlers are bots from AI companies that fetch web pages to train language models, build AI-search indexes, or answer live user questions. They come in three categories, each with its own user-agent tokens and its own robots.txt controls. never see your article text.
Want the full version — the four renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. modes, the reusable SEO field setup, sitemaps, draft-mode protection, JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal., and which plugins to use? Switch to the Advanced tab.
TL;DR — Sanity is content-neutral: it stores structured JSON in the Content Lake and emits zero HTML, so the frontend’s renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. mode decides everything. SSG and SSR ship complete HTML and are safe; CSR is the risky one because LLMA large language model (LLM) is a deep-learning model trained on massive text corpora to predict the next token and generate human-like text. LLMs use the transformer architecture and power AI search features like Google's AI Overviews (Gemini) and Bing Copilot (GPT-4). crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. don’t execute JavaScript, and Google deprecated dynamic renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. as a workaround. Portable Text is a JSON AST that the frontend must serialize. Build a reusable
seoobject in the content model with overrides (not requirements) viacoalesce(), generate sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. and JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. programmatically from existing fields, and keep drafts out of the indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. with anX-Robots-Tag: noindexheader on every preview response. Usesanity-plugin-seo— never the deprecated Yoast pane — but remember “SEO success in Sanity comes from intentional structure, not plugins.”
Sanity is content storage, not a publisher
A useful first principle: Sanity touches your content, never your rendering.
The Content Lake stores everything as structured JSON, queried with GROQ
(Sanity’s query language) or REST. Sanity Studio — the editing UI — is a React
single-page app that usually lives on its own .sanity.studio subdomain and isn’t
something you index. Nothing in this stack produces HTML.
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 CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms., 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 CMSA headless CMS decouples content storage and editing (the backend) from how that content is rendered and delivered (the frontend), serving content over an API instead of a built-in templated 'head'. Its SEO outcomes come almost entirely from how the separate frontend renders pages.).
Rendering mode is the foundation
Because the frontend builds the HTML, the rendering decision is the single most consequential SEO choice on a Sanity site. Four modes:
SSG — Static Site Generation. Content is fetched from Sanity at build time and baked into static HTML served from a CDN. Best-case SEO: fully-rendered HTML on first request, fast TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good.. Ideal for blog posts, marketing pages, and product/landing pages. The tradeoff is freshness — changed content needs a rebuild (ISR solves this).
SSR — Server-Side Rendering. Content is fetched per request and the full HTML is rendered on the server. Excellent SEO, always fresh. Use it for frequently updated content. Tradeoff is infrastructure cost and slightly higher TTFBTime to First Byte — the time from the start of a request to when the first byte of the response arrives. It's a diagnostic metric (not a Core Web Vital) and a major input to FCP and LCP; ≤0.8 s is good. than static files.
ISR — Incremental Static Regeneration (Vercel/Next.js). Static pages regenerate in the background, ideally triggered by a Sanity webhook on publish so the page rebuilds the moment an editor hits publish. This is the best of SSG’s speed and SSR’s freshness for content that changes on the order of hours or days.
CSR — Client-Side Rendering. An HTML shell ships, then JavaScript fetches from Sanity and builds the DOM in the browser. This is the worst SEO option: GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. has to queue the page for a later render wave, timing is unpredictable, and AI crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. and many other bots see only the shell. CSR is acceptable only behind authentication for content you don’t want indexed 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 hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers..” For a Sanity site, that means SSG or SSR — not a bot-detection hack. (Full rendering treatment in JavaScript SEOMaking sure search engines can crawl, render, and index content that depends on JavaScript..)
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 — your body copy is a JSON AST
This is the most Sanity-specific thing on the page. Sanity stores rich text as
Portable Text: a JSON abstract syntax tree, not HTML. Body copy in the Content
Lake looks like an array of typed blocks, not <p> tags. Your frontend has to
serialize it into HTML before any crawler can read it:
@portabletext/react— for React/Next.js.@portabletext/to-html— framework-agnostic (Astro, Remix, anything).- The old
@sanity/block-content-to-reactis deprecated — don’t use it.
If you render server-side or at build time, serialization happens before the page is
sent and crawlers get full HTML. If you render client-side, the serialization runs
in the browser. Because LLM-crawler rendering contracts vary by provider, CSR
Portable Text creates a coverage risk that raw HTML avoids. There’s also a handy GROQ
helper: pt::text(body) extracts all the plain text from a Portable Text field as a
string, which is perfect for feeding JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. descriptions without a separate editor
field.
Content modeling for SEO — the 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.”
In practice that means 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.
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 linksAn internal link is a hyperlink from one page on a website to another page on the same website. Internal links help search engines discover your pages and pass ranking signals (PageRank and anchor-text context) between them. so
URL changes propagate automatically. Add a hideFromSearch boolean and filter it out
of both the sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. GROQ query and the page’s robots metadata.
Metadata, sitemaps, and canonicals — all built in the frontend
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 GraphOpen Graph (OG) tags are `<meta>` elements in a page's head, defined by the Open Graph protocol (ogp.me, created by Facebook), that describe a page as a shareable object — its title, description, image, URL, and type. They control how a link preview card looks when the page is shared on Facebook, LinkedIn, Slack, Discord, WhatsApp, and iMessage. They are not a direct Google ranking factor, though Google reads og:title, og:image, and og:site_name as inputs to how a result appears. images can be
generated dynamically with Next.js Edge OG generation, pulling content straight from
Sanity.
Sitemaps. There’s no auto-sitemap. You build it from a GROQ query → URL array →
XML (sitemap.ts in Next.js, @astrojs/sitemap in Astro). Always filter drafts and
hidden pages:
*[_type in ["page", "post"] && defined(slug.current) && hideFromSearch != true]Use _updatedAt (not _createdAt or a manual date) for lastModified, keep
individual sitemap files under 50,000 URLs with an index for larger sites, and
trigger regeneration via a Sanity webhook on publish/unpublish so it never goes stale.
Canonicals. Set canonical URLs from the content model, default to a
self-referencing canonical, and build absolute URLs from a single SITE_URL so the
canonical never drifts. (Mechanics in
CanonicalizationHow search engines pick one canonical URL among duplicates and consolidate signals onto it..)
Structured data — 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 dataStructured data is a standardized way of labeling page content (using the schema.org vocabulary in JSON-LD, Microdata, or RDFa) so search engines can understand its meaning. It's not a direct ranking factor — its value is rich results and entity understanding. to search engines — fortunately structured data is what Sanity does best.”
Use pt::text(body) to pull plain text for schema descriptions, the TypeScript
package schema-dts for type safety, and render it with
<script type="application/ld+json">. Note that “the JSON-LD markup can be
rendered anywhere in the page — it doesn’t need to be stored inside the
<head>.” Priority types for content sites: Article/BlogPosting,
BreadcrumbList, FAQPage, Organization, WebSite.
Keeping drafts out of Google — the real-incident pitfall
Sanity’s perspective system controls draft visibility: published returns only
production content; drafts returns draft documents for preview. Always use the
published perspective in production API calls. But that alone isn’t enough,
because draft URLs leak. As one developer recounted, the danger is
“a client panicking because an unpublished landing page showed up in Google Search
Console. If a content editor shares that URL in Slack, and someone clicks it from a
browser that’s then crawled (it happens), the draft content can end up indexed.”
The reliable defense is a multi-layer one:
- Use the
publishedperspective in production; never expose an unprotected preview endpoint. - Add an
X-Robots-Tag: noindexHTTP header to every draft-mode/preview response — even if a draft URL leaks and gets crawled, GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. respects the header and won’t index it. (Don’t rely on robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. for this; a header is more reliable than a disallow for preview pages.) - Validate the preview secret server-side; never reflect it in the redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. URL, and scope the preview-enable endpoint to your Studio’s origin.
Robots, redirects, image SEO, and hreflang
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.
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.
Image SEOImage SEO is optimizing the images on your pages so search engines can discover, crawl, index, and rank them — in Google Images and visual search, and as part of standard web results. It spans file format, filenames, alt text, compression, responsive markup, structured data, and image sitemaps.: use Sanity’s image CDN with ?auto=format for automatic WebP/AVIF,
manage alt textAlt text is the value of the `alt` attribute on an HTML `<img>` element — a short text substitute chosen for the image's purpose and context, not a literal description of what it shows. It makes images accessible to screen-reader users and helps search engines understand images, mainly for image search. at the asset level with document-level overrides, use vanity
filenames instead of hashed URLs, and set hotspot/crop so automatic crops keep
the subject — which matters most for OG images.
HreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others.: model locale variants as separate Sanity documents referencing the canonical version, generate hreflang from a GROQ query returning all locale slugs, and give every locale page a self-referencing canonical — never canonical a non-English page to the English one.
Plugins — helpful, not a substitute
sanity-plugin-seo— the primary recommendation (22k+ downloads). Live SEO score, meta/OG preview, social cards, robots control, 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 Next.js helper functions (buildSeoMeta()).sanity-plugin-seo-pane— DEPRECATED. This is the old Yoast integration, removed due to an outdated dependency. It still shows up in old tutorials. Don’t use it.
The honest framing, from Yanatiev: “SEO success in Sanity comes from intentional structure, not plugins.” Plugins surface fields and give editorial feedback — they don’t replace proper content 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.txtllms.txt is a proposed (not adopted) Markdown file at /llms.txt that gives AI systems a curated map of a site's most important pages. Proposed by Jeremy Howard in 2024, it's read mostly by coding agents like Claude Code — not search crawlers — and Google ignores it.” 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 SearchAI search uses large language models and retrieval-augmented generation (RAG) to synthesize an answer from multiple sources rather than returning a ranked list of links. Examples include Google AI Overviews, ChatGPT Search, and Perplexity..)
The myths worth killing
- “Sanity does SEO automatically like WordPress + Yoast.” No. Zero HTML, zero automatic anything.
- “Any rendering mode is fine if the content’s in Sanity.” No. CSR breaks indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. and AI visibility; dynamic rendering is deprecated.
- “Drafts can’t be indexed.” They can, if a preview URL leaks. Use a
noindexheader. - “Portable Text is HTML.” It’s a JSON AST that the frontend must serialize.
- “You need a JSON-LD editor in Studio.” No — generate it from existing fields.
AI summary
A condensed take on the Advanced version:
- Sanity is content-neutral. It stores structured JSON in the Content Lake (queried via GROQ/REST) and emits zero HTML. The frontend (Next.js, Astro, Remix) produces all SEO output. “Sanity does SEO like WordPress” is a myth.
- RenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. mode is the foundation. SSG and SSR ship complete HTML and are safe; ISR (webhook-triggered on publish) adds freshness; CSR is risky. Google deprecated dynamic renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. — use SSR/static/hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers..
- LLMA large language model (LLM) is a deep-learning model trained on massive text corpora to predict the next token and generate human-like text. LLMs use the transformer architecture and power AI search features like Google's AI Overviews (Gemini) and Bing Copilot (GPT-4).-crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. rendering varies by provider — raw HTML maximizes Portable Text coverage.
- Portable Text is a JSON AST, not HTML. Serialize it with
@portabletext/reactor@portabletext/to-html;@sanity/block-content-to-reactis deprecated. Usept::text(body)to extract plain text for JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal.. - Content modeling: one reusable
seoobject across all types, fields as overrides not requirements viacoalesce(), validation rules enforcing limits, and ahideFromSearchflag filtered from both sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. and robots metadata. - SitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing., metadata, canonicals, robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. are all built in the frontend.
Filter drafts from the sitemap GROQ query, use
_updatedAtforlastModified, and regenerate via Sanity webhooks. - Generate JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. programmatically from existing fields at render time — never a
separate Studio editor. Use
schema-dts; it can render anywhere, not just<head>. - Keep drafts out of the indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed.: use the
publishedperspective in production and add anX-Robots-Tag: noindexheader to every preview response. A leaked draft URL has caused real indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. incidents. - Plugins:
sanity-plugin-seo(primary) orsanity-plugin-seofields. The Yoastsanity-plugin-seo-paneis deprecated. “SEO success in Sanity comes from intentional structure, not plugins.” - AEOAnswer Engine Optimization (AEO) is the practice of structuring content so engines deliver it as a direct answer — featured snippets, voice assistants, and AI search — rather than just a ranked link. Coined for voice search in 2018 and revived for the LLM era. Google's position is that it's still SEO.: monitor Bing (feeds ChatGPT browse); serve markdown via content
negotiation; Sanity advises against
llms.txtfor large sites.
Official documentation
Primary-source documentation from the search engines and Sanity.
- Understand JavaScript SEO Basics — the crawl → render → indexStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. pipeline, JS canonicals, and why blocked files don’t get rendered. The core reference for any Sanity frontend.
- Dynamic Rendering (deprecated workaround) — why Google deprecated it and what to use instead (SSR, static renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM., hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers.).
- Rendering for Content-Driven Web Apps — SSR vs. SSG vs. CSR tradeoffs for exactly the kind of content sites Sanity powers.
- Robots meta tag, data-nosnippet, and X-Robots-Tag — the
X-Robots-Tag: noindexHTTP header used to keep draft/preview responses out of the index. - Intro to robots.txt — what robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. does and doesn’t do (it controls crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor., not indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. of leaked drafts).
Bing / Microsoft
- The new evergreen Bingbot (Microsoft Edge) — BingbotBingbot is Microsoft Bing's primary web crawler — the bot that discovers, fetches, and renders pages to build the Bing index. That index also powers Yahoo, DuckDuckGo, Ecosia, and Microsoft Copilot, so Bingbot's reach is far wider than Bing's own search-market share. renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. JavaScript via Edge; relevant since Bing’s index feeds ChatGPT browse.
- IndexNow / indexnow.org — the push protocol to wire to your Sanity publish webhook.
Sanity
- SEO with Sanity — Sanity’s own master SEO guide.
- SEO Optimization course — the full Next.js SEOMaking sure search engines can crawl, render, and index content that depends on JavaScript. course (schema typesSchema markup is code that uses the schema.org vocabulary to label what your content means so search engines can understand it and show rich results. It's most often written in JSON-LD, and it's not a direct ranking factor., dynamic sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing., JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal.).
- Presenting and previewing content (perspectives) —
publishedvs.draftsperspectives, the basis of draft-mode safety.
Quotes from the source
On-the-record statements relevant to Sanity SEOSanity SEO is the set of technical and content practices that make a website built on Sanity.io rank and get cited. Sanity stores content as structured JSON and produces zero HTML, so every SEO output — meta tags, sitemaps, canonicals, structured data — is built in the frontend that consumes Sanity's API.. Each link is a deep link that jumps to the quoted passage on the source page.
Sanity — the headless SEO model
- “When using Sanity as a CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms., 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 renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. it in the format and places that search engines expect.” — Sanity Learn, 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 Learn, SEO schema typesSchema markup is code that uses the schema.org vocabulary to label what your content means so search engines can understand it and show rich results. It's most often written in JSON-LD, and it's not a direct ranking factor. and metadata. Jump to quote
- “JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. is a powerful way to provide structured dataStructured data is a standardized way of labeling page content (using the schema.org vocabulary in JSON-LD, Microdata, or RDFa) so search engines can understand its meaning. It's not a direct ranking factor — its value is rich results and entity understanding. to search engines—fortunately structured data is what Sanity does best.” — Sanity Learn, Generating JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. dynamically. Jump to quote
Google — dynamic renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. is deprecated
- “Dynamic rendering was a workaround and not a long-term solution for problems with JavaScript-generated content in search engines.” — Google Search Central docs. Jump to quote
- Recommended instead: “server-side rendering, static rendering, or hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers..” 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. Read the guide
- “AEOAnswer Engine Optimization (AEO) is the practice of structuring content so engines deliver it as a direct answer — featured snippets, voice assistants, and AI search — rather than just a ranked link. Coined for voice search in 2018 and revived for the LLM era. Google's position is that it's still SEO. and SEO live on the same plumbing, so we treat them as one job.” — Roboto Studio / Jono Alford, AEO & SEO best practices for Sanity. Read the post
- “SEO success in Sanity comes from intentional structure, not plugins.” — Yanatiev, SEO best practices for Sanity CMS. Read the post
- “Probably don’t do llms.txtllms.txt is a proposed (not adopted) Markdown file at /llms.txt that gives AI systems a curated map of a site's most important pages. Proposed by Jeremy Howard in 2024, it's read mostly by coding agents like Claude Code — not search crawlers — and Google ignores it..” — Knut Melvær, Sanity, How to serve content to agents. Read the field guide
Sanity SEO checklist
A pass built around how Sanity actually works — build the things the platform leaves to your frontend, and lock down the things that quietly break.
RenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. & content (the foundation)
- Pages render their content in HTML on first request (SSG or SSR), not only after client-side JavaScript runs.
- No SEO-critical page depends on CSR (raw HTML maximizes LLMA large language model (LLM) is a deep-learning model trained on massive text corpora to predict the next token and generate human-like text. LLMs use the transformer architecture and power AI search features like Google's AI Overviews (Gemini) and Bing Copilot (GPT-4).-crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. coverage).
- ISR (if used) regenerates on a Sanity publish webhook, not just a timer.
- Portable Text is serialized server-side with
@portabletext/reactor@portabletext/to-html(not the deprecatedblock-content-to-react).
Content model
- One reusable
seoobject on every document type — not per-type duplication. - SEO fields are overrides via
coalesce(), with validation rules enforcing title/description length before publish. - A
hideFromSearch(ornoIndex) boolean exists and is filtered from both the sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. GROQ query and the page’s robots metadata.
Frontend outputs
- Metadata wired from GROQ into
generateMetadata()(or framework equivalent) — one reusable helper. - SitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. generated from GROQ, drafts/hidden filtered,
_updatedAtused forlastModified, regenerated on a webhook. - Canonicals are absolute URLs from a single
SITE_URL, per-page and self-referencing by default. - robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. exists in the frontend;
.js/.cssare not blocked. - JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. generated programmatically from existing fields (Article, Breadcrumb, FAQ, Organization), verified with the Rich ResultsRich results (formerly 'rich snippets') are enhanced search listings — stars, images, prices, breadcrumbs, video thumbnails, and more — that Google and Bing build from structured data. They're a display feature, not a ranking factor, and eligibility never guarantees they'll show. Test.
Draft / preview safety
- Production API calls use the
publishedperspective. - Every draft/preview response sends an
X-Robots-Tag: noindexheader. - Preview secret validated server-side and scoped to the Studio origin.
AEOAnswer Engine Optimization (AEO) is the practice of structuring content so engines deliver it as a direct answer — featured snippets, voice assistants, and AI search — rather than just a ranked link. Coined for voice search in 2018 and revived for the LLM era. Google's position is that it's still SEO. & monitoring
- Bing Webmaster ToolsMicrosoft's free portal for monitoring and improving how a site appears in Bing search — the peer to Google Search Console, plus IndexNow instant indexing, richer backlink data, and keyword volumes. Because Bing's index also feeds Microsoft Copilot, it doubles as a window into AI-search visibility. set up (Bing feeds ChatGPT browse); IndexNowIndexNow is an open push protocol that lets you instantly tell participating search engines (Bing, Yandex, Naver, Seznam, and Yep) which URLs you've added, changed, or removed via a simple HTTP request — and one submission is shared across all of them. Google does not use it. on publish.
- (Optional) markdown served via content negotiation for AI crawlersAI crawlers are bots from AI companies that fetch web pages to train language models, build AI-search indexes, or answer live user questions. They come in three categories, each with its own user-agent tokens and its own robots.txt controls..
The mental models
1. Sanity stores, the frontend publishes. The Content Lake holds JSON; your framework produces every byte of HTML and every SEO signal. Before debugging any Sanity SEOSanity SEO is the set of technical and content practices that make a website built on Sanity.io rank and get cited. Sanity stores content as structured JSON and produces zero HTML, so every SEO output — meta tags, sitemaps, canonicals, structured data — is built in the frontend that consumes Sanity's API. problem, ask: what is the frontend actually sending crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index.? Almost everything resolves to that.
2. RenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. mode is the product. Pick by how the content changes:
- Mostly static (blog, docs, marketing) → SSG (rebuild or ISR on publish).
- Frequently changing, must be fresh → SSR.
- Hours/days cadence, want static speed → ISR (webhook-triggered).
- Behind a login, not meant to be indexedStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. → CSR is acceptable.
- Public content you want ranked or cited by AIAn AI citation is the visible source link an AI answer engine shows next to its generated text — the clickable reference that credits the web page it used. A citation's presence is a separate thing from whether the cited page actually supports the statement, and from being retrieved (read behind the scenes) or merely mentioned (named without a link); citation is driven more by brand mentions and being retrievable than by traditional ranking. → never CSR.
3. Overrides, not requirements.
SEO fields default to the primary content and only override when an editor fills them
in — implemented with coalesce(). This keeps the editing experience clean and
guarantees every page has something for its title and description.
4. Generate, don’t author, the markup. SitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing., JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal., hreflangHreflang is an annotation (in HTML, HTTP headers, or XML sitemaps) that tells search engines which language and optional region a page targets, and which alternate versions exist. It only works when every page in the cluster references all the others., and canonicals are all derived from existing fields in code at render time. A separate editor surface for any of them just creates drift. “Derive from existing fields, at render time, in code.”
5. Defense in depth for drafts.
published perspective in production is layer one; an X-Robots-Tag: noindex header
on every preview response is layer two. Never rely on a single control to keep
unpublished content out of the index.
Sanity SEO — cheat sheet
RenderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. modes at a glance
| Mode | Where HTML is built | SEO | Best for | Watch out for |
|---|---|---|---|---|
| SSG | Build time → static files | ✅ Best | Blogs, docs, marketing | Stale until rebuild |
| SSR | Server, per request | ✅ Best | Frequently-updated content | Higher infra cost |
| ISR | Static + webhook regen | ✅ Good | Hourly/daily content | Configure the publish webhook |
| CSR | In the browser | ⚠️ Risky | Logged-in dashboards | Invisible to AI crawlersAI crawlers are bots from AI companies that fetch web pages to train language models, build AI-search indexes, or answer live user questions. They come in three categories, each with its own user-agent tokens and its own robots.txt controls. |
What’s built in the frontend (not in Sanity)
| Output | How |
|---|---|
| Body copy HTML | Serialize Portable Text (@portabletext/react / -to-html) |
| Meta tagsMeta tags are HTML elements in a page's head that pass metadata about the page to search engines and browsers. For SEO only a few matter — the title element, the meta description, and the robots meta tag — while meta keywords and most others are ignored. | generateMetadata() from a GROQ result |
| SitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. | GROQ query → XML; filter drafts; _updatedAt for lastmod |
| Canonicals | Absolute URLs from one SITE_URL, per-page |
| robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere. | Static frontend file (robots.ts in Next.js) |
| JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. | Generated from existing fields; schema-dts for types |
| RedirectsA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. | Sanity documents → frontend middleware / Worker |
GROQ snippets worth memorizing
- Override with fallback:
coalesce(seo.title, title, "") - Plain text from Portable Text:
pt::text(body) - SitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. filter:
*[... && defined(slug.current) && hideFromSearch != true]
Fast rules
- LLMA large language model (LLM) is a deep-learning model trained on massive text corpora to predict the next token and generate human-like text. LLMs use the transformer architecture and power AI search features like Google's AI Overviews (Gemini) and Bing Copilot (GPT-4).-crawlerA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. varies by provider → avoid CSR-only public content.
- Dynamic rendering is deprecated — use SSR/static/hydrationActivating server-rendered HTML in the browser by attaching JavaScript handlers..
- 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
Use this runbook when an unpublished Sanity document has a discoverable preview URL or shows up in Google Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results..
- Confirm which response leaked. Fetch the reported URL without Studio
credentials and inspect both the status and
X-Robots-Tagheader. If it returns published content, continue to step 2. If it exposes a draft, disable the preview entry point while you continue. - Check the production perspective. Trace the page’s GROQ request and confirm
production uses the
publishedperspective. If it usesdrafts, fix that query first; if it already usespublished, continue to the response layer. - Add the indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. backstop. Send
X-Robots-Tag: noindexon every preview and draft-mode response. If the header is missing on any preview route, fix the shared preview middleware rather than patching one page. - Validate preview access. Confirm the preview secret is checked server-side, is not reflected into the destination URL, and accepts requests only from the intended Studio origin. If a public preview URL still works, rotate the secret and close that route.
- Remove the indexed copy. After the response is safe, use Search ConsoleGoogle's free tool for monitoring crawling, indexing, and search performance.’s
removal workflow when the exposure is urgent, then request a fresh crawl. If the
URL should never exist publicly, keep the
noindexresponse available long enough for crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. to see it rather than blocking it in robots.txtA plain-text file at the root of a host that tells crawlers which URLs they may and may not request. It controls crawling, not indexing — a blocked URL can still be indexed if it's linked from elsewhere.. - Verify the fix. Fetch the URL while logged out and run URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version.. The
draft must be absent from the body and the preview response must carry
noindex.
Sanity SEO mistakes to avoid
Expecting Sanity to emit SEO HTML
Why it’s wrong: Sanity stores JSON; it does not publish titles, canonicals, sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing., or page HTML. Do this instead: make the frontend responsible for each output and verify the generated response rather than the Studio fields.
Choosing CSR for public content
Why it’s wrong: The initial response is an empty shell, and many AI crawlersAI crawlers are bots from AI companies that fetch web pages to train language models, build AI-search indexes, or answer live user questions. They come in three categories, each with its own user-agent tokens and its own robots.txt controls. do not execute JavaScript at all. Do this instead: ship public content with SSG, SSR, or webhook-triggered ISR.
Assuming unpublished means unindexable
Why it’s wrong: A shared preview URL can leak and be crawled. Do this instead:
use the published perspective in production and send an X-Robots-Tag: noindex
header on every preview response.
Treating Portable Text as HTML
Why it’s wrong: Portable Text is a JSON AST, so un-serialized content never
becomes crawlable body copy. Do this instead: serialize it on the server with
@portabletext/react or @portabletext/to-html.
Maintaining JSON-LD in a separate editor
Why it’s wrong: A second copy of product, article, or organization facts drifts from the visible page. Do this instead: derive JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. from the same Sanity fields at render time and validate the rendered output.
Check whether a Sanity page ships real HTML
Run this after changing renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. mode, Portable Text serialization, or page data loading. It checks the initial response, before client-side JavaScript can fill gaps.
macOS / Linux — compare normal and GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer. responses
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 first command should find the page’s real title, canonical, H1An H1 tag is the HTML `<h1>` element that marks a page's primary heading — the big visible headline at the top of the content. It helps users, search engines, and screen readers understand what the page is about., and JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. in
raw HTML. A meaningful content difference in the diff deserves investigation;
crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. and users should not receive different canonical content.
Windows PowerShell — inspect the initial response
$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 — confirm 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 the browser Console. It is a rendered-DOM check, so pair it with
the curl test: content appearing only here but not in the initial response is still
client-rendered.
Patrick's relevant free tools
- Raw vs. Rendered HTML Checker — See what's in your page's initial HTML versus after JavaScript runs — headless-Chrome rendering only when the page actually needs it, a rendering-strategy verdict (SSR / prerendered / CSR / hybrid), ~15 calibrated JavaScript-SEO checks (noindex, canonicals, robots.txt blocking, links, soft 404s), a side-by-side raw-vs-rendered diff, and shareable reports.
- Staging vs. Production SEO Diff — Compare matched release URLs across redirects, canonicals, robots directives, hreflang, selected headers, schema eligibility, and raw or optionally rendered content with honest not-evaluated states.
- Google Index Checker — Check one URL’s observable indexability blockers, or reconcile sitemap, crawl, and supplied Search Console evidence across a URL set before verifying Google’s actual state in URL Inspection.
Tools for Sanity SEO
- URL InspectionA Google Search Console feature that reports how Google sees one specific URL on a property you own. By default it shows the last-indexed snapshot; a separate \"Test live URL\" mode fetches the current version. (Google Search ConsoleA free Google service that reports how a site performs in Google Search and surfaces problems with how Google crawls, indexes, and serves it. It's first-party data straight from Google — but you don't need it to appear in results.) — see how a single URL was crawled and rendered. The rendered HTML tells you whether your Portable Text actually made it in — essential for catching CSR gaps on a Sanity frontend.
- Rich ResultsRich results (formerly 'rich snippets') are enhanced search listings — stars, images, prices, breadcrumbs, video thumbnails, and more — that Google and Bing build from structured data. They're a display feature, not a ranking factor, and eligibility never guarantees they'll show. Test — confirm your programmatic JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. is present in the rendered output after any renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. or template change.
- Screaming Frog SEO SpiderA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. — crawl with JavaScript renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. on/off to compare raw HTML vs. rendered HTML; this is how you prove whether your content is server- rendered or client-rendered.
- Ahrefs Site Audit — surfaces missing metadata, broken canonicals, redirectA redirect sends browsers and crawlers from a requested URL to a different one. An HTTP redirect specifically is a 3xx status code paired with a Location header; meta refresh and JavaScript redirects achieve a similar navigation without being a 3xx response themselves. Permanent redirects (301/308) are Google's signal the target should be canonical; temporary ones (302/303/307) aren't. chains, and indexability issues across the whole frontend.
- Bing Webmaster ToolsMicrosoft's free portal for monitoring and improving how a site appears in Bing search — the peer to Google Search Console, plus IndexNow instant indexing, richer backlink data, and keyword volumes. Because Bing's index also feeds Microsoft Copilot, it doubles as a window into AI-search visibility. — submit your sitemapA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing. and monitor Bing indexingStoring a crawled page in the search index so it can appear in results. Crawled is not the same as indexed — Google selects what to keep, and indexing isn't guaranteed. (it feeds ChatGPT browse), plus where IndexNowIndexNow is an open push protocol that lets you instantly tell participating search engines (Bing, Yandex, Naver, Seznam, and Yep) which URLs you've added, changed, or removed via a simple HTTP request — and one submission is shared across all of them. Google does not use it. submissions show up.
sanity-plugin-seo— in-Studio live SEO score, meta/OG preview, and robots control so editors get feedback at authoring time.
Test yourself: Sanity SEO
Five quick questions on how SEO works on a Sanity-backed site. Pick an answer for each, then check.
Resources worth your time
My related writing
- JavaScript SEO Issues & Best Practices — my primary reference on renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. modes, which decide everything on a Sanity frontend.
- The Beginner’s Guide to Technical SEO — where renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. and crawlingCrawling is how search engines use automated bots (like Googlebot and Bingbot) to discover URLs and download pages. A page has to be crawlable to be indexed, but crawling on its own isn't a ranking factor. 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 GooglebotGooglebot is Google's web crawler — the software that fetches pages so Google can index and rank them. It comes in two variants, Googlebot Smartphone (primary, under mobile-first indexing) and Googlebot Desktop, and runs an evergreen Chromium renderer.’s stateless rendering. (Standing disclaimer: the dynamic-rendering recommendation in that deck is now outdated — Google deprecated it.)
On this site
- SEO for a Headless CMSA headless CMS decouples content storage and editing (the backend) from how that content is rendered and delivered (the frontend), serving content over an API instead of a built-in templated 'head'. Its SEO outcomes come almost entirely from how the separate frontend renders pages. — the sibling guide; Sanity is a specific application of the same headless rules.
- JavaScript SEOMaking sure search engines can crawl, render, and index content that depends on JavaScript. — the rendering deep dive.
- CanonicalizationHow search engines pick one canonical URL among duplicates and consolidate signals onto it. — the consolidation mechanics behind your frontend’s canonical tagsA rel=\"canonical\" annotation — in the HTML <head> or an HTTP Link header — that tells search engines which URL is the preferred version of duplicate or near-duplicate content..
- AI SearchAI search uses large language models and retrieval-augmented generation (RAG) to synthesize an answer from multiple sources rather than returning a ranked list of links. Examples include Google AI Overviews, ChatGPT Search, and Perplexity. — how AI crawlersAI crawlers are bots from AI companies that fetch web pages to train language models, build AI-search indexes, or answer live user questions. They come in three categories, each with its own user-agent tokens and its own robots.txt controls. and answer enginesAnswer Engine Optimization (AEO) is the practice of structuring content so engines deliver it as a direct answer — featured snippets, voice assistants, and AI search — rather than just a ranked link. Coined for voice search in 2018 and revived for the LLM era. Google's position is that it's still SEO. behave.
From around the industry
- SEO with Sanity (Sanity) — Sanity’s own master SEO guide; start here for platform-current behavior.
- SEO Optimization course (Sanity Learn) — the hands-on Next.js course covering the SEO object, dynamic sitemapsA sitemap is a file that lists the pages, images, videos, and other files on your site so search engines can discover them. It helps discovery, but submitting a sitemap doesn't guarantee crawling or indexing., and JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal..
- Sanity SEO (Webstacks, Devon Wood) — agency guide making the “frontend handles SEO output” point clearly.
- AEO & SEO best practices for Sanity (Roboto Studio, Jono Alford) — the AEO angle and the “derive JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. from existing fields” rule.
- SEO best practices for 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 case against llms.txtllms.txt is a proposed (not adopted) Markdown file at /llms.txt that gives AI systems a curated map of a site's most important pages. Proposed by Jeremy Howard in 2024, it's read mostly by coding agents like Claude Code — not search crawlers — and Google ignores it. for large sites.
- Headless CMS SEO (Ahrefs, Despina Gavoyannis) — the broader headless playbook (content/code/design optimized independently) that Sanity sits inside.
- turbo-start-sanity (Roboto Studio, GitHub) — an open-source Sanity SEOSanity SEO is the set of technical and content practices that make a website built on Sanity.io rank and get cited. Sanity stores content as structured JSON and produces zero HTML, so every SEO output — meta tags, sitemaps, canonicals, structured data — is built in the frontend that consumes Sanity's API. starter with real
query.ts,seo-fields.ts, andseo.tsimplementations.
Sanity SEO
Sanity SEO is the set of technical and content practices that make a website built on Sanity.io rank and get cited. Sanity stores content as structured JSON and produces zero HTML, so every SEO output — meta tags, sitemaps, canonicals, structured data — is built in the frontend that consumes Sanity's API.
Related: Headless CMS SEO, JavaScript SEO
Sanity SEO
Sanity SEO refers to the technical and content work required to make websites built with Sanity.io rank in search engines and get cited by AIAn AI citation is the visible source link an AI answer engine shows next to its generated text — the clickable reference that credits the web page it used. A citation's presence is a separate thing from whether the cited page actually supports the statement, and from being retrieved (read behind the scenes) or merely mentioned (named without a link); citation is driven more by brand mentions and being retrievable than by traditional ranking. answer enginesAnswer Engine Optimization (AEO) is the practice of structuring content so engines deliver it as a direct answer — featured snippets, voice assistants, and AI search — rather than just a ranked link. Coined for voice search in 2018 and revived for the LLM era. Google's position is that it's still SEO.. Unlike a traditional CMSA content management system (CMS) is software that lets users create, manage, and publish digital content — like blog posts and pages — without writing raw code. WordPress, Drupal, and Joomla are the most common open-source CMS platforms. like WordPress, Sanity is a headless CMSA headless CMS decouples content storage and editing (the backend) from how that content is rendered and delivered (the frontend), serving content over an API instead of a built-in templated 'head'. Its SEO outcomes come almost entirely from how the separate frontend renders pages.: it stores content as structured JSON in the “Content Lake” and serves it over GROQ queries or REST, but it produces no HTML of its own. That single fact reshapes everything.
Because Sanity emits no markup, the frontend framework that consumes its API decides your SEO — Next.js, Astro, Remix, Nuxt, or anything else. The renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. mode that frontend uses (static generation or server-side renderingTurning HTML, CSS, and JavaScript into the final visual page and DOM. vs. client-side rendering) determines whether crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. and LLMsA large language model (LLM) is a deep-learning model trained on massive text corpora to predict the next token and generate human-like text. LLMs use the transformer architecture and power AI search features like Google's AI Overviews (Gemini) and Bing Copilot (GPT-4). ever see your content. Every SEO output you’d expect a CMS plugin to handle — title tagsThe title tag is the HTML title element in a page's head that specifies the document's title. It's the primary source for the SERP title link and a confirmed light ranking factor — but since August 2021 Google doesn't always show it verbatim., meta descriptionsThe meta description is an HTML head tag — `<meta name=\"description\" content=\"…\">` — that suggests a short summary of the page for the search snippet. It's not a Google ranking factor, and Google rewrites it the majority of the time, but a good one can still lift click-through., canonical tagsA rel=\"canonical\" annotation — in the HTML <head> or an HTTP Link header — that tells search engines which URL is the preferred version of duplicate or near-duplicate content., XML sitemapsAn XML sitemap is a UTF-8 file listing the canonical URLs on your site (with optional lastmod) so search engines can discover and prioritize them. It's a discovery and diagnostic aid, not a guarantee of indexing — and Google ignores its priority and changefreq tags., robots directives, and JSON-LDJSON-LD (JavaScript Object Notation for Linked Data) is a script-based structured data format, typically paired with the schema.org vocabulary to describe page content for search engines and AI systems. Google recommends it over Microdata and RDFa because it's the easiest format to implement and maintain at scale — but all three work, and structured data isn't a ranking signal. structured dataStructured data is a standardized way of labeling page content (using the schema.org vocabulary in JSON-LD, Microdata, or RDFa) so search engines can understand its meaning. It's not a direct ranking factor — its value is rich results and entity understanding. — has to be implemented deliberately in the frontend.
Three things trip up teams new to Sanity:
- There are no automatic SEO features. Sanity ≠ WordPress + Yoast. Nothing is generated for you.
- Portable Text is not HTML. Sanity stores rich text as a JSON abstract syntax tree that the frontend must serialize to HTML before crawlersA crawler — also called a spider or bot — is an automated program that fetches web pages, extracts their links, and queues new URLs to visit. Search engines use crawlers to discover and download content for their index. can read body copy.
- Drafts can leak into the index. Sanity’s CDN API can return draft documents; without a
noindexdefense, a shared preview URL can get indexed.
Done right — SSG or SSR, a reusable SEO object in the content model, programmatic JSON-LD, and a locked-down preview perspective — a Sanity-backed site can be highly optimized. The risk is treating it like a turnkey CMS and skipping the implementation work.
Related: Headless CMS SEO, JavaScript SEO
Build-time retrieval analysis plus live signals for this exact article. The automatic chunk report includes a deterministic readiness score and is ready without a model download.
Search Console
sampleGA4 traffic (28d)
sampleCloudflare traffic (7d)
sampledCrUX field data (28d, phone)
sampleGoogle NLP entities
localChangelog
Updated Jul 19, 2026.
Editorial summary and recorded change details.Summary
Update pass: verified sanity/@sanity/client and every named plugin (sanity-plugin-seo, sanity-plugin-seofields, deprecated sanity-plugin-seo-pane, @portabletext/react, @portabletext/to-html, @sanity/block-content-to-react, @portabletext/markdown) against the npm registry — no version drift found, all still current or correctly flagged as legacy/deprecated. Tempered two absolute 'AI crawlers don't run JavaScript at all' claims (beginner lens and the Advanced AI-search section) into 'typically don't render JavaScript today,' naming Google's Gemini pipeline as a documented exception and noting provider behavior isn't a fixed contract. Confirmed the headless-boundary framing (Sanity stores content, the frontend owns SEO output) and Sanity's published/drafts perspective docs are still accurate and live (all three cited docs return HTTP 200, no removals).
Change details
-
Beginner lens: changed 'the crawlers behind ChatGPT, Claude, and Perplexity don't run JavaScript at all' to a hedged 'typically don't render JavaScript,' naming Gemini's Googlebot-rendering exception.
-
Advanced lens AI-search section: changed 'LLM training crawlers ... don't execute JavaScript' to 'typically don't execute JavaScript today,' with the same Gemini exception and a note that this is provider-specific, not guaranteed.
Full comparison unavailable — no prior snapshot was archived for this revision.