How to get changed fields from Sanity History API for diffing?

6 replies
Last updated: Nov 29, 2025
Using the History API, is there a way to get the exact fields that have been changed, so I can do a diff on them?I've used the
/v2023-02-01/data/history/:dataset/transactions/:id
endpoint to get all the transactions, but I need to get access to the content to do a diff.
AI Update

The History API's /data/history/:dataset/transactions/:id endpoint does give you access to transaction data with the actual content changes, which allows you to do field-level diffs. The key is understanding which parameters to use and how to interpret the response.

Getting Field-Level Changes

When you call the transactions endpoint, the response is in NDJSON format and includes mutations for each transaction. These mutations show the actual changes made to documents.

Key Parameters

excludeContent (boolean, default: false, required)

  • Keep this as false (the default) to get the actual document content and changes
  • Setting it to true would only give you transaction metadata without the changes themselves

effectFormat (string, default: "mendoza")

  • This controls how changes are expressed
  • Mendoza is Sanity's efficient format specifically designed for expressing differences between JSON documents
  • This is essentially a diff format built into the API!

Practical Approach

// Fetch transactions with full content
const response = await fetch(
  `https://${projectId}.api.sanity.io/v2023-02-01/data/history/${dataset}/transactions/${documentId}?excludeContent=false&effectFormat=mendoza`,
  {
    headers: {
      Authorization: `Bearer ${token}`
    }
  }
)

// Response is NDJSON - each line is a transaction
const ndjson = await response.text()
const transactions = ndjson.trim().split('\n').map(line => JSON.parse(line))

// Each transaction contains mutations showing what changed
transactions.forEach(transaction => {
  console.log('Transaction ID:', transaction.id)
  console.log('Timestamp:', transaction.timestamp)
  console.log('Mutations:', transaction.mutations)
  
  // Mutations contain the actual changes
  transaction.mutations.forEach(mutation => {
    if (mutation.patch) {
      // Patch operations show field-level changes
      console.log('Patched fields:', mutation.patch)
    }
    if (mutation.create || mutation.createOrReplace) {
      // Full document on create
      console.log('Created document:', mutation.create || mutation.createOrReplace)
    }
  })
})

Understanding the Mutations

The mutations array in each transaction contains operations that show exactly what changed:

  • patch operations show field-level modifications with set, unset, inc, etc.
  • create / createOrReplace operations include the full document
  • delete operations show document removal

For patch operations specifically, you'll see the exact fields being modified, which gives you the field-level diff you're looking for.

Additional Filtering

The endpoint also supports:

  • fromTime / toTime - Filter by timestamp range
  • fromTransaction / toTransaction - Filter by transaction ID range
  • reverse - Get transactions in reverse chronological order
  • limit - Limit number of transactions returned

These parameters help you narrow down to specific time periods or transaction ranges when building your diff functionality.

Show original thread
6 replies

Sanity – Build the way you think, not the way your CMS thinks

Sanity is the developer-first content operating system that gives you complete control. Schema-as-code, GROQ queries, and real-time APIs mean no more workarounds or waiting for deployments. Free to start, scale as you grow.

Was this answer helpful?