Reading time sanity blog
Last updated: 22.12.2025
Reading time sanity blog
Audio Narration

Reading time estimates are useful for readers to gauge their engagement time with content. For Sanity-powered blogs, calculating reading time is challenging due to Sanity's block content storing rich text as structured data. The recommended solution is to calculate reading time directly in a GROQ query. This involves using the pt::text() function to extract plain text from Portable Text blocks, splitting the text to count words, and dividing by 200 to estimate minutes to read, based on an average reading speed of 200 words per minute. Calculating reading time in GROQ queries enhances performance by reducing client-side processing and improving load times. Adjust the average reading speed based on the complexity of your content for more accurate estimates.
Reading time estimates help readers decide if they have time to engage with your content. Here's how to add this feature to your Sanity-powered blog.
The Challenge
Sanity's block content (Portable Text) stores rich text as structured data, not plain strings. This means you can't simply count words in the traditional way.
Calculate in GROQ Query
The most efficient approach is to calculate reading time directly in your GROQ query:
1```groq
2*[_type == "post" && defined(slug.current)]{
3_id,
4title,
5slug,
6"minutesToRead": length(string::split(pt::text(body), " ")) / 200,
7
8}
9```1```groq
2*[_type == "post" && defined(slug.current)]{
3_id,
4title,
5slug,
6"minutesToRead": length(string::split(pt::text(body), " ")) / 200,
7
8}
9```Finding the length of the block content using the pt::text() function splitting on space to get number of words dividing on 200 (average reading speed) to get minutes
The `pt::text()` function extracts plain text from Portable Text blocks.
Best Practice
For optimal performance, calculate reading time in GROQ queries. This reduces client-side JavaScript and improves load times.
The average reading speed of 200 words per minute is industry standard, but adjust based on your content's complexity.

Using the WAT Framework: Writing Sanity MCP Workflows That Make Claude Consistent and Reliable
The text explains why open-ended AI instructions like “write a blog post about TypeScript” lead to inconsistent results. Because models are probabilistic, they vary structure, miss fields, and overlook edge cases, which is problematic for repetitive, structured tasks such as publishing to a CMS. To solve this, it introduces the WAT framework: Workflows, Agents, Tools. Workflows are plain-language markdown SOPs that encode domain knowledge and specify steps. Agents (Claude) handle reasoning and decisions. Tools are deterministic scripts or APIs, like the Sanity MCP, that execute actions. This separation narrows the decision space and keeps behavior consistent across sessions. A concrete example is the draft_blog_post workflow, which fetches authors and categories from Sanity, requires outline approval, and strictly defines document shape and constraints, including a 5000-byte body limit. Workflows evolve through a self-improvement loop: each failure adds new rules and edge cases. To get started, you document repeatable tasks, inputs, tools, steps, and edge cases, store them in .claude/wat/workflows/, and reuse them for faster, cheaper, and more reliable AI-assisted work.
Read post
Serving Your Blog as Markdown So AI Agents Can Actually Read It
The article explains how to serve clean Markdown versions of blog posts so AI agents can consume content without HTML noise like navigation, scripts, and cookie banners. It recommends two access patterns: appending .md to post URLs, or using an Accept: text/markdown header for content negotiation. In Next.js, rewrites in next.config.ts route both patterns to an internal /md/posts/[slug] handler. That route fetches the post from Sanity, converts it to Markdown, and returns it with a text/markdown Content-Type and short caching headers. A buildPostMarkdown helper constructs the Markdown document with a title, canonical URL, optional hero image, auto-generated summary, and body converted from Portable Text via @portabletext/markdown. Code blocks stored in Sanity as _type: "code" are correctly rendered as fenced Markdown code blocks with language tags, making them ideal for AI agents and syntax highlighters. A /posts.md index provides a machine-readable sitemap listing all posts with metadata and links, enabling agents to discover and traverse content efficiently using either the .md suffix or Accept header approach.
Read post