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

6 replies
Last updated: Feb 28, 2023
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
Also any way to extract the author's actual name instead of the id?
You would want to do something like this for every item on your list.

curl -H "Authorization: Bearer <token>" "<https://exx11uqh.api.sanity.io/v2021-06-07/data/history/test/documents/b8b866a5-3546-47de-a15d-de149d058b06?revision=mXlLqCPElh7uu0wm84cjks>"
The important thing to pass here is the
_rev
id.
Thanks! That's exactly it. Not sure how I missed that in the docs. Any idea about extracting the author's actual name
I think I would make a fetch request with GROQ
[_type == "<your document type>" && _rev == "<rev id>"] { …, author-> }
That is basically getting the references of the author (just assuming)
Thanks, I found the endpoint I needed.

users/:userId
awesome. way to go
user F
😊

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?