Nuxt AI Ready can automatically track when page content was last updated by hashing markdown content and comparing it across builds. This helps AI agents assess content freshness when consuming your site's data.
During prerender, the module determines timestamps using this priority:
<meta property="article:modified_time" content="..."><meta name="last-modified" content="..."><meta name="updated" content="..."><meta property="og:updated_time" content="..."><meta name="lastmod" content="...">The updatedAt field is included in the llms.toon page-level export, making it available to AI agents via the bulk API.
If your pages include timestamps in meta tags, they'll be used as the source of truth:
<head>
<meta property="article:modified_time" content="2024-01-15T10:30:00Z">
</head>
This is useful when:
Manual timestamps sync to the manifest, so they persist across builds even if the meta tag is later removed.
Enable automatic timestamp tracking in your Nuxt config:
export default defineNuxtConfig({
aiReady: {
timestamps: {
enabled: true
}
}
})
For timestamps to work correctly across deployments, the content hash manifest must persist between builds. By default, the manifest is stored at node_modules/.cache/nuxt-seo/ai-index/content-hashes.json.
This is critical: Without persistent storage, every build treats all pages as new, assigning fresh timestamps each time.
Use GitHub Actions caching to persist the manifest between builds:
jobs:
build:
runs-on: ubuntu-latest
steps:
# Install...
- name: Cache AI Ready content hashes
uses: actions/cache@v4
with:
path: node_modules/.cache/nuxt-seo
key: nuxt-seo-${{ github.ref_name }}
# Build, etc..
Cloudflare Pages automatically persists the node_modules directory between builds, so no additional configuration is needed.
Vercel automatically caches node_modules/.cache, so no additional configuration is needed.
Use Netlify's cache plugin to persist the cache directory:
[[plugins]]
package = "netlify-plugin-cache"
[plugins.inputs]
paths = [ "node_modules/.cache/nuxt-seo" ]
You can customize where the manifest is stored:
export default defineNuxtConfig({
aiReady: {
timestamps: {
enabled: true,
manifestPath: '.cache/content-hashes.json' // Relative to output dir
}
}
})
If you don't need timestamp tracking, or your deployment environment doesn't support persistent storage:
export default defineNuxtConfig({
aiReady: {
timestamps: {
enabled: false
}
}
})
When disabled, the updatedAt field is omitted from the TOON export.
Timestamps are available in the page-level TOON export (/llms.toon):
import { decode } from '@toon-format/toon'
const response = await fetch('/llms.toon')
const text = await response.text()
const data = decode(text)
data.pages.forEach((page) => {
console.log(`${page.route} last updated: ${page.updatedAt}`)
// Example: / last updated: 2025-01-15T10:30:45.123Z
})
Timestamps follow ISO 8601 format and represent when the content was last modified (not when the build occurred, unless the content changed in that build).
The module uses SHA256 to hash the full reassembled markdown content of each page. Even minor content changes (typo fixes, formatting) will generate a new hash and update the timestamp.
Route-based chunk IDs remain stable (unchanged by content edits), while content hashes track actual changes. This separation allows:
When both timestamps and Nuxt Sitemap are enabled, the module automatically injects lastmod values into your sitemap.xml during prerender.
export default defineNuxtConfig({
modules: ['nuxt-ai-ready', '@nuxtjs/sitemap'],
aiReady: {
timestamps: {
enabled: true
}
}
})
The sitemap integration:
sitemap:resolved event during prerenderlastmod on matching sitemap URLsExample output in sitemap.xml:
<url>
<loc>https://example.com/docs/getting-started</loc>
<lastmod>2025-01-15T10:30:00Z</lastmod>
</url>
This ensures search engines see accurate content freshness dates without manual configuration.
On the first build (or when the manifest doesn't exist), all pages receive the current build timestamp for both updatedAt and firstSeenAt (internal field).
Subsequent builds preserve firstSeenAt but update updatedAt only when content changes.