# Sitemap lastmod reflects real content dates

- **Pattern:** `ab-002625` (`geo-readiness.ai-crawler-access.sitemap-lastmod-accurate`)
- **Severity:** low
- **Lifecycle:** active
- **Last modified:** 2026-06-10
- **Canonical URL:** https://auditbuffet.com/patterns/ab-002625
- **License:** CC-BY-4.0 — attribute to AuditBuffet Pattern Catalog (https://auditbuffet.com/patterns/ab-002625)

## Why it matters

Both major index operators document sitemap `lastmod` as a live signal for AI answers, and both condition it on honesty. Bing's guidance for AI-powered search says "the lastmod field in your sitemap remains a key signal" and that fresh discovery "helps ensure that AI systems reference the most current version of a page" — while explicitly ignoring `changefreq` and `priority`. Google states it "uses the lastmod value if it's consistently and verifiably … accurate." A sitemap that stamps every URL with the build timestamp claims everything changed on every deploy; that is exactly the inconsistency Google says disqualifies the signal, and it deprives AI systems of the per-page freshness data they use to avoid citing stale content. Vibe-coded sitemaps overwhelmingly default to `new Date()` for every entry.

## Severity rationale

Low because lastmod is a freshness optimization on top of normal crawling — losing it wastes a documented signal but does not remove pages from any index or AI answer surface.

## Remediation

Feed `lastmod` from per-record dates — post frontmatter, CMS/database updated-at fields, or file modification times — instead of a build-time constant, at least for content collections.

```ts
// app/sitemap.ts
export default function sitemap() {
  return posts.map((post) => ({
    url: `https://example.com/blog/${post.slug}`,
    lastModified: new Date(post.updatedAt), // per-record, not new Date()
  }))
}
```

Bing also supports IndexNow for pushing URL changes immediately — optional, but it serves the same freshness goal. Routes that genuinely change every deploy (a homepage with live data) may legitimately use the deploy date.

## Detection

- **ID:** `sitemap-lastmod-accurate`
- **Severity:** `low`
- **What to look for:** This is a code-level check. Locate the sitemap source — `app/sitemap.ts` / `sitemap.xml` route, a static `public/sitemap.xml`, or a generator script. Before evaluating, quote how `lastModified`/`lastmod` is populated for each URL family the sitemap emits. Classify each URL family as: (a) per-record dates (frontmatter dates, database `updated_at`, file mtimes), (b) a module-scope build-time constant (`new Date()` at module level, a `BUILD_DATE` const) applied to the family, or (c) no lastmod at all. Identify which families are **content collections** — blog posts, articles, docs pages, changelogged entries: things with an obvious per-record date available. Count the URL families and report the classification.
- **Pass criteria:** A sitemap exists, emits `lastmod`, and every content-collection family derives it from per-record dates. Build-constant lastmod is acceptable on routes that genuinely change with most deploys (homepage, live dashboards, index pages) — the inaccuracy Google disqualifies is claiming change where none happened, and those routes do change. Report even on pass: `"Sitemap emits lastmod for X URL families; Y content collections use per-record dates; build-date constant on [families] (routes that change per deploy — acceptable)."`
- **Fail criteria:** A sitemap exists but (a) emits no `lastmod` at all, or (b) stamps content collections (blog/articles/docs) with a build-time constant even though per-record dates exist in the source data. Report: `"lastmod for [family] is a build-time constant (new Date() at module scope) — per-record dates exist in [source] but are unused"`.
- **Do NOT fail for:** identical lastmod values in the rendered XML alone — a site whose every page genuinely changed in one deploy produces identical dates legitimately. The failure requires evidence in the code that the date is a constant applied regardless of content changes. Also do NOT fail for `changefreq`/`priority` choices: both Google and Bing document ignoring them.
- **Skip (N/A) when:** No sitemap exists — sitemap presence is covered by the SEO Fundamentals audit. Note in detail: `"No sitemap found — cannot assess lastmod accuracy. See SEO Fundamentals audit."`
- **Detail on fail:** `"app/sitemap.ts stamps all 4 URL families with a module-scope BUILD_DATE — blog posts have frontmatter dates that go unused. Google: lastmod is used only 'if it's consistently and verifiably accurate'; Bing calls lastmod 'a key signal' for AI answers."`
- **Remediation:** Use per-record dates for content collections:

  ```ts
  // app/sitemap.ts — per-record lastmod for content, deploy date only where honest
  const posts = getPosts()
  return [
    { url: base, lastModified: new Date() }, // homepage changes every deploy: fine
    ...posts.map((p) => ({
      url: `${base}/blog/${p.slug}`,
      lastModified: new Date(p.date), // from frontmatter/CMS, not the build
    })),
  ]
  ```

---

## External references

- external bing-sitemaps-ai-search — https://blogs.bing.com/webmaster/July-2025/Keeping-Content-Discoverable-with-Sitemaps-in-AI-Powered-Search
- external google-build-sitemap — https://developers.google.com/search/docs/crawling-indexing/sitemaps/build-sitemap

Taxons: findability

HTML version: https://auditbuffet.com/patterns/ab-002625
