XML Sitemap Generator

Paste the URLs you want indexed and get a valid sitemap.xml back, with ampersands escaped, duplicates dropped, relative paths rejected, and a sitemap index when the list goes past 50,000. The tool does not crawl your site, because a web page cannot fetch another origin. Export the URL list from your CMS, a database query or a crawler you run locally.

URLs (one per line)
sitemap.xml
Does not crawl your site: a browser page cannot fetch other origins (CORS), so you supply the URLs.

1 XML Sitemap Generator example

A date after a URL, separated by a space, becomes that URL's lastmod. The second /pricing is a duplicate, so the tool drops it. It also escapes the & in the query string, because one raw ampersand makes the whole file invalid XML.

Input

https://example.com/
https://example.com/pricing
https://example.com/blog/tags?name=css&page=2
https://example.com/blog/hello-world 2026-08-14
https://example.com/pricing

sitemap.xml

<?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/pricing</loc>
  </url>
  <url>
    <loc>https://example.com/blog/tags?name=css&amp;page=2</loc>
  </url>
  <url>
    <loc>https://example.com/blog/hello-world</loc>
    <lastmod>2026-08-14</lastmod>
  </url>
</urlset>

2 Google reads loc and lastmod

loc

Required. It must be an absolute URL on the same host as the sitemap, unless you have verified both properties in Search Console. List the canonical version of each URL, not one that redirects.

lastmod

Leave lastmod out unless the dates are real. Google uses it only on sites where it has proven accurate. Stamping every URL with today's date on every build teaches Google to ignore the field for your site.

changefreq

Google ignores it and says so in its documentation. Bing treats it as a weak hint at most. The option is here because the sitemap protocol defines it, and it defaults to Omit.

priority

Google ignores this too. Priority only ever ranked your pages against each other, so setting every URL to 1.0 changes nothing.

3 Past 50,000 URLs the tool writes a sitemap index

One sitemap file may hold at most 50,000 URLs and 50 MB uncompressed. Over either limit, this tool writes sitemap-1.xml, sitemap-2.xml and so on, plus a sitemap-index.xml that lists them, and Download gives you a zip of the set. The index builds each file's address from the origin of your URLs, so upload the files to the site root, or edit the loc lines if they live elsewhere.

sitemap-index.xml

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

Submit only the index. In Search Console, submit sitemap-index.xml instead of the individual files, and add one Sitemap: line for it to robots.txt.

How to use the XML Sitemap Generator tool

  1. Paste your URLs into the left panel, one per line, or click Upload to load a .txt file. Blank lines and lines starting with # are skipped.
  2. To give one URL its own lastmod, put the date after it with a space: https://example.com/post 2026-08-14.
  3. Set lastmod (None, Today or Custom date) for the rest. changefreq and priority default to Omit because Google ignores them.
  4. Read the status bar under the panels. It lists duplicates removed, lines skipped as relative or non-http, and URLs on a different host.
  5. Click Copy or Download. Past 50,000 URLs or 50 MB the output is split, the file picker shows each part, and Download .zip saves the parts plus sitemap-index.xml.

How to generate a sitemap.xml in code

JavaScript (Node.js)

import { writeFileSync } from "node:fs";

const xmlEscape = (s) => s
    .replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;")
    .replace(/"/g, "&quot;").replace(/'/g, "&apos;");

const pages = [
    { loc: "https://example.com/", lastmod: "2026-09-01" },
    { loc: "https://example.com/blog?tag=css&page=2" },
];

const body = pages.map((p) =>
    "  <url>\n    <loc>" + xmlEscape(new URL(p.loc).href) + "</loc>\n" +
    (p.lastmod ? "    <lastmod>" + p.lastmod + "</lastmod>\n" : "") +
    "  </url>\n").join("");

writeFileSync("sitemap.xml",
    '<?xml version="1.0" encoding="UTF-8"?>\n' +
    '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n' +
    body + "</urlset>\n");

new URL(...).href percent-encodes spaces and non-ASCII characters, which the protocol requires, before the XML escaping step.

PHP

<?php
$pages = [
    ['loc' => 'https://example.com/', 'lastmod' => '2026-09-01'],
    ['loc' => 'https://example.com/blog?tag=css&page=2'],
];

$xml = new XMLWriter();
$xml->openURI('sitemap.xml');
$xml->startDocument('1.0', 'UTF-8');
$xml->setIndent(true);
$xml->startElement('urlset');
$xml->writeAttribute('xmlns', 'http://www.sitemaps.org/schemas/sitemap/0.9');
foreach ($pages as $p) {
    $xml->startElement('url');
    $xml->writeElement('loc', $p['loc']);   // XMLWriter escapes & for you
    if (!empty($p['lastmod'])) {
        $xml->writeElement('lastmod', $p['lastmod']);
    }
    $xml->endElement();
}
$xml->endElement();
$xml->endDocument();
$xml->flush();

Python

from xml.sax.saxutils import escape

pages = [
    {"loc": "https://example.com/", "lastmod": "2026-09-01"},
    {"loc": "https://example.com/blog?tag=css&page=2"},
]

def chunks(items, size=50_000):
    for i in range(0, len(items), size):
        yield items[i:i + size]

for n, part in enumerate(chunks(pages), start=1):
    with open(f"sitemap-{n}.xml", "w", encoding="utf-8") as f:
        f.write('<?xml version="1.0" encoding="UTF-8"?>\n')
        f.write('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n')
        for p in part:
            f.write(f"  <url>\n    <loc>{escape(p['loc'])}</loc>\n")
            if p.get("lastmod"):
                f.write(f"    <lastmod>{p['lastmod']}</lastmod>\n")
            f.write("  </url>\n")
        f.write("</urlset>\n")

saxutils.escape handles &, < and >, which is all that element text needs. Pass a dict as the second argument if you also want quotes escaped.

Common errors and how to fix them

EntityRef: expecting ';' (or "Your Sitemap appears to be an HTML page")
A raw & in a URL. Escape it as &amp; inside <loc>, or regenerate the file with this tool. The second message usually means the server returned an error page instead of the XML.
Search Console: URL not allowed
The URL is on a different host or protocol from the sitemap, such as http:// in a sitemap served over https://, or www against the bare domain. List only URLs from the sitemap's own host, or verify both properties.
Sitemap is too large
More than 50,000 URLs or 50 MB uncompressed. Split it into several files and submit a sitemap index that lists them. Gzipping helps with transfer but the 50 MB limit applies to the uncompressed size.
Submitted URLs show as "Page with redirect" or "Alternate page with proper canonical tag"
The sitemap lists URLs that are not canonical. Replace them with the final destination of each redirect and the canonical version of each page.

Good to know

Google treats a sitemap as a hint. It uses the file to discover URLs and decide how often to recheck them. However, listing a URL does not guarantee it gets crawled or indexed, and leaving one out does not stop Google finding it through links. A sitemap helps most on large sites, new sites with few inbound links, and pages deep in the navigation.

The protocol also allows image, video and news extensions in their own namespaces. This tool does not generate them, so add them by hand only if you publish that kind of content. For ordinary pages, loc and an accurate lastmod are all the file needs.

Specifications and references

This tool follows the specifications below. Read them when you need the exact normative wording, for example to settle an edge case between two implementations.

Frequently Asked Questions

Can this tool crawl my website to find the URLs?

No. CORS stops a web page from reading pages on another origin, so no browser-only tool can crawl your site. Export the URL list from your CMS, a database query or a desktop crawler, and paste it in or use Upload.

How many URLs can one sitemap hold?

50,000 URLs or 50 MB uncompressed, whichever comes first. Above that, split the list into several files and list them in a sitemap index. This tool does the split automatically and downloads the set as a zip.

Does Google use changefreq and priority?

No. Google's documentation says it ignores both. It does use lastmod, but only on sites where the dates have proven accurate, so leave lastmod out instead of setting every URL to today.

Why is my sitemap invalid because of an ampersand?

A sitemap is XML, and a bare & starts an entity reference. URLs with query strings must write it as &amp; inside <loc>. The generator escapes &, <, >, quotes and apostrophes for you.

Where do I put sitemap.xml and how do I submit it?

Upload it to the site root, add a Sitemap: line with its absolute URL to robots.txt, and submit it under Sitemaps in Google Search Console and Bing Webmaster Tools. A sitemap only covers URLs on its own host and below its own directory.

What changefreq value should I use in a sitemap?

The protocol allows always, hourly, daily, weekly, monthly, yearly and never. always is for pages that change on every request, such as a live feed, and never for archived pages. Google ignores the field, and Bing treats it as a weak hint, so leave it on Omit unless a tool you use requires it. If you set it, be honest: a daily value on pages that never change teaches crawlers to ignore it.

Can I set a different priority or changefreq for each URL?

Not here. The changefreq and priority selects apply one value to every URL in the list, which is why they default to Omit. priority only ever ranked your pages against each other, so a single value for all of them says nothing. Only lastmod can vary per URL, by writing the date after it on the same line. Edit the XML by hand if you need different values.

Related

Point crawlers at the finished file with a Sitemap: line from the robots.txt generator. If some of the URLs moved, write the rules with the redirect generator and list only the new addresses. To pull a URL apart and check its query string, use the URL parser.

More Generators

Browse all generators

Copied to clipboard!