How to get first published and last published timestamps in Sanity?

4 replies
Last updated: Jun 15, 2023
Hi. If I want to show when a document was first published and last published on a web page how would I find that info? For last published, I guess _updatedAt is the correct timestamp, but _createdAt might not be the same as first published. I Have tried getting the transactions from the history api, but I'm not sure how to retrieve first published from the ndjson that is returned...
AI Update

You're absolutely right that _createdAt doesn't necessarily reflect when a document was first published—it just shows when the document was created in the system, which could have been while it was still a draft.

For tracking first published and last published dates, the recommended approach is to create custom fields and use a custom publish action to set them. Here's how:

The Solution: Custom Fields + Custom Publish Action

Add two fields to your schema:

{
  name: 'firstPublished',
  type: 'datetime',
  title: 'First Published',
  readOnly: true
},
{
  name: 'lastPublished', 
  type: 'datetime',
  title: 'Last Published',
  readOnly: true
}

Then create a custom publish action that sets firstPublished only on the first publish, and updates lastPublished every time:

import {useDocumentOperation} from 'sanity'

export function createPublishAction(originalPublishAction) {
  return (props) => {
    const {patch, publish} = useDocumentOperation(props.id, props.type)
    const {draft, published} = props
    
    return {
      ...originalPublishAction(props),
      onHandle: () => {
        // Set firstPublished only if document hasn't been published before
        if (!published) {
          patch.execute([{set: {firstPublished: new Date().toISOString()}}])
        }
        
        // Always update lastPublished
        patch.execute([{set: {lastPublished: new Date().toISOString()}}])
        
        // Perform the publish
        publish.execute()
        
        props.onComplete()
      }
    }
  }
}

This is actually documented as an example in Sanity's schema recipes!

Why Not Use the History API?

While you could parse the History API's NDJSON response to find the first transaction where a document was published (looking for transactions that created the document without the drafts. prefix), it's unnecessarily complex and has limitations based on your history retention period (3 days for Free, 90 days for Growth, 365 days for Enterprise).

The custom field approach is more reliable, performant, and gives you instant access to these timestamps in your queries without needing to process transaction history.

For Last Updated

For last published, you can actually use _updatedAt on the published document (not the draft), which will reflect when it was last published. Just make sure you're querying the published version specifically by filtering out drafts or using the published perspective in your queries.

Show original thread
4 replies
I found this: https://www.sanity.io/schemas/make-a-field-read-only-after-publishing-once-d87bf5f6 So I'm thinking the the solution is to create a custom "publish" action that sets a "firstPublished" field the first time
Yes, you’re correct! You’d need to create your own fields for this.
This led me to reading the docs on custom actions, and my case is exactly what is documented :D
I love it when that happens!

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?