Sitemap Audit
Audit a website's XML sitemaps and produce an actionable SEO report.
When to use this skill
Use this skill when the user asks to:
- Audit, validate, or check an XML sitemap or sitemap index
- Find sitemap URLs that 404, redirect, are noindexed, or are blocked by robots.txt
- Find URLs in the sitemap that canonicalize elsewhere or sit on the wrong host/protocol
- Check that sitemaps are declared in robots.txt and stay under the 50,000-URL / 50MB limits
- Clean up lastmod, priority, and changefreq metadata
- Improve the quality and trustworthiness of the URL set submitted to search engines
Inputs to collect
Before starting, confirm with the user:
- Site URL or sitemap URL — a live site root (e.g.,
https://example.com, which auto-discovers sitemaps via robots.txt and common paths) or a specific sitemap URL (--sitemap).
- Scope — how many listed URLs to probe (default 2000). Large sitemaps can be sampled with
--max-urls.
- Probing — whether to fetch each listed URL to check status/canonical/noindex (default on). Use
--no-probe for a fast structural-only pass (parse errors, size limits, lastmod hygiene).
Note on the indexable contract: every URL in an XML sitemap should be a final, canonical, indexable 200 page. A URL that redirects, 404s, is noindexed, is blocked by robots.txt, or canonicalizes elsewhere does not belong in the sitemap. Most checks here enforce that contract.
Workflow
Step 1: Discover, parse, and probe the sitemaps
Use scripts/collect_sitemap.py:
python3 scripts/collect_sitemap.py https://example.com --max-urls 2000 --output sitemap_inventory.json
Point directly at a sitemap with --sitemap:
python3 scripts/collect_sitemap.py https://example.com/sitemap_index.xml --sitemap --output sitemap_inventory.json
The script reads robots.txt for Sitemap: directives (falling back to /sitemap.xml and /sitemap_index.xml), follows sitemap index files, handles gzipped sitemaps, and records each sitemap's type, URL count, byte size, and any parse/fetch error. For every listed URL it captures the sitemap's lastmod/changefreq/priority, then probes the URL for status, redirect target, rel=canonical, meta robots, the X-Robots-Tag header, and whether robots.txt disallows it.
Step 2: Run the audit checks
Use scripts/audit_sitemap.py:
python3 scripts/audit_sitemap.py sitemap_inventory.json --output audit_report.json
Step 3: Evaluate the audit checks
Evaluate each check defined in references/audit-checks.md. The core checks are:
| Check |
Severity |
| No parseable sitemap found |
High |
| Sitemap parse error / fetch error |
High |
| Sitemap exceeds 50,000 URLs |
High |
| Sitemap exceeds 50MB uncompressed |
High |
| Listed URL returns 4xx/5xx/error |
High |
| Listed URL redirects (not a final 200) |
High |
| Listed URL is noindex (meta robots or X-Robots-Tag) |
High |
| Listed URL is blocked by robots.txt |
High |
| Listed URL canonicalizes to a different URL |
Medium |
| Listed URL is on the wrong host or protocol |
Medium |
| Sitemaps not declared in robots.txt |
Medium |
| Duplicate URL across sitemaps |
Low |
| Missing / invalid / future lastmod |
Low |
| Invalid priority or changefreq |
Low |
Step 4: Produce the report
Write a report following the structure in references/report-template.md:
- Summary — sitemaps found, total URLs listed, URLs probed, issue counts by severity
- Sitemap files — table of each sitemap: type, URL count, size, gzip, errors
- Issues — one section per failing check, listing the URL, the problem, and the fix
- Prioritized action list — ordered by severity and impact
Step 5: Recommend fixes
For each issue, give a concrete fix:
- Non-200, redirecting, noindex, robots-blocked, or canonicalized URLs: remove them from the sitemap (or, for redirects, replace each with its final destination URL). The sitemap should list only final indexable pages.
- Wrong host/protocol: rewrite URLs to the canonical host and
https://.
- Size limits: split the sitemap into multiple files under 50,000 URLs / 50MB and reference them from a sitemap index.
- Not in robots.txt: add a
Sitemap: line to robots.txt for each sitemap (or the index).
- lastmod hygiene: emit a valid W3C datetime reflecting the real last-modified date; drop
priority/changefreq if they are arbitrary (Google ignores them).
- Base every recommendation on the observed data; do not invent URLs.
Optional: export the report
As a Word document (.docx)
If the user wants the report as a .docx (for example, to share with stakeholders or attach to a ticket), save the Markdown report to a file and convert it:
python3 scripts/md_to_docx.py report.md --output report.docx
scripts/md_to_docx.py uses only the Python standard library (no pip install) and renders headings, tables, lists, links, bold/italic, and code blocks. Offer this whenever a user asks for a Word doc, a .docx, or a shareable/downloadable report.
As a CSV of findings (.csv)
If the user wants the raw findings as a spreadsheet (for filtering, sorting, or triage in Sheets or Excel), convert the audit's audit_report.json directly:
python3 scripts/findings_to_csv.py audit_report.json --output findings.csv
scripts/findings_to_csv.py is also standard-library only. It writes one row per finding, with check and severity columns prepended and list fields (e.g. the pages sharing a duplicate value) joined with ; . Unlike the .docx, which reformats the written report, the CSV is a direct dump of the structured findings — offer it whenever a user wants the data itself, a spreadsheet, or to slice findings by check or severity.
Resources
scripts/md_to_docx.py — convert the Markdown report into a Word (.docx) document (standard library only)
scripts/findings_to_csv.py — flatten the audit findings JSON into a CSV, one row per finding (standard library only)
references/audit-checks.md — full definitions, thresholds, and rationale for every audit check
references/report-template.md — report output structure
scripts/collect_sitemap.py — discover, parse, and probe a site's XML sitemaps
scripts/audit_sitemap.py — run audit checks against a sitemap inventory JSON file
1---2name: sitemap-audit3description: Audit a website's XML sitemaps for SEO. Discovers sitemaps from robots.txt, follows sitemap index files, and validates every listed URL to find broken (non-200) URLs, redirecting URLs, noindexed or robots-blocked URLs, URLs canonicalized to a different page, wrong-host or wrong-protocol URLs, duplicate URLs, oversized sitemaps (over 50,000 URLs or 50MB), parse errors, and missing or invalid lastmod/priority/changefreq values. Use when the user asks to audit, analyze, check, validate, or fix an XML sitemap, sitemap index, sitemap.xml, or sitemap coverage of a website.4---56# Sitemap Audit78Audit a website's XML sitemaps and produce an actionable SEO report.910## When to use this skill1112Use this skill when the user asks to:1314- Audit, validate, or check an XML sitemap or sitemap index15- Find sitemap URLs that 404, redirect, are noindexed, or are blocked by robots.txt16- Find URLs in the sitemap that canonicalize elsewhere or sit on the wrong host/protocol17- Check that sitemaps are declared in robots.txt and stay under the 50,000-URL / 50MB limits18- Clean up lastmod, priority, and changefreq metadata19- Improve the quality and trustworthiness of the URL set submitted to search engines2021## Inputs to collect2223Before starting, confirm with the user:24251. **Site URL or sitemap URL** — a live site root (e.g., `https://example.com`, which auto-discovers sitemaps via robots.txt and common paths) or a specific sitemap URL (`--sitemap`).262. **Scope** — how many listed URLs to probe (default 2000). Large sitemaps can be sampled with `--max-urls`.273. **Probing** — whether to fetch each listed URL to check status/canonical/noindex (default on). Use `--no-probe` for a fast structural-only pass (parse errors, size limits, lastmod hygiene).2829> **Note on the indexable contract:** every URL in an XML sitemap should be a final, canonical, indexable `200` page. A URL that redirects, 404s, is noindexed, is blocked by robots.txt, or canonicalizes elsewhere does not belong in the sitemap. Most checks here enforce that contract.3031## Workflow3233### Step 1: Discover, parse, and probe the sitemaps3435Use `scripts/collect_sitemap.py`:3637```bash38python3 scripts/collect_sitemap.py https://example.com --max-urls 2000 --output sitemap_inventory.json39```4041Point directly at a sitemap with `--sitemap`:4243```bash44python3 scripts/collect_sitemap.py https://example.com/sitemap_index.xml --sitemap --output sitemap_inventory.json45```4647The script reads `robots.txt` for `Sitemap:` directives (falling back to `/sitemap.xml` and `/sitemap_index.xml`), follows sitemap index files, handles gzipped sitemaps, and records each sitemap's type, URL count, byte size, and any parse/fetch error. For every listed URL it captures the sitemap's `lastmod`/`changefreq`/`priority`, then probes the URL for status, redirect target, `rel=canonical`, meta robots, the `X-Robots-Tag` header, and whether robots.txt disallows it.4849### Step 2: Run the audit checks5051Use `scripts/audit_sitemap.py`:5253```bash54python3 scripts/audit_sitemap.py sitemap_inventory.json --output audit_report.json55```5657### Step 3: Evaluate the audit checks5859Evaluate each check defined in `references/audit-checks.md`. The core checks are:6061| Check | Severity |62|---|---|63| No parseable sitemap found | High |64| Sitemap parse error / fetch error | High |65| Sitemap exceeds 50,000 URLs | High |66| Sitemap exceeds 50MB uncompressed | High |67| Listed URL returns 4xx/5xx/error | High |68| Listed URL redirects (not a final 200) | High |69| Listed URL is noindex (meta robots or X-Robots-Tag) | High |70| Listed URL is blocked by robots.txt | High |71| Listed URL canonicalizes to a different URL | Medium |72| Listed URL is on the wrong host or protocol | Medium |73| Sitemaps not declared in robots.txt | Medium |74| Duplicate URL across sitemaps | Low |75| Missing / invalid / future lastmod | Low |76| Invalid priority or changefreq | Low |7778### Step 4: Produce the report7980Write a report following the structure in `references/report-template.md`:81821. **Summary** — sitemaps found, total URLs listed, URLs probed, issue counts by severity832. **Sitemap files** — table of each sitemap: type, URL count, size, gzip, errors843. **Issues** — one section per failing check, listing the URL, the problem, and the fix854. **Prioritized action list** — ordered by severity and impact8687### Step 5: Recommend fixes8889For each issue, give a concrete fix:9091- **Non-200, redirecting, noindex, robots-blocked, or canonicalized URLs:** remove them from the sitemap (or, for redirects, replace each with its final destination URL). The sitemap should list only final indexable pages.92- **Wrong host/protocol:** rewrite URLs to the canonical host and `https://`.93- **Size limits:** split the sitemap into multiple files under 50,000 URLs / 50MB and reference them from a sitemap index.94- **Not in robots.txt:** add a `Sitemap:` line to robots.txt for each sitemap (or the index).95- **lastmod hygiene:** emit a valid W3C datetime reflecting the real last-modified date; drop `priority`/`changefreq` if they are arbitrary (Google ignores them).96- Base every recommendation on the observed data; do not invent URLs.9798## Optional: export the report99100### As a Word document (.docx)101102If the user wants the report as a `.docx` (for example, to share with stakeholders or attach to a ticket), save the Markdown report to a file and convert it:103104```bash105python3 scripts/md_to_docx.py report.md --output report.docx106```107108`scripts/md_to_docx.py` uses only the Python standard library (no `pip install`) and renders headings, tables, lists, links, bold/italic, and code blocks. Offer this whenever a user asks for a Word doc, a `.docx`, or a shareable/downloadable report.109110### As a CSV of findings (.csv)111112If the user wants the raw findings as a spreadsheet (for filtering, sorting, or triage in Sheets or Excel), convert the audit's `audit_report.json` directly:113114```bash115python3 scripts/findings_to_csv.py audit_report.json --output findings.csv116```117118`scripts/findings_to_csv.py` is also standard-library only. It writes one row per finding, with `check` and `severity` columns prepended and list fields (e.g. the pages sharing a duplicate value) joined with `; `. Unlike the `.docx`, which reformats the written report, the CSV is a direct dump of the structured findings — offer it whenever a user wants the data itself, a spreadsheet, or to slice findings by check or severity.119120## Resources121122- `scripts/md_to_docx.py` — convert the Markdown report into a Word (.docx) document (standard library only)123- `scripts/findings_to_csv.py` — flatten the audit findings JSON into a CSV, one row per finding (standard library only)124- `references/audit-checks.md` — full definitions, thresholds, and rationale for every audit check125- `references/report-template.md` — report output structure126- `scripts/collect_sitemap.py` — discover, parse, and probe a site's XML sitemaps127- `scripts/audit_sitemap.py` — run audit checks against a sitemap inventory JSON file