How to add Last Updated Timestamp in Sitecore sites with Next.js
Improve content debugging by surfacing Sitecore's built-in last-updated timestamp, __Updated field in your headless frontend
Improve content debugging by surfacing Sitecore's built-in last-updated timestamp, __Updated field in your headless frontend
When building a headless Sitecore site with Next.js, you may want to display or expose the date a page was last updated. Sitecore stores this internally in the __Updated system field on every item, but the Layout Service does not include it by default.
Having this timestamp available is useful for troubleshooting — making it easy to confirm whether a content change has been published and is actually being served. It may be useful for SEO and caching too.
This post shows how to fetch that value via the Sitecore GraphQL API and make it available in your Next.js application.
Sitecore's GraphQL API allows you to query any field on an item by its ID (or path) and language. The __Updated field is a standard system field present on every Sitecore item and holds an ISO 8601 timestamp of the last time the item was saved.
query ItemUpdated($path: String!, $language: String!) {
item(path: $path, language: $language) {
field(name: "__Updated") {
value
}
}
}Create a utility function that calls the GraphQL endpoint and returns the __Updated value. The function is designed to never throw — if the query fails for any reason, it logs the error and returns an empty string so it never breaks your page rendering.
//JSS
import { gql, GraphQLClient } from 'graphql-request';
import config from 'temp/config';
export async function fetchItemUpdatedDate(
itemId: string | undefined,
language: string
): Promise<string> {
if (!itemId) return '';
try {
const graphQLClient = new GraphQLClient(config.graphQLEndpoint);
graphQLClient.setHeader('sc_apikey', config.sitecoreApiKey);
const query = gql`
query ItemUpdated($path: String!, $language: String!) {
item(path: $path, language: $language) {
field(name: "__Updated") {
value
}
}
}
`;
const data = await graphQLClient.request<{
item: { field: { value: string } | null } | null;
}>(query, { path: itemId, language });
return data?.item?.field?.value ?? '';
} catch (error) {
console.error('Failed to fetch __Updated for item', itemId, error);
return '';
}
}//Content SDK
import client from './sitecore-client';
const QUERY = `
query ItemUpdated($path: String!, $language: String!) {
item(path: $path, language: $language) {
field(name: "__Updated") {
value
}
}
}
`;
export async function fetchItemUpdatedDate(
itemId: string | undefined,
language: string
): Promise<string> {
if (!itemId) return '';
try {
const data = await client.getData<ItemUpdatedResponse>(QUERY, {
path: itemId,
language,
});
return data?.item?.field?.value ?? '';
} catch (error) {
console.error('Failed to fetch __Updated for item', itemId, error);
return '';
}
}The itemId and language values are available from the layout data that Sitecore's Layout Service already provides:
props.layoutData.sitecore.route?.itemIdprops.layoutData.sitecore.context.languageIn your catch-all page ([[...path]].tsx), call the function after the Layout Service props have been created:
const props = await sitecorePagePropsFactory.create(context);
const itemId = props.layoutData.sitecore.route?.itemId;
const language = props.layoutData.sitecore.context.language ?? 'en';
const __updated = await fetchItemUpdatedDate(itemId, language);
props.layoutData.__updated = __updated;With __updated now available on layoutData, you can use it anywhere in your component tree.
The most common practice is to expose the last-updated timestamp as a Last-Modified meta tag in the page's . This is useful for:
How you render the meta tag is up to you and depends on your project's architecture. You could add it in your Layout component, in a dedicated Head component, or via the metadata/metatags pipeline already in place in your application. For example:
<meta name="Last-Modified" content={layoutData.__updated} />Or as an HTTP header set in getServerSideProps:
if (__updated) {
context.res.setHeader('Last-Modified', new Date(__updated).toUTCString());
}Both approaches are valid — the right choice depends on whether you need the value visible to browsers and crawlers at the HTML level, at the HTTP header level, or both.
Start typing to search...