Search Console Submitted sitemaps table showing one sitemap with status Success and 72 discovered pages.
← All Quick Wins
AEO & GEOSEO & Search

How to Create and Submit an XML Sitemap

What goes in a sitemap, how to generate and submit one, and how to read the Search Console status.

Where this came from:

β˜† Save

The quick answer

Generate a file at /sitemap.xml that lists the canonical URLs you want indexed, add a Sitemap line to your robots.txt, and submit it in Google Search Console. Most CMS plugins and frameworks can generate the file for you. A sitemap helps discovery but does not guarantee crawling or indexing.

Bottom lineList only canonical, indexable URLs, point to the file from robots.txt, and submit it in Search Console.
On this page

Generate a file at /sitemap.xml that lists the canonical URLs you want indexed, add a Sitemap: line to your robots.txt, and submit it in Google Search Console. Most frameworks and CMS plugins can generate the file for you, so you rarely write it by hand.

What a sitemap is

An XML sitemap is a file that lists the pages on your site. It helps search engines find your pages, especially new ones and ones that few other pages link to. Good internal links do the same job from the inside, so the two work best together.

A sitemap does not guarantee that a page will be crawled or indexed. Think of it as a list you hand over, not an instruction they must follow. If you want to see how it fits with robots.txt and llms.txt, read what each file does.

What a minimal sitemap looks like

<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://example.com/</loc>
  </url>
  <url>
    <loc>https://example.com/blog/first-post</loc>
    <lastmod>2026-09-20</lastmod>
  </url>
</urlset>

Only <loc> is needed for each URL. Add <lastmod> only if you can keep it accurate, meaning the date the page really changed.

You can leave out <priority> and <changefreq>. Google has said it ignores both, so adding them only makes the file longer.

What to include, and what to leave out

Include only pages you want indexed, and use the final version of each URL. That means the right protocol, the right host, no tracking parameters, and the canonical version of the page if the same content can be reached more than one way.

Leave out:

  • Redirects and pages that return errors.
  • Pages with a noindex tag.
  • Pages blocked in robots.txt. A sitemap that lists a blocked page sends mixed signals, and it is often a sign that robots.txt is blocking something by accident.
  • Duplicate or parameter versions of the same page.

Step by step

  1. Generate it. On WordPress, an SEO plugin or the built-in sitemap creates one, often at /sitemap.xml or /wp-sitemap.xml. On Next.js (App Router), add app/sitemap.js that returns your list of URLs, and the framework serves it at /sitemap.xml (there is an example below). On Shopify and most site builders, one is created automatically at /sitemap.xml. On static sites, use a generator for your tool, or write the file by hand if the site is small.
  2. Include only pages you want indexed, as described above.
  3. Keep it in sync. New pages should appear without you editing the file. If you have to remember to update it, it will go stale.
  4. Point to it from robots.txt. Add this line, with your own domain, using the full address including https://. You can list more than one sitemap, one line each.
Sitemap: https://example.com/sitemap.xml
  1. Submit it in Google Search Console. Open the Sitemaps section, enter the sitemap address and submit. Other search engines, such as Bing, have similar webmaster tools.
  2. Open it in a browser. You should see XML, not a web page.

Example: a sitemap in Next.js

In the App Router, a file called app/sitemap.js is all you need:

// app/sitemap.js
export default function sitemap() {
  return [
    {
      url: 'https://example.com/',
      lastModified: new Date('2026-09-20'),
    },
    {
      url: 'https://example.com/blog/first-post',
      lastModified: new Date('2026-09-20'),
    },
  ];
}

For a site with many pages, build the list from your data instead of typing it. The function can be async, so it can read posts from a database or a CMS:

// app/sitemap.js
import { getAllPosts } from '@/lib/posts'; // your own data source

export default async function sitemap() {
  const posts = await getAllPosts();

  const postUrls = posts.map((post) => ({
    url: `https://example.com/blog/${post.slug}`,
    lastModified: post.updatedAt,
  }));

  return [
    { url: 'https://example.com/', lastModified: new Date() },
    ...postUrls,
  ];
}

Use each post's real update date for lastModified. Using new Date() for every page means every date changes on every build, which makes the dates useless.

You can also point to the sitemap from app/robots.js:

// app/robots.js
export default function robots() {
  return {
    rules: { userAgent: '*', allow: '/' },
    sitemap: 'https://example.com/sitemap.xml',
  };
}

Limits, and when to use a sitemap index

A single sitemap file can hold up to 50,000 URLs and 50 MB uncompressed. Larger sites split the list into several files and list those files in a sitemap index:

<?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <sitemap>
    <loc>https://example.com/sitemap-posts.xml</loc>
    <lastmod>2026-09-20</lastmod>
  </sitemap>
  <sitemap>
    <loc>https://example.com/sitemap-products.xml</loc>
    <lastmod>2026-09-18</lastmod>
  </sitemap>
</sitemapindex>

Submit the index file, not each child file. Splitting by content type (posts, products, pages) also makes problems easier to spot, because Search Console reports on each file.

After you submit

Open the Sitemaps report in Search Console. It shows each sitemap you submitted, when it was last read, and a status. In a live example, the Submitted sitemaps table shows one sitemap with the status Success and 72 discovered pages. Success means the file was fetched and read, not that every page is indexed.

Search Console Submitted sitemaps table with one sitemap showing status Success and 72 discovered pages.

The Sitemaps report in Search Console, from a live site. β€œSuccess” means the file was fetched and read, not that every page is indexed.

The Discovered pages column is the number of URLs Google found in the file. Compare it with the number of pages you expect, and look into any big gap.

  • Success: Google fetched and read the file. This does not mean every URL is indexed. It only means the file is fine.
  • Has errors: the file was read, but some entries have problems. Open the report to see which ones.
  • Couldn't fetch: Google couldn't get the file. Check that the address is correct, that the file loads in a browser without a login, and that robots.txt doesn't block it.

Give it a few days before worrying. Discovery isn't instant, and a new site can take a while. To see whether individual pages are indexed, use the Page indexing report, not the Sitemaps report.

How to check

Visit https://yourdomain.com/sitemap.xml and confirm it is XML with <urlset> or <sitemapindex> at the top. If you prefer the command line, this shows the status code and content type:

curl -I https://yourdomain.com/sitemap.xml

You want a 200 status and an XML content type, usually application/xml or text/xml.

You can also run the SEO checker, which tests for the file at that address. It looks at the standard location, so if your sitemap lives elsewhere, referencing it in robots.txt is still worth doing.

What "file exists but isn't a sitemap" means

The SEO checker gives a different result when something answers at /sitemap.xml but is not a real sitemap. This usually means the site returns a normal HTML page for any address, often a custom "not found" page that responds with a success code (a soft 404). A crawler that finds a web page there has no list of URLs.

Fix it by generating a real sitemap, or by making the missing address return a proper 404.

Common mistakes

  • Listing URLs that redirect or return errors.
  • Listing noindex pages or pages blocked in robots.txt.
  • Leaving staging or http:// URLs in a live sitemap.
  • Setting every lastmod to the build date, so the dates are meaningless.
  • Forgetting to update it after moving or removing pages.
  • Submitting the sitemap but never adding the Sitemap: line to robots.txt.
  • Submitting each child file of a sitemap index instead of the index itself.

Quick reference

  • Create it: use your CMS, a plugin, or app/sitemap.js in Next.js.
  • What goes in: canonical, indexable URLs only.
  • Required tag: <loc>.
  • Optional tag: <lastmod>, only if accurate.
  • Skip: <priority> and <changefreq>.
  • Size limit: 50,000 URLs or 50 MB uncompressed per file.
  • Bigger site: split into files and use a sitemap index.
  • Tell crawlers: put Sitemap: https://example.com/sitemap.xml in robots.txt.
  • Submit: Search Console, Sitemaps section.
  • Check: open it in a browser, or run the SEO checker.

Where to go next

A sitemap is one step in getting a site found. Once it is live and submitted, work through the new-site checklist to see what else needs attention.

FAQ

No. It helps search engines find pages, but crawling and indexing are still their decision. Success in Search Console only means the file was read.

No. Google has said it ignores both, so leaving them out keeps the file shorter. Only loc is required, and lastmod is worth adding only if it is accurate.

Redirects, error pages, noindex pages, pages blocked in robots.txt, and duplicate or parameter versions of the same page.

One file can hold up to 50,000 URLs and 50 MB uncompressed. Larger sites split the list into several files and submit a sitemap index.

Google could not get the file. Check that the address is correct, that it loads in a browser without a login, and that robots.txt does not block it.

See how your own site scores

Run the same AEO, SEO, and GEO checks this explainer is about β€” free, rule-based, no signup.

Run the free scan

Comments

No comments yet β€” be the first.