Sanity
Overview
Sanity is a modern headless content management system (CMS) that offers a highly customizable and developer-friendly platform for managing structured content. Built for modern web applications, mobile apps, and omnichannel digital experiences, Sanity stands out with its real-time collaboration, GROQ query language, Portable Text content format, and completely customizable Sanity Studio interface.
Unlike traditional CMSs, Sanity treats content as structured data, delivering it via APIs to any frontend framework. This API-first approach makes it ideal for teams building with Next.js, Gatsby, Nuxt, React, Vue, or any JavaScript framework.
Best For: Developers, agencies, and enterprises seeking a flexible, API-first headless CMS with real-time collaboration and custom content modeling. Market Position: Competes with Contentful, Prismic, and Strapi by offering superior developer experience, real-time features, and unmatched customization. Popular Use Cases: Marketing sites, e-commerce, blogs, documentation, digital products, multi-brand websites, and headless commerce.
Analytics Capabilities
Sanity is a headless CMS, meaning analytics are implemented in your frontend application (Next.js, Gatsby, Nuxt, React, etc.), not in Sanity Studio itself. However, Sanity's content structure and APIs provide excellent opportunities for rich analytics tracking:
- Content metadata tracking - Track which content types, authors, categories perform best
- GROQ-powered analytics queries - Query analytics data alongside content
- Real-time content preview tracking - Monitor preview sessions separately from published content
- Portable Text engagement - Track how users interact with rich text content
- Multi-dataset analytics - Separate tracking for production, staging, and preview environments
- Webhook-triggered server-side events - Send server-side events when content changes
Quick Links
- Integrations - Set up Google Analytics, GTM, Meta Pixel
- Troubleshooting - Fix tracking and performance issues
- User Management - Manage team access in Sanity
Key Sanity Features for Developers
1. GROQ Query Language
GROQ (Graph-Relational Object Queries) is Sanity's open-source query language designed for querying JSON documents. It's more intuitive than GraphQL for many use cases and provides powerful filtering, projections, and joins.
Why GROQ Matters:
- Simpler syntax than GraphQL for most queries
- Powerful filtering with operators like
&&,||,match,in - Projections to reshape data exactly as needed
- References and joins to fetch related content in one query
- No schema required - query any field directly
Example GROQ Queries:
// Fetch all published blog posts with author info
*[_type == "post" && publishedAt < now()] | order(publishedAt desc) {
_id,
title,
slug,
publishedAt,
"author": author->name,
"categories": categories[]->title,
mainImage {
asset-> {
url,
metadata {
lqip,
dimensions
}
}
}
}
// Search posts by keyword
*[_type == "post" && title match $searchTerm] {
title,
slug,
excerpt
}
// Fetch a single post with all references
*[_type == "post" && slug.current == $slug][0] {
...,
author->,
categories[]->,
relatedPosts[]->{
title,
slug,
mainImage
}
}
// Count posts by category
*[_type == "category"] {
_id,
title,
"postCount": count(*[_type == "post" && references(^._id)])
}
GROQ vs GraphQL:
- GROQ: More concise, no schema required, powerful filtering, easier learning curve
- GraphQL: Type-safe, IDE autocomplete, familiar to many developers, broader ecosystem
- Sanity supports both - use GROQ for flexibility or GraphQL for type safety
2. Portable Text
Portable Text is Sanity's JSON-based rich text format that represents content as structured data rather than HTML. This makes content truly portable across platforms and enables custom rendering.
Why Portable Text Matters:
- Platform-agnostic - Same content renders on web, mobile, AR/VR, voice assistants
- Structured data - Content is queryable, transformable, and version-controllable
- Custom rendering - Define exactly how each content type appears
- Embed anything - Images, videos, code blocks, custom components inline
- Serialization - Convert to HTML, Markdown, plain text, or custom formats
Portable Text Structure:
[
{
"_type": "block",
"_key": "abc123",
"style": "h2",
"children": [
{
"_type": "span",
"text": "This is a heading"
}
]
},
{
"_type": "block",
"children": [
{
"_type": "span",
"text": "This is a paragraph with ",
"marks": []
},
{
"_type": "span",
"text": "bold text",
"marks": ["strong"]
}
]
},
{
"_type": "image",
"asset": {
"_ref": "image-abc123-1920x1080-jpg"
},
"alt": "Description"
}
]
Rendering Portable Text:
// React example with @portabletext/react
import { PortableText } from '@portabletext/react'
const components = {
block: {
h2: ({children}) => <h2 className="text-3xl font-bold">{children}</h2>,
normal: ({children}) => <p className="my-4">{children}</p>,
},
marks: {
link: ({value, children}) => (
<a href={value.href} className="text-blue-600 hover:underline">
{children}
</a>
),
},
types: {
image: ({value}) => (
<img
src={urlFor(value.asset).width(800).url()}
alt={value.alt}
loading="lazy"
/>
),
code: ({value}) => (
<pre className="bg-gray-900 text-white p-4 rounded">
<code className={`language-${value.language}`}>
{value.code}
</code>
</pre>
),
}
}
export function Article({ content }) {
return <PortableText value={content} components={components} />
}
3. Real-Time Collaboration
Sanity Studio provides real-time collaborative editing similar to Google Docs, where multiple users can edit content simultaneously.
Real-Time Features:
- Live presence indicators - See who's editing what in real-time
- Automatic conflict resolution - Merge changes from multiple editors
- Instant synchronization - Changes appear immediately for all users
- Activity feeds - See recent edits and changes across your project
- Document locking - Optional locking for specific workflows
Real-Time in Your Frontend:
You can also subscribe to real-time updates in your frontend application:
import { client } from '@/lib/sanity.client'
// Listen for changes to a specific document
const subscription = client
.listen('*[_type == "post" && slug.current == $slug]', { slug: 'my-post' })
.subscribe(update => {
console.log('Document updated:', update)
// Refresh your UI with new content
})
// Clean up subscription
subscription.unsubscribe()
Use Cases:
- Content preview - Show live preview as editors make changes
- Notification systems - Alert users when content they care about changes
- Real-time dashboards - Display up-to-the-second analytics or content stats
- Collaborative tools - Build custom collaborative features
4. Sanity Studio Customization
Sanity Studio is the open-source editing interface for Sanity. It's built with React and is 100% customizable.
Customization Options:
A. Custom Input Components
Replace default inputs with custom UI:
// schemas/product.ts
export default {
name: 'product',
type: 'document',
fields: [
{
name: 'price',
type: 'number',
components: {
input: PriceInput // Custom component
}
}
]
}
// components/PriceInput.tsx
export function PriceInput(props) {
return (
<div>
<label>Price (USD)</label>
<input
type="number"
value={props.value}
onChange={(e) => props.onChange(parseFloat(e.target.value))}
/>
<span className="preview">
${props.value?.toFixed(2) || '0.00'}
</span>
</div>
)
}
B. Custom Document Actions
Add custom actions to the document toolbar:
// sanity.config.ts
import { defineConfig } from 'sanity'
export default defineConfig({
// ...
document: {
actions: (prev, context) => {
return [
...prev,
// Custom action: Send to translation service
{
label: 'Send to Translation',
onHandle: () => {
// Send document to translation API
}
}
]
}
}
})
C. Custom Desk Structure
Organize content with custom navigation:
// deskStructure.ts
import { StructureBuilder } from 'sanity/desk'
export const deskStructure = (S: StructureBuilder) =>
S.list()
.title('Content')
.items([
S.listItem()
.title('Published Posts')
.child(
S.documentList()
.title('Published Posts')
.filter('_type == "post" && publishedAt < now()')
),
S.listItem()
.title('Drafts')
.child(
S.documentList()
.title('Draft Posts')
.filter('_type == "post" && !defined(publishedAt)')
),
S.divider(),
...S.documentTypeListItems()
])
D. Custom Widgets & Tools
Add custom widgets to the Studio:
// sanity.config.ts
export default defineConfig({
// ...
plugins: [
// Custom widget
{
name: 'analytics-widget',
component: AnalyticsDashboard
}
]
})
E. Themes & Branding
Customize Studio appearance:
// sanity.config.ts
export default defineConfig({
// ...
theme: {
fonts: {
text: {
family: 'Inter, sans-serif'
}
},
colors: {
primary: {
base: '#your-brand-color'
}
}
},
studio: {
components: {
logo: MyCustomLogo
}
}
})
History & Evolution
Sanity was founded in 2015 by a team of developers who wanted to create a better content management experience for modern development teams.
- 2015: Founded with vision of real-time collaboration and flexible content modeling
- 2016: Launched Sanity Studio and GROQ query language
- 2017: Introduced Portable Text format
- 2018: Reached 1,000+ projects, expanded plugin ecosystem
- 2019: GraphQL support added alongside GROQ
- 2020: Content Lake architecture introduced for improved scalability
- 2021: Raised Series B funding, reached 50,000+ projects
- 2022: Launched Sanity Compose (visual page builder)
- 2023-Present: Continued growth with AI features, improved real-time capabilities, and enhanced developer tools
Key Features & Capabilities
1. Flexible Content Modeling
- JavaScript-based schemas - Define content types with code, not through a UI
- Custom validation - Write validation rules in JavaScript
- Conditional fields - Show/hide fields based on other field values
- Recursive structures - Support for nested and self-referencing content
2. Real-Time Collaboration & Editing
- Live editing - Multiple users edit simultaneously with instant updates
- Presence indicators - See who's editing in real-time
- Revision history - Complete audit trail of all changes
- Document versioning - Roll back to any previous version
3. Powerful API Support
- GROQ API - Query language designed for JSON documents
- GraphQL API - Type-safe queries with autocomplete
- REST API - Standard HTTP interface for CRUD operations
- Real-time subscriptions - Listen to content changes
- CDN-cached reads - Fast content delivery globally
4. Customizable Studio Interface
- Open-source Studio - Built with React, fully customizable
- Custom input components - Replace any field UI
- Plugin ecosystem - Hundreds of community plugins
- Custom workflows - Define approval processes, publishing schedules
- Branding - Match Studio to your brand identity
5. Scalability & Performance
- Content Lake architecture - Distributed, globally available content
- Asset CDN - Automatic image optimization and delivery
- Query caching - Fast responses with intelligent cache invalidation
- Multi-dataset support - Separate environments (prod, staging, dev)
- 99.99% uptime SLA - Enterprise-grade reliability
Sanity vs Competitors
| Feature | Sanity | Contentful | Prismic | Strapi |
|---|---|---|---|---|
| Ease of Use | Easy (dev-friendly) | Moderate | Easy (editor-friendly) | Moderate |
| Customization | Very High | High | Moderate | Very High |
| Real-Time Collaboration | Built-In | Limited | Basic | No |
| Query Language | GROQ + GraphQL | GraphQL only | REST API | REST + GraphQL |
| API Capabilities | Excellent | Excellent | Good | Excellent |
| Developer Experience | Outstanding | Good | Moderate | Good |
| Studio Customization | 100% customizable | Limited | Limited | Customizable |
| Pricing | Free tier, paid scale | Free tier, paid scale | Free tier, paid scale | Free (self-hosted) |
| Hosting | Cloud-hosted | Cloud-hosted | Cloud-hosted | Self-hosted or cloud |
| Image Optimization | Built-in CDN | Built-in CDN | Built-in CDN | Manual |
When to Choose Sanity:
- Need real-time collaboration features
- Want complete control over Studio UI/UX
- Prefer GROQ's simpler query syntax
- Building with Next.js, Gatsby, or React frameworks
- Need Portable Text for cross-platform content
- Require custom content workflows
When to Choose Alternatives:
- Contentful: Need mature enterprise features and established ecosystem
- Prismic: Want editor-friendly UI with minimal developer setup
- Strapi: Need self-hosted solution or open-source flexibility
Platform-Specific Considerations
Frontend Framework Integration
Sanity works with any frontend framework, but has excellent support for:
Next.js:
- Official
next-sanitypackage - Optimized for App Router and Pages Router
- Built-in image optimization with Sanity CDN
- ISR (Incremental Static Regeneration) support
Gatsby:
gatsby-source-sanityplugin- GraphQL integration
- Image optimization with gatsby-plugin-image
- Build-time content fetching
Nuxt:
@nuxtjs/sanitymodule- SSR and SSG support
- Vue component examples
- Sanity image loader
SvelteKit:
- Direct Sanity client integration
- Server-side data loading
- TypeScript support
Multi-Environment Setup
Sanity supports multiple datasets for different environments:
// Development
const devClient = createClient({
projectId: 'your-project-id',
dataset: 'development',
useCdn: false, // Don't use CDN for dev
})
// Production
const prodClient = createClient({
projectId: 'your-project-id',
dataset: 'production',
useCdn: true, // Use CDN for prod
})
Content Preview & Draft Mode
Enable content preview before publishing:
// Next.js Draft Mode
// app/api/draft/route.ts
export async function GET(request: Request) {
const { searchParams } = new URL(request.url)
const secret = searchParams.get('secret')
const slug = searchParams.get('slug')
// Verify secret
if (secret !== process.env.SANITY_PREVIEW_SECRET) {
return new Response('Invalid token', { status: 401 })
}
// Enable Draft Mode
draftMode().enable()
// Redirect to preview
redirect(`/blog/${slug}`)
}
// Fetch with drafts in page
import { draftMode } from 'next/headers'
export default async function BlogPost({ params }) {
const { isEnabled } = draftMode()
const query = `*[_type == "post" && slug.current == $slug][0]`
const post = await client.fetch(query, { slug: params.slug }, {
perspective: isEnabled ? 'previewDrafts' : 'published'
})
return <Article post={post} />
}
Pros & Cons
Pros
Highly Flexible Content Modeling
- JavaScript-based schemas provide unlimited flexibility
- Custom validation, conditional fields, recursive structures
- No limitations on content structure
Outstanding Real-Time Collaboration
- Google Docs-like editing experience
- Live presence indicators and conflict resolution
- Activity feeds and revision history
Developer-Friendly
- GROQ query language is intuitive and powerful
- 100% customizable Studio with React
- Excellent TypeScript support
- Great documentation and community
Portable Text Format
- Content works across any platform (web, mobile, AR/VR)
- Structured, queryable rich text
- Custom rendering for any use case
Performance & Scalability
- Global CDN for content and assets
- Automatic image optimization
- 99.99% uptime SLA
- Query caching and real-time updates
Cons
Learning Curve
- Requires JavaScript knowledge for advanced customization
- GROQ is powerful but needs learning (though simpler than GraphQL)
- Schema-based approach different from traditional CMSs
Developer-Focused
- Less suitable for non-technical users without developer support
- Content teams may need training on Portable Text concepts
- Studio customization requires React knowledge
Pricing
- Free tier is generous but has limits
- Costs can increase with scale (API requests, bandwidth)
- Enterprise features require higher-tier plans
Ecosystem
- Smaller than WordPress/Drupal
- Fewer third-party integrations than Contentful
- Community is growing but not as large as established CMSs
Who Should Use Sanity?
Sanity is ideal for:
Development Teams
- Agencies building client sites
- Product teams needing content APIs
- Developers wanting customization control
- Teams using modern JavaScript frameworks
Content-Heavy Projects
- Editorial websites and magazines
- Multi-brand content platforms
- Documentation sites
- Marketing sites with frequent updates
Omnichannel Experiences
- Content for web, mobile, and IoT
- Headless commerce platforms
- AR/VR experiences
- Voice assistants and chatbots
Enterprise Use Cases
- Multi-market websites with localization
- Large content teams needing collaboration
- Projects requiring custom workflows
- Systems needing audit trails and versioning
Not Recommended For:
- Non-technical users without developer support
- Simple brochure sites (overkill)
- Projects requiring traditional WYSIWYG editing
- Teams without JavaScript knowledge
Common Use Cases
E-Commerce (Headless Commerce)
- Product catalogs with custom fields
- Content-driven product pages
- Marketing content alongside products
- Multi-currency and multi-market support
Media & Publishing
- Blog posts and articles
- Magazine-style layouts
- Author management
- Editorial workflows
Marketing Sites
- Landing pages
- Campaign content
- A/B testing content
- Multi-brand sites
Documentation
- Technical documentation
- API references
- Knowledge bases
- Help centers
Getting Started with Analytics
Since Sanity is headless, analytics setup happens in your frontend:
- Set up Google Analytics - Track page views and content engagement
- Configure Google Tag Manager - Centralize all tracking tags
- Track Sanity Content - Monitor which content performs best
- Fix Tracking Issues - Debug common Sanity-specific problems
Additional Resources
Official Documentation:
- Sanity.io Documentation
- GROQ Query Cheat Sheet
- Portable Text Specification
- Sanity Studio Customization
Community:
- Sanity Community Slack
- Sanity Exchange - Plugins and starters
- GitHub Discussions
Framework Guides:
Conclusion
Sanity offers a powerful, flexible, and modern headless CMS that excels at real-time collaboration, developer experience, and content flexibility. Its GROQ query language, Portable Text format, and fully customizable Studio make it stand out from competitors.
For teams that value developer control, real-time features, and omnichannel content delivery, Sanity is an excellent choice. However, it requires technical expertise and may have a steeper learning curve than more traditional CMSs.
Ready to add analytics to your Sanity site? Start with our Google Analytics setup guide or explore our troubleshooting guides for common issues