Analyze existing XML sitemaps or generate new ones with industry templates. Validates format, URLs, and structure. Use when user says "sitemap", "generate sitemap", "sitemap issues", or "XML sitemap".
84%
Does it follow best practices?
Run evals on this skill
Adds up to 20 points to the overall score
Low
Low-risk findings worth noting
Discover candidates before reporting a sitemap missing, and read every sitemap found in the same run:
"${CLAUDE_PLUGIN_ROOT}/scripts/claude-seo" run sitemap_discovery.py <url> --expand --jsonThe helper reads every bounded Sitemap: declaration in robots.txt, validates
cross-host targets through the shared SSRF-safe fetch layer, and still probes
common paths when a declared sitemap is stale or invalid. Use only entries in
found; preserve declared failures as findings instead of treating a robots.txt
line alone as proof that a sitemap works. Gzip sitemaps (.xml.gz) are inflated
and classified by their content; such an entry carries gzip: true.
With --expand it also follows a sitemap index one level down to its child
sitemaps and counts every entry. expanded.files has one
object per sitemap file and expanded.totals sums them. Read these checks from
the output; do not count or parse sitemap files by hand:
| Check | Fields in expanded |
|---|---|
| Valid XML, file reachable | files[].valid, error, status_code, kind |
| Per-file limit: ≤50,000 URLs AND ≤50MB uncompressed | url_count, bytes, decompressed_bytes; findings holds over_50000_urls, over_50000_sitemaps or over_50mib_uncompressed |
| Index structure | child_count, child files carry parent; nested_sitemap_index in findings means an index lists another index (not allowed, not followed) |
<lastmod> present and valid W3C Datetime | lastmod_count against url_count, lastmod_invalid_count |
<lastmod> suspiciously uniform | lastmod_identical_share near 1.0 on a file with many URLs, with lastmod_most_common, lastmod_oldest, lastmod_newest |
| URLs on another host than their sitemap | cross_host_url_count, cross_host_url_examples; a child file on another host has cross_host |
| Duplicate or malformed URLs | duplicate_count (repeats inside one file), totals.duplicates_across_files (URL already listed by an earlier file; each entry is counted one way only), invalid_loc_count, totals.unique_urls against totals.total_urls |
| Tokens or session IDs in listed URLs | redacted_url_count, redacted_url_examples (values replaced) |
| Sitemap referenced in robots.txt | source is robots.txt (top-level declared lists every directive) |
| Run cut short | truncated, children.skipped; rerun with a higher --max-children (default 50) |
Sitemap file URLs (url, parent) and cross_host_url_examples are printed
without their query string (query_redacted refers to the file URL). Every
page URL is counted, but only --sample distinct URLs per file (default 20) are
printed in sample_urls. Those keep their query string and can be requested as
printed. URLs in redacted_url_examples had a value replaced: report them, do
not status-check them.
The script cannot judge these; check them yourself:
sample_urls from each file (never
redacted_url_examples or cross_host_url_examples, which are not exact URLs)<lastmod> accuracy: it must reflect the last significant content change
(main content, structured data, links, not copyright/boilerplate edits).
Google only honours <lastmod> when consistently and verifiably accurate, so
warn when values are newer than the page's real content.<priority> and <changefreq> are ignored by Googletotals.total_urls, kind)| Issue | Severity | Fix |
|---|---|---|
| >50k URLs in single file | Critical | Split with sitemap index |
| >50MB uncompressed single file | Critical | Split with sitemap index |
| Non-200 URLs | High | Remove or fix broken URLs |
| Noindexed URLs included | High | Remove from sitemap |
| Redirected URLs included | Medium | Update to final URLs |
| All identical lastmod | Low | Use actual modification dates |
| Priority/changefreq used | Info | Can remove (ignored by Google) |
Google documents three subtypes with their own rules, validate per-subtype:
http://www.google.com/schemas/sitemap-image/1.1): only two valid
tags remain, <image:image> and <image:loc> (max 1,000 <image:image>
per <url>). <image:caption>/<image:geo_location>/<image:title>/
<image:license> were deprecated (2022), flag as info-level removable.<video:video> with <video:thumbnail_loc>,
<video:title>, <video:description>, plus <video:content_loc> or
<video:player_loc>; mRSS also supported. Flag deprecated/removed tags
(<video:category>, <video:gallery_loc>, <video:price>, <video:tvshow>,
player autoplay/allow_embed) as info-level removable; recheck Google docs before citing a removal date.<news:news> tags per file. Keep the 50,000 URL and
50 MB checks; do not replace them when the news: namespace is present
(https://developers.google.com/search/docs/crawling-indexing/sitemaps/news-sitemap).
Include <news:news> only on articles from the last 2 days; required
<news:publication>/<news:name>/<news:language>/<news:publication_date>/
<news:title>; submit/discover through Search Console or robots.txt/sitemap
index; use Publisher Center only for publication management where relevant.../seo-plan/assets/ directory✅ Integration pages (with real setup docs) ✅ Template/tool pages (with downloadable content) ✅ Glossary pages (200+ word definitions) ✅ Product pages (unique specs, reviews) ✅ User profile pages (user-generated content)
❌ Location pages with only city name swapped ❌ "Best [tool] for [industry]" without industry-specific value ❌ "[Competitor] alternative" without real comparison data ❌ AI-generated pages without human review and unique value
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://example.com/page</loc>
<lastmod>2026-02-07</lastmod>
</url>
</urlset><?xml version="1.0" encoding="UTF-8"?>
<sitemapindex xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<sitemap>
<loc>https://example.com/sitemap-pages.xml</loc>
<lastmod>2026-02-07</lastmod>
</sitemap>
<sitemap>
<loc>https://example.com/sitemap-posts.xml</loc>
<lastmod>2026-02-07</lastmod>
</sitemap>
</sitemapindex>sitemap_discovery.py and report "not found" only
when its found list is empty after declared and common candidates are checkedVALIDATION-REPORT.md: analysis resultssitemap.xml (or split files with index)STRUCTURE.md: site architecture documentationAgriciDaniel/claude-seo
468ed5b
If you maintain this skill, you can claim it as your own. Once claimed, you can manage eval scenarios, bundle related skills, attach documentation or rules, and ensure cross-agent compatibility.