Automatically tag blog posts

Official(made by Sanity team)

By Ken Jones Pizza & Knut Melvær

AI-powered automatic tagging for Sanity blog posts that analyzes content to generate 3 relevant tags, maintaining consistency by reusing existing tags from your content library.

schemaTypes/post.ts

defineField({
  name: 'tags',
  title: 'Tags',
  type: 'array',
  of: [{ type: 'string' }],
  description: 'Tags will be automatically generated when you publish a post',
}),

functions/auto-tag/index.ts

import {createClient} from '@sanity/client'
import {documentEventHandler} from '@sanity/functions'

export const handler = documentEventHandler(async ({context, event}) => {
  const client = createClient({
    ...context.clientOptions,
    apiVersion: 'vX',
    useCdn: false,
  })
  const {data} = event
  const {local} = context // local is true when running locally

  try {
    const result = await client.agent.action.generate({
      noWrite: local ? true : false, // if local is true, we don't want to write to the document, just return the result for logging
      instructionParams: {
        content: {
          type: 'field',
          path: 'body',
        },
        tagsUsedInOtherPosts: {
          type: 'groq',
          query: "array::unique(*[_type == 'post' && _id != $id && defined(tags)].tags[])",
          params: {
            id: data._id,
          },
        },
      },
      instruction: `Based on the $content, create 3 relevant tags. Attempt to use $tagsUsedInOtherPosts first if they fit the context. Tags should be simple lowercase words strings and no brackets.`,
      target: {
        path: 'tags',
      },
      documentId: data._id,
      schemaId: '_.schemas.default',
      forcePublishedWrite: true,
    })
    console.log(
      local ? 'Generated tags (LOCAL TEST MODE - Content Lake not updated):' : 'Generated tags:',
      result.tags,
    )
  } catch (error) {
    console.error('Error occurred during tag generation:', error)
  }
})

sanity.blueprint.ts

import {defineBlueprint, defineDocumentFunction} from '@sanity/blueprints'

export default defineBlueprint({
  resources: [
    defineDocumentFunction({
      type: 'sanity.function.document',
      name: 'auto-tag',
      src: './functions/auto-tag',
      memory: 2,
      timeout: 30,
      event: {
        on: ['create', 'update'],
        filter:
             "_type == 'post' && (delta::changedAny(content) || (delta::operation() == 'create' && defined(content)))",
        projection: '{_id}',
      },
    }),
  ],
})

This Sanity Function solves a common content management challenge: the time-consuming task of manually tagging blog posts. Content creators typically spend 2-3 minutes per post adding tags, which can lead to inconsistent tagging across your content library and reduced productivity in editorial workflows.

Quick Start

View the complete example and source code.

Initialize blueprints if you haven't already: npx sanity blueprints init

Then: npx sanity blueprints add function --example auto-tag

Then deploy: npx sanity blueprints deploy

How It Works

When a content editor publishes a new blog post without tags, the function automatically:

  1. Triggers on the publish event for post documents without existing tags
  2. Analyzes the post's content field using AI
  3. Retrieves existing tags from other published posts for vocabulary consistency
  4. Generates 3 relevant tags, prioritizing reuse of existing tags when appropriate
  5. Applies the tags directly to the published document

Key Benefits

  • Saves 2-3 minutes per post by eliminating manual tagging
  • Improves content discoverability through consistent tag application
  • Maintains tag vocabulary by prioritizing reuse of existing tags
  • Scales automatically as your content library grows
  • Reduces editorial overhead for content teams

Technical Implementation

The function uses Sanity's AI capabilities to analyze the portable text content and generate contextually relevant tags. It's built with:

  • Event-driven architecture (triggers on document publish)
  • Smart filtering to only process posts without tags
  • GROQ queries to fetch existing tags for consistency
  • Direct document updates using Sanity's AI agent

Perfect For

  • Content-heavy sites with regular blog publishing
  • Teams looking to improve content organization
  • Projects requiring consistent taxonomy
  • Editorial workflows needing automation

The function is compatible with any of Sanity's official "clean" templates and can be easily customized to adjust tag count, format, or target different document types.

Contributors

Official Recipes by Sanity

First Published Timestamp Function

Featured contribution
Official(made by Sanity team)

Automatically track when content was first published with a timestamp that sets once and never overwrites, providing reliable publication history for analytics and editorial workflows.

Knut Melvær
Go to First Published Timestamp Function