
Seo Aeo Best Practices
- 4.9k installs
- 171 repo stars
- Updated July 29, 2026
- sanity-io/agent-toolkit
seo-aeo-best-practices is a Sanity skill for SEO and AEO covering metadata, structured data, EEAT, sitemaps, and AI answer optimization.
About
The seo-aeo-best-practices skill from Sanity agent-toolkit covers principles for traditional search engine optimization and answer engine optimization for AI assistants. Apply it when implementing metadata and Open Graph tags, creating sitemaps and robots.txt, adding JSON-LD structured data, optimizing for featured snippets, preparing content for ChatGPT and Perplexity answer surfaces, and evaluating quality with EEAT experience expertise authoritativeness and trustworthiness. Core concepts distinguish SEO as ranking in Google and Bing results from AEO as being selected as authoritative answers by AI systems. Reference files under references/ provide detailed guidance: eeat-principles.md for author schema and trust signals, structured-data.md for Article FAQ Breadcrumb and Product JSON-LD patterns, technical-seo.md for metadata sitemaps hreflang and robots checklists, and aeo-considerations.md for AI Overviews and crawler management. Load the single reference matching the task rather than all files at once for focused implementation work on content-heavy sites and headless CMS deployments.
- Covers both SEO for search rankings and AEO for AI answer engine selection.
- References EEAT principles, structured data, technical SEO, and AEO considerations files.
- Applies to metadata, Open Graph, sitemaps, robots.txt, hreflang, and JSON-LD markup.
- Guides featured snippet optimization and AI assistant answer surface readiness.
- Routes to focused reference docs by task instead of loading all guidance at once.
Seo Aeo Best Practices by the numbers
- 4,868 all-time installs (skills.sh)
- +188 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #146 of 1,879 Marketing & SEO skills by installs in the Skillselion catalog
- Security screen: LOW risk (skills.sh audit)
- Data as of Aug 2, 2026 (Skillselion catalog sync)
seo-aeo-best-practices capabilities & compatibility
- Capabilities
- seo and aeo principle routing · json ld structured data patterns · eeat author and trust implementation · technical seo checklist guidance · ai overview and crawler management references
- Works with
- vercel
- Use cases
- seo · documentation · copywriting
What seo-aeo-best-practices says it does
Principles for optimizing content for both traditional search engines (SEO) and AI-powered answer engines (AEO).
Google's framework for evaluating content quality.
Start with the one reference that matches the task
npx skills add https://github.com/sanity-io/agent-toolkit --skill seo-aeo-best-practicesAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 4.9k |
|---|---|
| repo stars | ★ 171 |
| Security audit | 3 / 3 scanners passed |
| Last updated | July 29, 2026 |
| Repository | sanity-io/agent-toolkit ↗ |
How do I optimize pages for both Google search rankings and AI answer engine citation?
Implement SEO and AEO best practices for metadata, structured data, sitemaps, hreflang, EEAT, and AI answer surface optimization.
Who is it for?
Developers implementing page SEO, schema markup, international SEO, or AI-overview readiness on content sites.
Skip if: Skip when you need paid ads or social media campaigns; this skill targets organic search and AEO.
When should I use this skill?
User implements page SEO, JSON-LD schema, sitemaps, hreflang, EEAT, or AI answer surface optimization.
What you get
Implemented metadata, structured data, technical SEO checklist items, and AEO-ready content patterns.
- Metadata and Open Graph implementation
- JSON-LD structured data markup
- Technical SEO checklist completion
By the numbers
- Four reference doc areas
- EEAT framework covered
- JSON-LD Article FAQ Breadcrumb Product patterns
Files
SEO & AEO Best Practices
Principles for optimizing content for both traditional search engines (SEO) and AI-powered answer engines (AEO). Includes Google's EEAT guidelines and structured data implementation.
When to Apply
Reference these guidelines when:
- Implementing metadata and Open Graph tags
- Creating sitemaps and robots.txt
- Adding JSON-LD structured data
- Optimizing content for featured snippets
- Preparing content for AI assistants (ChatGPT, Perplexity, etc.)
- Evaluating content quality using EEAT principles
Core Concepts
SEO (Search Engine Optimization)
Optimizing content to rank well in traditional search results (Google, Bing).
AEO (Answer Engine Optimization)
Optimizing content to be selected as authoritative answers by AI systems.
EEAT (Experience, Expertise, Authoritativeness, Trustworthiness)
Google's framework for evaluating content quality.
References
Start with the one reference that matches the task, such as technical SEO, structured data, EEAT, or AI-answer readiness. See references/ for detailed guidance:
references/eeat-principles.md— EEAT implementation and author schemareferences/structured-data.md— JSON-LD patterns (Article, FAQ, Breadcrumb, Product)references/technical-seo.md— Technical SEO checklist (metadata, sitemaps, hreflang, robots.txt)references/aeo-considerations.md— AI/AEO considerations (AI Overviews, crawler management)
AI/AEO Considerations
Answer Engine Optimization (AEO) prepares content to be selected as authoritative answers by AI systems like ChatGPT, Perplexity, Google AI Overviews, and Bing Copilot.
How AI Selects Answers
AI systems evaluate content based on:
1. Clarity: Is the answer direct and easy to extract? 2. Authority: Is the source trustworthy? 3. Comprehensiveness: Does it fully address the question? 4. Recency: Is the information up to date? 5. Structure: Can the AI parse and understand it?
Content Structure for AI
Direct Answers First
Lead with the answer, then explain.
Bad:
The history of JavaScript dates back to 1995 when Brendan Eich... [500 words later] ...JavaScript runs in the browser.
Good:
JavaScript is a programming language that runs in web browsers. It was created in 1995 by Brendan Eich...
Clear Headings
Use descriptive H2/H3 headings that match user questions.
Bad: "Overview" → "Details" → "More Information" Good: "What is X?" → "How does X work?" → "When should you use X?"
Lists and Tables
AI extracts structured information more easily than prose.
## Benefits of Structured Content
- **Reusability:** Use content across channels
- **Flexibility:** Change presentation without changing content
- **Scalability:** Manage large content volumesFAQ Format
Question-answer pairs are ideal for AI extraction.
// Schema for AI-friendly FAQs
defineType({
name: 'faq',
type: 'document',
fields: [
defineField({ name: 'question', type: 'string' }),
defineField({ name: 'answer', type: 'text' }),
defineField({ name: 'category', type: 'reference', to: [{ type: 'faqCategory' }] }),
]
})Technical Implementation
Structured Data (Critical)
JSON-LD helps AI understand content type and relationships.
// FAQ structured data
const faqSchema = {
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: faqs.map(faq => ({
"@type": "Question",
name: faq.question,
acceptedAnswer: {
"@type": "Answer",
text: faq.answer
}
}))
}Canonical Content
Ensure AI finds your authoritative version, not copies.
- Set canonical URLs
- Avoid duplicate content across pages
- Use
rel="canonical"for syndicated content
Freshness Signals
AI systems prefer current information.
- Display publish and update dates prominently
- Update content regularly with substantive changes (superficial updates like changing dates without meaningful edits can be counterproductive)
- Use
dateModifiedin structured data
Content Quality Signals
Author Credentials
AI systems increasingly check author authority.
- Display author name and credentials
- Link to author profiles
- Include author structured data
Citations and Sources
Linking to authoritative sources increases trust.
- Cite primary sources
- Link to studies, documentation, official sources
- Avoid circular citations (sites citing each other)
Comprehensive Coverage
AI prefers content that fully answers questions.
- Cover related questions users might have
- Include definitions for technical terms
- Address common misconceptions
Google AI Overviews
Google's AI Overviews (formerly SGE) now appear in many search results. To optimize:
- Be the cited source: AI Overviews cite specific pages. Concise, authoritative answers increase citation likelihood.
- Structure for extraction: Use clear headings, direct answers, and lists that AI can easily parse.
- Cover follow-up questions: AI Overviews often address related queries. Anticipate and answer them on the same page or link to dedicated pages.
- Monitor in Search Console: Google Search Console provides data on AI Overview impressions and clicks.
AI Crawler Management
Make conscious decisions about which AI systems can crawl your content:
- robots.txt directives: Use
User-agent: GPTBot,ClaudeBot,PerplexityBot,Google-Extendedto control access. - Allowing crawlers increases chances of being cited as a source in AI responses.
- Blocking crawlers prevents content from being used in AI training (but may reduce AI citations).
- Review your policy regularly — this is one of the most actively evolving areas of SEO.
Measuring AEO Success
Monitor AI Mentions
Track when AI assistants cite your content:
- Use Google Search Console's AI Overview data for impression and click tracking
- Monitor referral traffic from AI platforms (Perplexity, ChatGPT, Bing Copilot)
- Search for your brand + "according to" in AI assistants
- Consider third-party AEO tracking tools for comprehensive monitoring
Track Zero-Click Queries
If AI answers questions directly, traditional rankings matter less.
Featured Snippet Capture
Featured snippets often become AI answers. Track which you own.
AEO vs SEO Balance
AEO and SEO largely align—quality content serves both. Key differences:
| Aspect | SEO Focus | AEO Focus |
|---|---|---|
| Goal | Rank on page 1 | Be THE answer |
| Format | Varies | Direct, structured |
| Length | Often longer | Concise + comprehensive |
| Links | Link building | Source citations |
EEAT Principles
Google's EEAT framework (Experience, Expertise, Authoritativeness, Trustworthiness) guides how content quality is evaluated. This applies to both SEO rankings and AI answer selection.
The Four Pillars
Experience
First-hand or life experience with the topic.
Signals:
- Personal anecdotes and case studies
- "I tested this" content
- Real-world results and screenshots
- User-generated reviews
Implementation:
- Include author bios with relevant experience
- Add "About the Author" sections
- Feature customer testimonials
- Show real examples, not just theory
Expertise
Knowledge and skill in the subject area.
Signals:
- Credentials and qualifications
- Depth of content coverage
- Technical accuracy
- Citations to authoritative sources
Implementation:
- Display author credentials
- Link to primary sources
- Cover topics comprehensively
- Keep content technically accurate and updated
Authoritativeness
Recognition as a go-to source in the field.
Signals:
- Backlinks from respected sites
- Mentions in industry publications
- Social proof and follower counts
- Brand recognition
Implementation:
- Build thought leadership content
- Contribute to industry publications
- Maintain consistent publishing
- Develop recognizable brand voice
Trustworthiness
Accuracy, transparency, and legitimacy.
Signals:
- Clear authorship and contact info
- Accurate, fact-checked content
- Secure website (HTTPS)
- Privacy policy and terms
Implementation:
- Display clear author attribution
- Include publication and update dates
- Provide contact information
- Use HTTPS and maintain security
Sanity Implementation
// Author schema with EEAT signals
defineType({
name: 'author',
type: 'document',
fields: [
defineField({ name: 'name', type: 'string' }),
defineField({ name: 'role', type: 'string' }),
defineField({ name: 'bio', type: 'text' }),
defineField({ name: 'credentials', type: 'array', of: [{ type: 'string' }] }),
defineField({ name: 'image', type: 'image' }),
// sameAs: used for schema.org Person structured data output
defineField({ name: 'sameAs', type: 'array', of: [{ type: 'url' }],
description: 'Canonical profile URLs (LinkedIn, Twitter, etc.) for schema.org Person'
}),
// socialLinks: used for display purposes (platform icons, labels)
defineField({
name: 'socialLinks',
type: 'array',
of: [{ type: 'object', fields: [
defineField({ name: 'platform', type: 'string' }),
defineField({ name: 'url', type: 'url' })
]}],
description: 'Social links for display in the UI. Use sameAs for structured data output.'
}),
]
})
// Content with EEAT metadata
defineType({
name: 'post',
fields: [
defineField({ name: 'author', type: 'reference', to: [{ type: 'author' }] }),
defineField({ name: 'publishedAt', type: 'datetime' }),
defineField({ name: 'updatedAt', type: 'datetime' }),
defineField({
name: 'reviewedBy',
type: 'reference',
to: [{ type: 'author' }],
description: 'Expert reviewer for fact-checking'
}),
defineField({
name: 'sources',
type: 'array',
of: [{ type: 'url' }],
description: 'Citations and references'
}),
]
})YMYL Considerations
"Your Money or Your Life" topics (health, finance, legal, safety) require extra EEAT rigor:
- Medical content reviewed by healthcare professionals
- Financial advice from certified experts
- Legal content reviewed by attorneys
- Clear disclaimers where appropriate
Structured Data (JSON-LD)
Structured data helps search engines and AI understand your content. JSON-LD is the recommended format.
Why Structured Data Matters
- Rich snippets: Enhanced search result appearance
- Knowledge panels: Featured information boxes
- AI training: Better content understanding
- Voice search: Answer selection for voice queries
Common Schema Types
Article / Blog Post
import { Article, WithContext } from 'schema-dts'
const articleSchema: WithContext<Article> = {
"@context": "https://schema.org",
"@type": "Article",
headline: post.title,
description: post.excerpt,
image: post.image?.url,
datePublished: post.publishedAt,
dateModified: post.updatedAt,
author: {
"@type": "Person",
name: post.author.name,
url: post.author.url
},
publisher: {
"@type": "Organization",
name: "Your Company",
logo: {
"@type": "ImageObject",
url: "https://example.com/logo.png"
}
}
}FAQ Page
import { FAQPage, WithContext } from 'schema-dts'
const faqSchema: WithContext<FAQPage> = {
"@context": "https://schema.org",
"@type": "FAQPage",
mainEntity: faqs.map(faq => ({
"@type": "Question",
name: faq.question,
acceptedAnswer: {
"@type": "Answer",
text: faq.answer // Plain text, use pt::text() in GROQ
}
}))
}Organization
import { Organization, WithContext } from 'schema-dts'
const orgSchema: WithContext<Organization> = {
"@context": "https://schema.org",
"@type": "Organization",
name: "Your Company",
url: "https://example.com",
logo: "https://example.com/logo.png",
sameAs: [
"https://twitter.com/company",
"https://linkedin.com/company/company"
],
contactPoint: {
"@type": "ContactPoint",
telephone: "+1-555-555-5555",
contactType: "customer service"
}
}Product
import { Product, WithContext } from 'schema-dts'
const productSchema: WithContext<Product> = {
"@context": "https://schema.org",
"@type": "Product",
name: product.name,
description: product.description,
image: product.images,
offers: {
"@type": "Offer",
price: product.price,
priceCurrency: "USD",
availability: "https://schema.org/InStock"
},
aggregateRating: product.rating ? {
"@type": "AggregateRating",
ratingValue: product.rating.average,
reviewCount: product.rating.count
} : undefined
}Breadcrumb
import { BreadcrumbList, WithContext } from 'schema-dts'
const breadcrumbSchema: WithContext<BreadcrumbList> = {
"@context": "https://schema.org",
"@type": "BreadcrumbList",
itemListElement: breadcrumbs.map((crumb, index) => ({
"@type": "ListItem",
position: index + 1, // schema.org positions are 1-based
name: crumb.title,
item: `https://example.com${crumb.path}`
}))
}Combining Multiple Schemas (@graph)
Real-world pages often need multiple schema types. Use @graph to combine them. The @context is defined once at the top level — omit it from individual schema generators when used inside @graph:
const pageSchema = {
"@context": "https://schema.org",
"@graph": [
generateArticleSchema(post), // No @context needed here
generateBreadcrumbSchema(breadcrumbs),
generateOrganizationSchema(),
]
}Implementation in Next.js
// Component to render JSON-LD
// Ensure data comes from trusted sources (your CMS).
// If data could contain user-generated content, strip HTML tags
// and escape special characters before passing to JSON.stringify.
function JsonLd({ data }: { data: WithContext<Thing> }) {
return (
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(data) }}
/>
)
}
// Usage in page
export default function PostPage({ post }) {
return (
<>
<JsonLd data={generateArticleSchema(post)} />
<article>...</article>
</>
)
}GROQ for Plain Text
Structured data often needs plain text, not rich text:
*[_type == "faq"]{
question,
"answer": pt::text(answerRichText) // Convert Portable Text to plain string
}Testing Tools
Technical SEO Checklist
Essential technical SEO elements for modern web applications.
Table of Contents
- Metadata
- Sitemaps
- Canonical URLs
- Redirects
- Performance
- Robots.txt
- International SEO
Metadata
Title Tags
- Unique per page
- 50-60 characters
- Primary keyword near the beginning
- Brand name at the end (optional)
Meta Descriptions
- Unique per page
- 150-160 characters
- Include call-to-action
- Contain relevant keywords
Open Graph
<meta property="og:title" content="Page Title" />
<meta property="og:description" content="Description" />
<meta property="og:image" content="https://example.com/image.jpg" />
<meta property="og:url" content="https://example.com/page" />
<meta property="og:type" content="article" />Sanity + Next.js Implementation
export async function generateMetadata({ params }): Promise<Metadata> {
const { data } = await sanityFetch({
query: PAGE_QUERY,
stega: false, // Critical: no stega in metadata
})
return {
title: data.seo?.title || data.title,
description: data.seo?.description,
openGraph: {
images: data.seo?.image ? [{
url: urlFor(data.seo.image).width(1200).height(630).url(),
width: 1200,
height: 630,
}] : [],
},
robots: data.seo?.noIndex ? 'noindex' : undefined,
}
}Sitemaps
Dynamic sitemap from CMS content:
// app/sitemap.ts
import { MetadataRoute } from 'next'
export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
const pages = await client.fetch(`
*[_type in ["page", "post"] && defined(slug.current) && seo.noIndex != true]{
"url": select(
_type == "page" => "/" + slug.current,
_type == "post" => "/blog/" + slug.current
),
_updatedAt
}
`)
return pages.map(page => ({
url: `https://example.com${page.url}`,
lastModified: new Date(page._updatedAt),
// Note: changeFrequency and priority are largely ignored by Google
// but may be used by other search engines
}))
}Canonical URLs
Prevent duplicate content issues:
export async function generateMetadata({ params }): Promise<Metadata> {
return {
alternates: {
canonical: `https://example.com/${params.slug}`,
},
}
}Redirects
CMS-managed redirects:
// next.config.ts
async redirects() {
const redirects = await client.fetch(`
*[_type == "redirect" && isEnabled == true]{
source,
destination,
permanent
}
`)
return redirects
}Performance
Core Web Vitals impact rankings:
- LCP (Largest Contentful Paint): < 2.5s
- INP (Interaction to Next Paint): < 200ms
- CLS (Cumulative Layout Shift): < 0.1
Image Optimization (Next.js example)
- Use
next/imagewith Sanity URL builder - Serve WebP/AVIF formats
- Implement LQIP blur placeholders
- Set explicit dimensions
Font Loading (Next.js example)
// Prevent layout shift
import { Inter } from 'next/font/google'
const inter = Inter({ subsets: ['latin'], display: 'swap' })Robots.txt
# public/robots.txt
User-agent: *
Allow: /
Disallow: /api/
Disallow: /studio/
# AI crawlers — allow or block based on your content strategy
# Uncomment to block specific AI crawlers:
# User-agent: GPTBot
# Disallow: /
# User-agent: ClaudeBot
# Disallow: /
# User-agent: PerplexityBot
# Disallow: /
# User-agent: Google-Extended
# Disallow: /
Sitemap: https://example.com/sitemap.xmlAI crawler considerations: Decide whether AI training crawlers should access your content. Blocking Google-Extended prevents AI training use while still allowing Google Search indexing. Review your policy regularly as this landscape evolves.
International SEO (hreflang)
For multi-language sites, implement hreflang tags to indicate language/region variants:
export async function generateMetadata({ params }: { params: Promise<{ lang: string; slug: string }> }): Promise<Metadata> {
const { lang, slug } = await params
return {
alternates: {
canonical: `https://example.com/${lang}/${slug}`,
languages: {
'en': `https://example.com/en/${slug}`,
'de': `https://example.com/de/${slug}`,
'x-default': `https://example.com/en/${slug}`,
},
},
}
}Include all language variants in sitemaps with hreflang annotations for proper indexing.
Related skills
How it compares
seo-aeo-best-practices is a Sanity skill for SEO and AEO covering metadata, structured data, EEAT, sitemaps, and AI answer optimization, not a generic alternative.
FAQ
Who is seo-aeo-best-practices for?
Developers and content engineers implementing technical SEO and AEO on Sanity or headless content sites.
When should I use seo-aeo-best-practices?
When adding metadata, structured data, sitemaps, EEAT signals, or optimizing for AI answer engines.
Is seo-aeo-best-practices safe to install?
Review the Security Audits panel on this page before installing in production.