
Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag storeThe SEO Pane plugin is exactly what you're looking for – it brings Yoast-style SEO analysis directly into Sanity Studio. Here's what you need to know to get it working with Next.js:
Install the plugin in your Sanity Studio project:
npm install sanity-plugin-seo-paneThe plugin works as a View Pane in your Studio's Structure Builder. You'll need to configure it in your desk structure to specify where your SEO fields live and how to preview your front-end:
// ./src/deskStructure.js (or sanity.config.ts)
import { SEOPane } from 'sanity-plugin-seo-pane'
S.view
.component(SEOPane)
.options({
keywords: `seo.keywords`, // dot-notated path to your keywords field
synonyms: `seo.synonyms`, // path to synonyms field
url: (doc) => resolveProductionUrl(doc), // function that returns preview URL
})
.title('SEO')The plugin needs to fetch your rendered front-end to analyze it. The url function should return the preview URL for your document – similar to what you'd use for Live Preview.
Since the plugin fetches your Next.js site from the Studio, you'll need to handle CORS in your preview API route:
// pages/api/preview.js
const corsOrigin = process.env.NODE_ENV === 'development'
? `http://localhost:3333`
: `https://your-studio.sanity.studio`
res.setHeader('Access-Control-Allow-Origin', corsOrigin)
res.setHeader('Access-Control-Allow-Credentials', true)The plugin appends ?fetch=true to preview URLs. Your preview route should detect this and return the page HTML as a string instead of redirecting:
// pages/api/preview.js
if (req?.query?.fetch === 'true') {
const proto = process.env.NODE_ENV === 'development' ? `http://` : `https://`
const host = req.headers.host
const pathname = req?.query?.slug ?? `/`
const absoluteUrl = new URL(`${proto}${host}${pathname}`).toString()
const previewHtml = await fetch(absoluteUrl, {
credentials: `include`,
headers: {Cookie: req.headers.cookie},
})
.then((previewRes) => previewRes.text())
.catch((err) => console.error(err))
return res.send(previewHtml)
}The plugin looks for content in your HTML. Add this attribute to your main content container:
<div data-content="main">
<!-- Your main content here -->
</div>Or use a standard <main> tag as a fallback.
Include a canonical tag in your page head for proper URL detection:
<link rel="canonical" href="https://example.com/your-page" />For Next.js 13+ with App Router / Vite:
You may need to add polyfills for Node.js built-ins that the underlying yoastseo package requires:
// sanity.cli.ts
import {nodePolyfills} from 'vite-plugin-node-polyfills'
export default defineCliConfig({
vite: (prev) => ({
...prev,
plugins: [
...prev.plugins,
nodePolyfills({ util: true }),
],
define: {
...prev.define,
'process.env': {},
},
}),
})For embedded Studio in Next.js:
Update your next.config.mjs:
const config = {
experimental: {
esmExternals: 'loose'
},
}Once configured, you'll see real-time Yoast-style analysis as you edit your content, including:
The plugin is maintained by Simeon Griggs from Sanity's team, and there's a detailed blog post walking through its features. The GitHub repo has full documentation and examples.
This should give you the Yoast-like experience you're looking for! The key is getting the preview URL and CORS configuration right so the plugin can analyze your rendered pages.
Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.
Content operations
Content backend


The only platform powering content operations
By Industry


Tecovas strengthens their customer connections
Build and Share

Grab your gear: The official Sanity swag store
Read Grab your gear: The official Sanity swag store