Complete Documentation - Sanity SEO v1.4.0
Everything you need to know about the plugin - from installation to advanced features. This guide covers all tiers: Free, AI, and Pro (coming soon).
Whether you're a beginner or experienced developer, follow the sections that match your needs. Each section is self-contained.
What is Sanity SEO Plugin?
A complete SEO toolkit that lives inside Sanity Studio. Helps you optimize content for Google and social media.
The plugin adds an SEO panel to Sanity Studio with:
FREE TIER (Always Free):
- Live SEO Score (0-100)
- Google search preview
- Social media preview (Facebook, Twitter, LinkedIn, WhatsApp)
- Meta title & description optimization
- Keyword tracking
- Readability analysis
- Multi-language support (hreflang)
- Mobile responsiveness check
AI TIER (Pay as you use):
- AI keyword suggestions
- AI meta title generator
- AI description writer
- 3 AI providers (OpenAI, Anthropic, Groq)
- Usually costs $1-5/month
PRO TIER (Coming Soon):
- Team workflows
- Bulk editing
- Advanced analytics
- Rich snippets/Schema.orgWhy Should You Use This Plugin?
Benefits and use cases
Problems It Solves:
1. No need to jump between tools
→ Everything in Sanity Studio
2. Real-time feedback
→ See SEO score as you type
3. No broken links to production
→ Preview before publishing
4. Team collaboration
→ Assign tasks, track progress
5. Multi-site management
→ Manage many websites at once
6. Save hours on writing
→ AI can generate titles/keywords
7. Better Google rankings
→ Optimize for search engines
Who Uses It:
- Content managers writing blog posts
- Marketing teams managing multiple websites
- SEO agencies managing client sites
- Small businesses wanting better Google rankings
- Teams wanting to collaborate on SEOStep 1: Install Plugin
Takes 5 minutes. Choose your package manager.
# Using npm
npm install sanity-plugin-seo
# Using yarn
yarn add sanity-plugin-seo
# Using pnpm
pnpm add sanity-plugin-seo
# Using bun
bun add sanity-plugin-seo
That's it! Plugin is installed.
Sanity Compatibility: Works with v3, v4, and v5Step 2: Configure for Free Tier
Add plugin to your Sanity configuration file
// sanity.config.ts or sanity.config.js
import { defineConfig } from "sanity";
import { seoMetaFields } from "sanity-plugin-seo";
export default defineConfig({
name: "default",
title: "My Project",
projectId: "your-project-id",
dataset: "production",
// Add this line:
plugins: [seoMetaFields()],
// ... rest of config
});
Save the file. Restart Sanity Studio.
The SEO panel now appears on all documents!Understanding the SEO Panel
The panel has 4 tabs. Here's what each does.
TAB 1: BASIC SEO
- Meta Title: What shows in Google (60 chars)
- Meta Description: Preview text (160 chars)
- Focus Keyword: Main topic of page
- Live Score: 0-100. Higher is better.
Feedback shows what's missing
TAB 2: SOCIAL SHARING
- Title for Facebook/Twitter/LinkedIn
- Description text for social networks
- Upload custom image for sharing
- See preview of how it looks
TAB 3: ADVANCED
- Robots commands (noindex, nofollow, etc)
- hreflang for multi-language sites
- Custom meta tags
- Additional SEO settings
TAB 4: SCHEMA (PRO ONLY - Coming Soon)
- Rich snippets (star ratings, prices)
- 30+ content types supported
- JSON-LD preview
- Live validationFree Tier Features - Complete List
Everything included in the free tier
1. LIVE SEO SCORE
Shows 0-100 score in real-time
Tells you what's missing
Updates as you type
2. GOOGLE PREVIEW
See exactly how page appears in Google search
Shows title, description, URL
Character count warnings
3. SOCIAL PREVIEWS
Facebook preview
Twitter/X preview
LinkedIn preview
WhatsApp preview
4. META TAGS
Meta Title field (SEO)
Meta Description field (SEO)
Focus Keyword tracking
Keyword suggestions
5. ROBOTS CONTROL
noindex (hide from search)
nofollow (don't crawl links)
noarchive (no cache)
nosnippet (no preview)
6. MULTI-LANGUAGE
hreflang tags for each language
Tell Google which version is for which country
Supports unlimited languages
7. READABILITY
Flesch-Kincaid reading level
Check if easy to understand
Get suggestions for improvement
8. OPEN GRAPH & TWITTER
Custom titles for social sharing
Custom descriptions
Custom images
Twitter card configuration
9. CUSTOM META TAGS
Add any custom meta tags
HTML attributes
Data attributes
10. GEO CHECKLIST
Validate for Google AI Overview
Ensure content meets Google standards
Get actionable feedbackStep 3: Setup AI Features (Optional)
Add AI to auto-generate keywords and meta tags
// sanity.config.ts with AI enabled
import { defineConfig } from "sanity";
import { seoMetaFields } from "sanity-plugin-seo";
export default defineConfig({
plugins: [
seoMetaFields({
// Enable AI features
aiFeature: {
provider: "openai", // or "anthropic" or "groq"
apiKey: process.env.SANITY_STUDIO_OPENAI_KEY,
model: "gpt-4o-mini" // optional, uses default if omitted
},
// Tell plugin where your content is
// Single field:
bodyFields: ["content"],
// Multiple fields (great for sites with different document types):
// bodyFields: ["body", "content", "sections[].content"],
slugField: "slug", // Your URL slug field
// Show analytics dashboard
dashboard: true // Show SEO Health + Optimizer
})
]
});
Add to .env.local:
SANITY_STUDIO_OPENAI_KEY=sk-your-api-key-here
Now AI buttons appear in SEO panel!AI Features Explained
What each AI feature does
AI KEYWORD SUGGESTIONS
- Button: Click "Generate Keywords"
- Reads your content automatically
- Suggests relevant keywords
- You can accept or edit suggestions
- Cost: ~$0.01 per request
AI META TITLE GENERATOR
- Button: Click "Generate Title"
- Creates SEO-optimized title (60 chars)
- Based on your content
- You can edit before using
- Cost: ~$0.01 per request
AI META DESCRIPTION WRITER
- Button: Click "Generate Description"
- Creates compelling description (160 chars)
- Entices people to click
- You can edit before using
- Cost: ~$0.01 per request
READABILITY ANALYSIS
- Scores 0-100
- Tells you if easy to read
- Suggests improvements
- Works automaticallyChoosing an AI Provider
Comparison of OpenAI, Anthropic, and Groq
OPENAI (Recommended for quality)
- Model: gpt-4o-mini
- Cost: $0.15 per 1M tokens (~$2-5/month)
- Speed: Fast
- Quality: Excellent
- Setup: Sign up at openai.com
- Best for: Best quality, don't mind paying
ANTHROPIC (Fast and efficient)
- Model: claude-haiku-4-5-20251001
- Cost: $0.80 per 1M tokens (~$1-3/month)
- Speed: Very fast
- Quality: Good
- Setup: Sign up at anthropic.com
- Best for: Balance of quality and cost
GROQ (Free tier available)
- Model: llama-3.3-70b-versatile
- Cost: Free tier available, paid tiers cheap
- Speed: Fastest
- Quality: Good
- Setup: Sign up at groq.com
- Best for: Tight budget, free tier option
RECOMMENDATION:
Start with Groq (free), upgrade to OpenAI if neededStep 4: Show SEO on Your Website
Your SEO data needs to appear on your actual website
The plugin works inside Sanity Studio.
But your website also needs the SEO meta tags.
You need to:
1. Fetch SEO data from Sanity
2. Add meta tags to your website
3. Publish the page
Your website builder (Next.js, Astro, etc)
handles this automatically IF you configure it.
Different frameworks handle it differently:
- Next.js: uses generateMetadata()
- Astro: uses <title> and <meta> tags
- Vue/Nuxt: uses useHead() composable
- SvelteKit: uses <svelte:head> tag
SEE THE FRAMEWORK GUIDES BELOW for your specific setup!Complete GROQ Query Reference
Copy this to fetch all SEO data from Sanity
// lib/sanity-queries.ts
export const SEO_FRAGMENT = `{
metaTitle,
metaDescription,
focusKeyword,
seoKeywords[],
nofollowAttributes,
robotsMeta[],
metaImage {
asset->{ url }
},
openGraph {
title,
description,
siteName,
image { asset->{ url } }
},
twitter {
cardType,
site,
creator,
handle
},
hreflang[] {
locale,
url
},
additionalMetaTags[] {
metaAttributes[] {
attributeKey,
attributeType,
attributeValueString
}
},
seoStatus,
seoReviewNotes
}`;
// Usage in a query:
const pageQuery = `
*[_type == "page" && slug.current == $slug][0] {
title,
slug,
content,
seo${SEO_FRAGMENT}
}
`;Next.js Integration (App Router)
Complete setup for Next.js 15 with async params
// lib/sanity.ts
import { createClient } from "@sanity/client";
export const client = createClient({
projectId: process.env.NEXT_PUBLIC_SANITY_PROJECT_ID,
dataset: process.env.NEXT_PUBLIC_SANITY_DATASET || "production",
useCdn: false,
apiVersion: "2024-01-01",
});
// app/[slug]/page.tsx
import type { Metadata } from "next";
import { client } from "@/lib/sanity";
const SEO_QUERY = `{
metaTitle, metaDescription,
metaImage { asset->{ url } },
openGraph { title, description, image { asset->{ url } } }
}`;
export async function generateMetadata(props: {
params: Promise<{ slug: string }>;
}): Promise<Metadata> {
const { slug } = await props.params;
const page = await client.fetch(
`*[_type == "page" && slug.current == $slug][0] { title, seo${SEO_QUERY} }`,
{ slug }
);
return {
title: page?.seo?.metaTitle || page?.title,
description: page?.seo?.metaDescription,
keywords: page?.seo?.focusKeyword, // powers SEO score in Studio
openGraph: {
title: page?.seo?.openGraph?.title,
description: page?.seo?.openGraph?.description,
images: page?.seo?.metaImage?.asset?.url
? [{ url: page.seo.metaImage.asset.url }]
: [],
},
};
}
export default async function Page(props: {
params: Promise<{ slug: string }>;
}) {
const { slug } = await props.params;
const page = await client.fetch(
`*[_type == "page" && slug.current == $slug][0]`,
{ slug }
);
return <main>{page?.title}</main>;
}Astro Integration
Complete setup for Astro with SEO meta tags
// src/lib/sanity.ts
import { createClient } from "@sanity/client";
export const client = createClient({
projectId: import.meta.env.PUBLIC_SANITY_PROJECT_ID,
dataset: "production",
useCdn: false,
apiVersion: "2024-01-01",
});
// src/pages/[slug].astro
---
import { client } from "@/lib/sanity";
import Layout from "@/layouts/Layout.astro";
const { slug } = Astro.params;
const page = await client.fetch(
`*[_type == "page" && slug.current == $slug][0] {
title,
seo {
metaTitle,
metaDescription,
metaImage { asset->{ url } },
openGraph { title, description, image { asset->{ url } } }
}
}`,
{ slug }
);
if (!page) {
return Astro.redirect("/404");
}
---
<Layout
title={page.seo?.metaTitle || page.title}
description={page.seo?.metaDescription}
ogImage={page.seo?.metaImage?.asset?.url}
>
<h1>{page.title}</h1>
</Layout>Vue 3 / Nuxt Integration
Complete setup for Nuxt 3 with composables
// composables/useSeoData.ts
import { createClient } from "@sanity/client";
const client = createClient({
projectId: useRuntimeConfig().public.sanityProjectId,
dataset: "production",
useCdn: false,
apiVersion: "2024-01-01",
});
export const useSeoData = async (slug: string) => {
return await client.fetch(
`*[_type == "page" && slug.current == $slug][0] {
title,
seo {
metaTitle,
metaDescription,
metaImage { asset->{ url } },
openGraph { title, description, image { asset->{ url } } }
}
}`,
{ slug }
);
};
// pages/[slug].vue
<script setup lang="ts">
const route = useRoute();
const page = await useSeoData(route.params.slug as string);
useHead({
title: page?.seo?.metaTitle || page?.title,
meta: [
{
name: "description",
content: page?.seo?.metaDescription,
},
{
property: "og:title",
content: page?.seo?.openGraph?.title,
},
{
property: "og:description",
content: page?.seo?.openGraph?.description,
},
{
property: "og:image",
content: page?.seo?.metaImage?.asset?.url,
},
],
});
</script>
<template>
<div>
<h1>{{ page?.title }}</h1>
</div>
</template>SvelteKit Integration
Complete setup for SvelteKit with hooks
// src/lib/sanity.ts
import { createClient } from "@sanity/client";
export const client = createClient({
projectId: import.meta.env.VITE_SANITY_PROJECT_ID,
dataset: "production",
useCdn: false,
apiVersion: "2024-01-01",
});
// src/routes/[slug]/+page.ts
import type { PageLoad } from "./$types";
export const load: PageLoad = async ({ params }) => {
const page = await client.fetch(
`*[_type == "page" && slug.current == $slug][0] {
title,
seo {
metaTitle,
metaDescription,
metaImage { asset->{ url } }
}
}`,
{ slug: params.slug }
);
return { page };
};
// src/routes/[slug]/+page.svelte
<script lang="ts">
import type { PageData } from "./$types";
export let data: PageData;
$: title = data.page?.seo?.metaTitle || data.page?.title;
$: description = data.page?.seo?.metaDescription;
</script>
<svelte:head>
<title>{title}</title>
<meta name="description" content={description} />
</svelte:head>
<h1>{data.page?.title}</h1>Pro Features (Coming Soon)
Advanced features launching soon. All features built and tested.
PRO TIER INCLUDES:
1. SERP PREVIEW
Desktop & Mobile mockups
Pixel-accurate title/description truncation
Real Google search appearance
2. SCHEMA.ORG WIZARD
30+ content types supported
Articles, Products, Events, FAQs, Recipes
Live JSON-LD preview
One-click rich snippet generation
3. ADVANCED VALIDATION
5 automated checks
Duplicate title detection
Missing OG image warnings
Focus keyword placement check
Content length optimization
One-click auto-fixes
4. TEAM WORKFLOW
Draft → Review → Approved pipeline
Assign tasks to team members
Leave review notes and feedback
Track approval status
Bulk workflow actions
5. SEO HEALTH DASHBOARD
Site-wide SEO metrics
Average score across site
Document status breakdown
Issue trending over time
Export reports
6. SEO OPTIMIZER (Bulk Editor)
Edit 100 pages at once
Inline field editing
Type filtering
Bulk OG image sync
CSV import/export
Find and replace
7. WORKFLOW DASHBOARD
Site-wide status tracking
Which documents need review
Which need improvement
Which are approved
Team assignment view
STATUS: Coming Soon - Sign up for updatesTroubleshooting
Common problems and solutions
PROBLEM: SEO panel not showing in Sanity
SOLUTION:
- Restart Sanity Studio
- Make sure seoMetaFields() is in plugins array
- Add seo field to your document schema
PROBLEM: AI buttons not appearing
SOLUTION:
- Add aiFeature configuration to seoMetaFields()
- Restart Sanity Studio
- Check API key is in .env.local
- Test API key is valid
PROBLEM: Meta tags not appearing on website
SOLUTION:
- Check GROQ query is correct
- Verify client fetch is working
- Check page slug is correct
- Verify SEO fields are filled in Sanity
- Restart development server
PROBLEM: AI suggestions are bad quality
SOLUTION:
- Try different AI provider (OpenAI is best)
- Write better content body
- Use specific focus keyword
- Try different model
PROBLEM: Hydration error on website
SOLUTION:
- Check your integration code for SSR issues
- Make sure server-side and client-side data match
- Check for dynamic content without key
PROBLEM: Slug field not working
SOLUTION:
- Check slug field name matches config
- Make sure slug field is generated from title
- Regenerate slugs if changed
PROBLEM: Permission denied errors
SOLUTION:
- Check Sanity API token has right permissions
- Verify .env variables are correct
- Check CORS settings in Sanity
- Try creating new API tokenFrequently Asked Questions
Common questions answered
Q: Is the free tier really free forever?
A: Yes! Free tier has no expiration. Use it as long as you want.
Q: Can I upgrade from free to AI anytime?
A: Yes. Just add AI configuration and restart. Seamless upgrade.
Q: Which AI provider should I choose?
A: Start with Groq (free). Upgrade to OpenAI for better quality.
Q: How much does AI cost?
A: Usually $1-5/month depending on usage. Only pay for what you use.
Q: Can multiple people use the plugin?
A: Yes! Everyone in your Sanity workspace can use it.
Q: Does it work with other plugins?
A: Yes! Works alongside other Sanity plugins.
Q: Can I use it with custom fields?
A: Yes! Use bodyFields (array) and slugField to match your schema.
bodyFields supports multiple fields and nested paths like sections[].content.
Q: What is focusKeyword used for?
A: It powers the SEO score inside Studio — checks if your keyword appears
in the title, description, and body. You can also use it on your frontend:
return { keywords: page.seo.focusKeyword } in generateMetadata().
It is NOT the same as the deprecated <meta name="keywords"> tag.
Q: Is my data stored on external servers?
A: No! Your content stays in Sanity. We don't store anything.
Q: What versions of Sanity are supported?
A: Works with v3, v4, and v5.
Q: Can I remove the SEO panel from some documents?
A: Yes! Only add the seo field to documents that need it.
Q: What happens if I stop using the plugin?
A: Your SEO data stays in Sanity. Just remove the plugin.
Q: Is there a free trial for Pro?
A: Not yet. Check back for updates.
Q: How do I get support?
A: GitHub issues, email, or community forum.
Q: Can I contribute to the plugin?
A: Yes! Plugin is open source on GitHub.