agentspeed.
← all fixes
Issue remediation

Missing XML sitemap

No /sitemap.xml means agents and search engines must discover every page through link-following alone.

failed checksitemap.present
What this means

An XML sitemap is a machine-readable list of every public URL on your site, served at /sitemap.xml as application/xml. Crawlers (both search engines and AI agents) fetch it as one of their first requests on a new domain. Without it, the crawler has to follow links from your homepage and may miss pages that aren't linked from the navigation (older blog posts, deep product pages, archived content).

Why it matters for AI agents

Agents have a finite per-domain crawl budget. With a sitemap, they fetch a curated list and prioritise; without one, they spend their budget on whatever the homepage links to and stop. Recently published pages, paginated content, and deep product catalogues are the most common casualties. A sitemap also carries lastmod timestamps, which signal to agents which pages are fresh and worth re-fetching.

Business impact

Pages that are not in the sitemap are not in the index. Pages that are not in the index are not cited by agents. For e-commerce: every product not in the sitemap is invisible to AI shopping agents. For content sites: every article not in the sitemap is invisible to answer engines. The fix is mechanical, ships once, and updates automatically thereafter.

How to check manually

Open https://your-domain.com/sitemap.xml directly. Expect HTTP 200 with content-type application/xml and a body that opens with <?xml version="1.0" ...?> and contains <urlset> wrapping <url><loc> entries. If you get a 404, you have no sitemap. If you get HTML, your server is misrouting. Also check robots.txt for a 'Sitemap:' directive, since search engines and agents check there too.

The exact fix

Generate sitemap.xml at build time (preferred) or as a route handler that queries your CMS. Each <url> entry needs a <loc> (absolute URL) and ideally a <lastmod> (ISO 8601 timestamp). Reference the sitemap from robots.txt with a 'Sitemap:' line. Keep individual sitemaps under 50 MB / 50,000 URLs; use a sitemap index for larger sites.

Copy-paste snippet
Reference snippetxmlsitemap.xml
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://acme.com/</loc>
    <lastmod>2026-04-15T10:00:00Z</lastmod>
  </url>
  <url>
    <loc>https://acme.com/products/skillet-10</loc>
    <lastmod>2026-04-12T08:30:00Z</lastmod>
  </url>
  <url>
    <loc>https://acme.com/blog/seasoning-guide</loc>
    <lastmod>2026-04-08T14:15:00Z</lastmod>
  </url>
  <url>
    <loc>https://acme.com/pricing</loc>
    <lastmod>2026-03-30T09:00:00Z</lastmod>
  </url>
</urlset>
Platform-specific implementations

The reference snippet above is platform-agnostic. Below are the concrete steps for the four most common stacks plus a generic fallback for any other host.

Next.js

Next.js has built-in sitemap support via app/sitemap.ts. Export a default function that returns an array of {url, lastModified, changeFrequency, priority} entries; Next serves the result at /sitemap.xml automatically. For dynamic content (CMS, DB), the function can be async, so Next will generate it at build time, or per-request if you mark it dynamic.

Next.jstsapp/sitemap.ts
import type { MetadataRoute } from 'next';
import { getAllProducts } from '@/lib/products';
import { getAllPosts } from '@/lib/posts';

export default async function sitemap(): Promise<MetadataRoute.Sitemap> {
  const base = 'https://acme.com';
  const products = await getAllProducts();
  const posts = await getAllPosts();

  return [
    { url: base, lastModified: new Date() },
    { url: `${base}/pricing`, lastModified: new Date() },
    ...products.map((p) => ({
      url: `${base}/products/${p.slug}`,
      lastModified: p.updatedAt,
    })),
    ...posts.map((p) => ({
      url: `${base}/blog/${p.slug}`,
      lastModified: p.publishedAt,
    })),
  ];
}

WordPress

WordPress 5.5+ ships a built-in XML sitemap at /wp-sitemap.xml. Most installs have it on by default; if you've disabled it (or you want a richer sitemap), Yoast SEO and Rank Math both generate sitemaps with priority/lastmod and ping search engines on update. Confirm /wp-sitemap.xml or /sitemap_index.xml returns 200; alias /sitemap.xml to whichever you use via .htaccess.

WordPressapache.htaccess
# Alias /sitemap.xml to WordPress's core sitemap so agents that hard-code
# the conventional path also find it.
RewriteRule ^sitemap\.xml$ /wp-sitemap.xml [L,R=301]

Shopify

Shopify generates /sitemap.xml automatically. Every store has one and it updates as you add products, collections, blogs, and pages. There is nothing to configure. The common failure mode is having the wrong canonical domain (the sitemap lists shop.myshopify.com instead of your custom domain) or having a third-party app that overrides robots.txt and breaks the Sitemap: line.

Shopifytxtrobots.txt.liquid (Shopify default already has this)
# Shopify's default robots.txt.liquid already contains:
Sitemap: {{ shop.url }}/sitemap.xml

# If you've overridden robots.txt.liquid, make sure this line is preserved.

Webflow

Webflow generates /sitemap.xml automatically when you enable it under Site settings → SEO → Auto-generate sitemap. Switch the toggle on and re-publish. Webflow respects per-page "Exclude from sitemap" settings, so confirm the pages you care about are not flagged. CMS Collection items are included by default; static utility pages (404, search) are correctly excluded.

WebflowtxtSite settings → SEO → Sitemap
1. Site settings → SEO tab
2. Toggle "Auto-generate sitemap" → on
3. Publish
4. Confirm https://your-domain.com/sitemap.xml returns 200

Static HTML / any stack

Most static-site generators emit sitemap.xml automatically: Astro has @astrojs/sitemap, Eleventy has community plugins, Hugo and Jekyll have it built in. If you're hand-rolling, write a small build script that walks your content directory and emits sitemap.xml into the output folder.

Static HTML / any stackjsscripts/build-sitemap.mjs
import { readdir, writeFile } from 'node:fs/promises';
import { join } from 'node:path';

const BASE = 'https://acme.com';
const PAGES_DIR = './src/pages';

const files = await readdir(PAGES_DIR, { recursive: true });
const urls = files
  .filter((f) => f.endsWith('.html'))
  .map((f) => f.replace(/\.html$/, '').replace(/\/index$/, ''))
  .map((slug) => `  <url><loc>${BASE}/${slug}</loc></url>`);

const xml = `<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
${urls.join('\n')}
</urlset>`;

await writeFile(join('./public', 'sitemap.xml'), xml);
Common mistakes
How to re-test

Fetch https://your-domain.com/sitemap.xml and confirm it returns 200 with valid XML. Spot-check three URLs from the body to make sure they load. Submit the sitemap to Google Search Console and Bing Webmaster Tools (one-time). Then run a fresh AgentSpeed scan, and the "sitemap present" check should pass.

FAQ
How big can a sitemap be?

50,000 URLs and 50 MB uncompressed per file. Beyond that, split into multiple sitemaps and add a sitemap index file at /sitemap-index.xml that lists them.

Should I include images and videos?

You can. Google supports image and video extensions in sitemap entries. For most agents, the URL list alone is sufficient. Add image/video markup only if you actively rely on image search.

Sitemap.xml vs llms.txt, do I need both?

Yes. They serve different purposes. sitemap.xml is the exhaustive list (every page, machine-readable). llms.txt is the curated highlights (your best pages, in priority order). Agents read both and weight them differently.

Verify on your site
Run a scan

Free scan, no signup. The score page is permanent and citable, so you can link it from your team's remediation ticket alongside this guide for “Missing XML sitemap”.

Run a free scan →See all fixes →