Site content catalog
Crawl a website's sitemap and blog index to build a complete content inventory.
How to use it
- Hit Copy SKILL.md — or use the Claude Code line below to get every file.
- Claude: ⋯ → Download .md, then Customize → Skills → Add → Upload skill.
ChatGPT: make a Project and paste it into Instructions.
Neither? Paste it at the top of a new chat — it works for that chat. - Describe your job in plain words. The AI follows the skill from there.
npx degit gooseworks-ai/goose-skills/skills/seo/capabilities/site-content-catalog#main ~/.claude/skills/site-content-catalogFor one project only, change the path to .claude/skills/site-content-catalog. This skill also uses content-inventory.json, robots.txt — copying SKILL.md alone won't be enough. See the folder on GitHub.
Not working?
- Check which app you pasted it into — the steps above name the right one.
- Some skills need the paid tier of Claude or ChatGPT.
Paste into Claude, ChatGPT or Cursor.
Show the full text204 lines
Site Content Catalog
Crawl a website's sitemap and blog to build a complete content inventory — every page cataloged with URL, title, date, content type, and topic cluster. Groups content by category, identifies publishing patterns, and optionally deep-analyzes top pages.
Quick Start
# Basic content inventory
python3 scripts/catalog_content.py --domain "example.com"
# With deep analysis of top 20 pages
python3 scripts/catalog_content.py --domain "example.com" --deep-analyze 20
# Output to specific file
python3 scripts/catalog_content.py --domain "example.com" --output content-inventory.json
Inputs
| Parameter | Required | Default | Description |
|---|---|---|---|
| domain | Yes | — | Domain to catalog (e.g., "example.com") |
| deep-analyze | No | 0 | Number of top pages to deep-read for content analysis |
| output | No | stdout | Path to save JSON output |
| include-non-blog | No | true | Also catalog landing pages, docs, etc. (not just blog) |
Cost
- Sitemap/RSS crawling: Free (direct HTTP requests)
- Apify sitemap extractor (fallback): ~$0.50 per site
- Deep analysis: Free (WebFetch on individual pages)
Process
Phase 1: Discover All Pages
The script attempts multiple methods to find all pages on a site, in order:
A) Sitemap.xml
- Fetch
https://[domain]/sitemap.xml - If it's a sitemap index, recursively fetch all child sitemaps
- Common alternate locations:
/sitemap_index.xml,/sitemap-index.xml,/wp-sitemap.xml - Check
robots.txtforSitemap:directives
B) RSS/Atom Feeds
- Check
/feed,/rss,/atom.xml,/blog/feed, etc. - Extract posts with titles, dates, and URLs
- RSS typically only surfaces recent content (last 10-50 posts)
C) Blog Index Crawl
- Fetch
/blog,/resources,/insights,/news,/articles - Extract links from the page
- Follow pagination if present (
/blog/page/2,?page=2, etc.)
D) Site: Search (fallback)
- WebSearch:
site:[domain]to estimate total indexed pages - WebSearch:
site:[domain]/blogto find blog content - WebSearch:
site:[domain] intitle:to discover page title patterns
E) Apify Sitemap Extractor (fallback for JS-heavy sites)
- Actor:
onescales/sitemap-url-extractor - Use when sitemap.xml is missing and the site is JS-rendered
Phase 2: Classify Each Page
For each discovered URL, classify by:
Content Type
Classify based on URL patterns and page titles:
| Type | URL Patterns | Examples |
|---|---|---|
blog-post |
/blog/, /posts/, /articles/ |
How-to guides, opinion pieces |
case-study |
/case-study/, /customers/, /success-stories/ |
Customer stories |
comparison |
/vs/, /compare/, /alternative/ |
X vs Y pages |
landing-page |
/solutions/, /use-cases/, /for-/ |
Product marketing pages |
docs |
/docs/, /help/, /documentation/, /api/ |
Technical documentation |
changelog |
/changelog/, /releases/, /whats-new/ |
Product updates |
pricing |
/pricing/ |
Pricing page |
about |
/about/, /team/, /careers/ |
Company pages |
legal |
/privacy/, /terms/, /security/ |
Legal/compliance |
resource |
/resources/, /guides/, /ebooks/, /webinars/ |
Gated/downloadable content |
glossary |
/glossary/, /dictionary/, /terms/ |
SEO glossary pages |
integration |
/integrations/, /apps/, /marketplace/ |
Integration pages |
other |
— | Anything else |
Topic Cluster
Group by extracting topic signals from URL slugs and titles:
- Extract keywords from URL path segments
- Group similar keywords into clusters (e.g., "aws-cost", "cloud-spending", "finops" → "Cloud Cost Management")
- Use simple keyword co-occurrence for clustering
Phase 3: Analyze Publishing Patterns
From the dated content (primarily blog posts):
- Total content pieces by type
- Publishing frequency: Posts per month over last 12 months
- Trend: Increasing, decreasing, or stable output
- Recency: Date of most recent publish
- Author diversity: Unique authors (if extractable from RSS)
Phase 4: Deep Analysis (Optional)
If --deep-analyze N is specified, fetch the top N pages (prioritizing blog posts) and extract:
- Word count (approximate)
- Target keyword (inferred from title + H1 + URL)
- Funnel stage: TOFU (awareness), MOFU (consideration), BOFU (decision)
- Content depth: Shallow (<500 words), Medium (500-1500), Deep (1500+)
- Has images/video: Boolean
- Has CTA: Boolean (detected by common CTA patterns)
- Internal links count
Phase 5: Output
JSON Output (default)
{
"domain": "example.com",
"crawl_date": "2026-02-25",
"total_pages": 347,
"discovery_methods": ["sitemap.xml", "rss"],
"pages": [
{
"url": "https://example.com/blog/reduce-aws-costs",
"title": "How to Reduce Your AWS Bill by 40%",
"date": "2025-11-15",
"type": "blog-post",
"topic_cluster": "Cloud Cost Optimization",
"deep_analysis": {
"word_count": 2100,
"target_keyword": "reduce aws costs",
"funnel_stage": "TOFU",
"content_depth": "deep",
"has_images": true,
"has_cta": true
}
}
],
"summary": {
"by_type": {"blog-post": 89, "landing-page": 23, "case-study": 12, ...},
"by_topic": {"Cloud Cost Optimization": 34, "FinOps": 18, ...},
"publishing_cadence": {
"posts_per_month_avg": 4.2,
"trend": "increasing",
"most_recent": "2026-02-20"
}
}
}
Markdown Summary (also generated)
# Content Inventory: example.com
**Crawled:** 2026-02-25 | **Total pages:** 347
## Content by Type
| Type | Count | % |
|------|-------|---|
| Blog Posts | 89 | 25.6% |
| Landing Pages | 23 | 6.6% |
| ...
## Content by Topic Cluster
| Topic | Posts | Most Recent |
|-------|-------|-------------|
| Cloud Cost Optimization | 34 | 2026-02-20 |
| ...
## Publishing Cadence
- Average: 4.2 posts/month
- Trend: Increasing (3.1 → 5.4 over last 6 months)
- Most recent: 2026-02-20
## Full Catalog
| # | Date | Type | Topic | Title | URL |
|---|------|------|-------|-------|-----|
| 1 | 2026-02-20 | blog-post | Cloud Cost | How to Reduce... | https://... |
Tips
- Sitemap.xml is the best source. Most well-maintained sites have one. If missing, it's itself an SEO signal (negative).
- RSS only shows recent content. If you need the full catalog, sitemap is essential. RSS is supplementary.
- Deep analysis is optional but valuable. Use it when feeding into brand-voice-extractor or when you need funnel stage mapping.
- JS-rendered sites may need the Apify fallback. Signs: sitemap.xml returns HTML, or blog page returns mostly JavaScript.
- Combine with seo-domain-analyzer to overlay traffic data on the content inventory — see which content actually performs.
Dependencies
- Python 3.8+
requestslibrary (pip install requests)APIFY_API_TOKENenv var (only for Apify fallback mode)
| 1 | |
| 2 | name site-content-catalog |
| 3 | description > |
| 4 | Crawl a website's sitemap and blog index to build a complete content inventory. |
| 5 | Lists every page with URL, title, publish date, content type, and topic cluster. |
| 6 | Groups content by category and topic. Optionally deep-reads top N pages for |
| 7 | quality analysis and funnel stage tagging. Use before SEO audits, content gap |
| 8 | analysis, or brand voice extraction. |
| 9 | tags [content, seo] |
| 10 | |
| 11 | |
| 12 | # Site Content Catalog |
| 13 | |
| 14 | Crawl a website's sitemap and blog to build a complete content inventory — every page cataloged with URL, title, date, content type, and topic cluster. Groups content by category, identifies publishing patterns, and optionally deep-analyzes top pages. |
| 15 | |
| 16 | ## Quick Start |
| 17 | |
| 18 | |
| 19 | # Basic content inventory |
| 20 | python3 scripts/catalog_content.py --domain "example.com" |
| 21 | |
| 22 | # With deep analysis of top 20 pages |
| 23 | python3 scripts/catalog_content.py --domain "example.com" --deep-analyze 20 |
| 24 | |
| 25 | # Output to specific file |
| 26 | python3 scripts/catalog_content.py --domain "example.com" --output content-inventory.json |
| 27 | |
| 28 | |
| 29 | ## Inputs |
| 30 | |
| 31 | | Parameter | Required | Default | Description | |
| 32 | |-----------|----------|---------|-------------| |
| 33 | | domain | Yes | — | Domain to catalog (e.g., "example.com") | |
| 34 | | deep-analyze | No | 0 | Number of top pages to deep-read for content analysis | |
| 35 | | output | No | stdout | Path to save JSON output | |
| 36 | | include-non-blog | No | true | Also catalog landing pages, docs, etc. (not just blog) | |
| 37 | |
| 38 | ## Cost |
| 39 | |
| 40 | **Sitemap/RSS crawling:** Free (direct HTTP requests) |
| 41 | **Apify sitemap extractor (fallback):** ~$0.50 per site |
| 42 | **Deep analysis:** Free (WebFetch on individual pages) |
| 43 | |
| 44 | ## Process |
| 45 | |
| 46 | ### Phase 1: Discover All Pages |
| 47 | |
| 48 | The script attempts multiple methods to find all pages on a site, in order: |
| 49 | |
| 50 | #### A) Sitemap.xml |
| 51 | Fetch `https://[domain]/sitemap.xml` |
| 52 | If it's a sitemap index, recursively fetch all child sitemaps |
| 53 | Common alternate locations: `/sitemap_index.xml`, `/sitemap-index.xml`, `/wp-sitemap.xml` |
| 54 | Check `robots.txt` for `Sitemap:` directives |
| 55 | |
| 56 | #### B) RSS/Atom Feeds |
| 57 | Check `/feed`, `/rss`, `/atom.xml`, `/blog/feed`, etc. |
| 58 | Extract posts with titles, dates, and URLs |
| 59 | RSS typically only surfaces recent content (last 10-50 posts) |
| 60 | |
| 61 | #### C) Blog Index Crawl |
| 62 | Fetch `/blog`, `/resources`, `/insights`, `/news`, `/articles` |
| 63 | Extract links from the page |
| 64 | Follow pagination if present (`/blog/page/2`, `?page=2`, etc.) |
| 65 | |
| 66 | #### D) Site: Search (fallback) |
| 67 | WebSearch: `site:[domain]` to estimate total indexed pages |
| 68 | WebSearch: `site:[domain]/blog` to find blog content |
| 69 | WebSearch: `site:[domain] intitle:` to discover page title patterns |
| 70 | |
| 71 | #### E) Apify Sitemap Extractor (fallback for JS-heavy sites) |
| 72 | Actor: `onescales/sitemap-url-extractor` |
| 73 | Use when sitemap.xml is missing and the site is JS-rendered |
| 74 | |
| 75 | ### Phase 2: Classify Each Page |
| 76 | |
| 77 | For each discovered URL, classify by: |
| 78 | |
| 79 | #### Content Type |
| 80 | Classify based on URL patterns and page titles: |
| 81 | |
| 82 | | Type | URL Patterns | Examples | |
| 83 | |------|-------------|----------| |
| 84 | | `blog-post` | `/blog/`, `/posts/`, `/articles/` | How-to guides, opinion pieces | |
| 85 | | `case-study` | `/case-study/`, `/customers/`, `/success-stories/` | Customer stories | |
| 86 | | `comparison` | `/vs/`, `/compare/`, `/alternative/` | X vs Y pages | |
| 87 | | `landing-page` | `/solutions/`, `/use-cases/`, `/for-/` | Product marketing pages | |
| 88 | | `docs` | `/docs/`, `/help/`, `/documentation/`, `/api/` | Technical documentation | |
| 89 | | `changelog` | `/changelog/`, `/releases/`, `/whats-new/` | Product updates | |
| 90 | | `pricing` | `/pricing/` | Pricing page | |
| 91 | | `about` | `/about/`, `/team/`, `/careers/` | Company pages | |
| 92 | | `legal` | `/privacy/`, `/terms/`, `/security/` | Legal/compliance | |
| 93 | | `resource` | `/resources/`, `/guides/`, `/ebooks/`, `/webinars/` | Gated/downloadable content | |
| 94 | | `glossary` | `/glossary/`, `/dictionary/`, `/terms/` | SEO glossary pages | |
| 95 | | `integration` | `/integrations/`, `/apps/`, `/marketplace/` | Integration pages | |
| 96 | | `other` | — | Anything else | |
| 97 | |
| 98 | #### Topic Cluster |
| 99 | Group by extracting topic signals from URL slugs and titles: |
| 100 | Extract keywords from URL path segments |
| 101 | Group similar keywords into clusters (e.g., "aws-cost", "cloud-spending", "finops" → "Cloud Cost Management") |
| 102 | Use simple keyword co-occurrence for clustering |
| 103 | |
| 104 | ### Phase 3: Analyze Publishing Patterns |
| 105 | |
| 106 | From the dated content (primarily blog posts): |
| 107 | **Total content pieces** by type |
| 108 | **Publishing frequency:** Posts per month over last 12 months |
| 109 | **Trend:** Increasing, decreasing, or stable output |
| 110 | **Recency:** Date of most recent publish |
| 111 | **Author diversity:** Unique authors (if extractable from RSS) |
| 112 | |
| 113 | ### Phase 4: Deep Analysis (Optional) |
| 114 | |
| 115 | If `--deep-analyze N` is specified, fetch the top N pages (prioritizing blog posts) and extract: |
| 116 | **Word count** (approximate) |
| 117 | **Target keyword** (inferred from title + H1 + URL) |
| 118 | **Funnel stage:** TOFU (awareness), MOFU (consideration), BOFU (decision) |
| 119 | **Content depth:** Shallow (<500 words), Medium (500-1500), Deep (1500+) |
| 120 | **Has images/video:** Boolean |
| 121 | **Has CTA:** Boolean (detected by common CTA patterns) |
| 122 | **Internal links count** |
| 123 | |
| 124 | ### Phase 5: Output |
| 125 | |
| 126 | #### JSON Output (default) |
| 127 | |
| 128 | { |
| 129 | "domain": "example.com", |
| 130 | "crawl_date": "2026-02-25", |
| 131 | "total_pages": 347, |
| 132 | "discovery_methods": ["sitemap.xml", "rss"], |
| 133 | "pages": [ |
| 134 | { |
| 135 | "url": "https://example.com/blog/reduce-aws-costs", |
| 136 | "title": "How to Reduce Your AWS Bill by 40%", |
| 137 | "date": "2025-11-15", |
| 138 | "type": "blog-post", |
| 139 | "topic_cluster": "Cloud Cost Optimization", |
| 140 | "deep_analysis": { |
| 141 | "word_count": 2100, |
| 142 | "target_keyword": "reduce aws costs", |
| 143 | "funnel_stage": "TOFU", |
| 144 | "content_depth": "deep", |
| 145 | "has_images": true, |
| 146 | "has_cta": true |
| 147 | } |
| 148 | } |
| 149 | ], |
| 150 | "summary": { |
| 151 | "by_type": {"blog-post": 89, "landing-page": 23, "case-study": 12, ...}, |
| 152 | "by_topic": {"Cloud Cost Optimization": 34, "FinOps": 18, ...}, |
| 153 | "publishing_cadence": { |
| 154 | "posts_per_month_avg": 4.2, |
| 155 | "trend": "increasing", |
| 156 | "most_recent": "2026-02-20" |
| 157 | } |
| 158 | } |
| 159 | } |
| 160 | |
| 161 | |
| 162 | #### Markdown Summary (also generated) |
| 163 | |
| 164 | # Content Inventory: example.com |
| 165 | **Crawled:** 2026-02-25 | **Total pages:** 347 |
| 166 | |
| 167 | ## Content by Type |
| 168 | | Type | Count | % | |
| 169 | |------|-------|---| |
| 170 | | Blog Posts | 89 | 25.6% | |
| 171 | | Landing Pages | 23 | 6.6% | |
| 172 | | ... |
| 173 | |
| 174 | ## Content by Topic Cluster |
| 175 | | Topic | Posts | Most Recent | |
| 176 | |-------|-------|-------------| |
| 177 | | Cloud Cost Optimization | 34 | 2026-02-20 | |
| 178 | | ... |
| 179 | |
| 180 | ## Publishing Cadence |
| 181 | - Average: 4.2 posts/month |
| 182 | - Trend: Increasing (3.1 → 5.4 over last 6 months) |
| 183 | - Most recent: 2026-02-20 |
| 184 | |
| 185 | ## Full Catalog |
| 186 | | # | Date | Type | Topic | Title | URL | |
| 187 | |---|------|------|-------|-------|-----| |
| 188 | | 1 | 2026-02-20 | blog-post | Cloud Cost | How to Reduce... | https://... | |
| 189 | |
| 190 | |
| 191 | ## Tips |
| 192 | |
| 193 | **Sitemap.xml is the best source.** Most well-maintained sites have one. If missing, it's itself an SEO signal (negative). |
| 194 | **RSS only shows recent content.** If you need the full catalog, sitemap is essential. RSS is supplementary. |
| 195 | **Deep analysis is optional but valuable.** Use it when feeding into brand-voice-extractor or when you need funnel stage mapping. |
| 196 | **JS-rendered sites** may need the Apify fallback. Signs: sitemap.xml returns HTML, or blog page returns mostly JavaScript. |
| 197 | **Combine with seo-domain-analyzer** to overlay traffic data on the content inventory — see which content actually performs. |
| 198 | |
| 199 | ## Dependencies |
| 200 | |
| 201 | Python 3.8+ |
| 202 | `requests` library (`pip install requests`) |
| 203 | `APIFY_API_TOKEN` env var (only for Apify fallback mode) |
| 204 |