Castopod Has No XML Sitemap — Feed-Driven Generator + GSC Submission¶
Castopod (verified through 2.0.0-next.4) ships no XML sitemap — /sitemap.xml 404s, no route or config exists (spark routes | grep -i sitemap is empty), and robots.txt declares no Sitemap: line. Google discovers episodes only via internal links + RSS, so indexing coverage stays terrible (observed: 37 of 238 known URLs indexed, 15.5%) and Googlebot spends its crawl budget on /assets/* and the actor page instead of episodes.
Symptom¶
- GSC shows large "Crawled – currently not indexed" and (after partial discovery) "Discovered – currently not indexed" buckets; episode pages barely indexed.
- Verified-Googlebot log analysis (filter IPs
66.249.*— most "Googlebot" UA traffic is spoofed scanners) shows episode pages getting ~1 crawl/day while static assets take >50% of hits.
Fix — generate the sitemap from the public RSS feed¶
The feed is the authoritative episode list and requires no DB access. Cron-regenerate so new episodes auto-add.
/usr/local/bin/<site>-sitemap.sh (as deployed on tttpod for techtalkthursdays.net):
#!/usr/bin/env bash
# Generates /sitemap.xml (Castopod has no native sitemap).
# Source of truth = the public RSS feed. Re-run via cron so new episodes auto-add.
set -euo pipefail
SITE="https://techtalkthursdays.net"
HANDLE="@TechTalkThursdays" # case-sensitive Castopod handle
OUT="/var/www/html/castopod/public/sitemap.xml"
RESOLVE="--resolve techtalkthursdays.net:443:127.0.0.1"
FEED="$SITE/$HANDLE/feed.xml"
TMP_URLS="$(mktemp)"; TMP_XML="$(mktemp)"
trap 'rm -f "$TMP_URLS" "$TMP_XML"' EXIT
# Static high-value pages + every episode page from the feed
# (strip query/fragment; the /episodes/[^/]+$ grep drops /comments, /embed, /oembed variants)
{
echo "$SITE/$HANDLE"
echo "$SITE/$HANDLE/episodes"
echo "$SITE/credits"
curl -fsS $RESOLVE "$FEED" \
| grep -oE "$SITE/$HANDLE/episodes/[^<\" ]+" \
| sed 's/[?#].*//' \
| grep -E "/episodes/[^/]+$" \
| sort -u
} | sort -u > "$TMP_URLS"
{
echo '<?xml version="1.0" encoding="UTF-8"?>'
echo '<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">'
while IFS= read -r u; do
esc=${u//&/&}
printf ' <url><loc>%s</loc></url>\n' "$esc"
done < "$TMP_URLS"
echo '</urlset>'
} > "$TMP_XML"
install -o www-data -g www-data -m 0644 "$TMP_XML" "$OUT"
echo "Wrote $(grep -c '<url>' "$OUT") URLs to $OUT"
Notes:
- Writing a static file into castopod/public/ works because Apache serves existing files before CodeIgniter's router sees the request — no Castopod patching, nothing lost on upgrade (unlike vendor/ or modules/ edits).
- Credits is site-wide, not per-podcast: Castopod serves it at /credits. /@<handle>/credits is a 404 — an earlier version of this script listed it, and Search Console reported the dead page (fixed 2026-10-27).
- --resolve pins the request to localhost so the cron doesn't depend on external DNS/proxy.
- Cron: /etc/cron.d/<site>-sitemap → 30 4 * * * root /usr/local/bin/<site>-sitemap.sh >/var/log/<site>-sitemap.log 2>&1
Declare + submit — the step that actually matters¶
- Append to
castopod/public/robots.txt: - Submit it in GSC → Sitemaps. Do not rely on robots.txt discovery alone: on tttpod, robots.txt-only discovery produced exactly 2 Googlebot sitemap fetches in 5 weeks while episode-crawl share sat at 1.3% and indexed count fell. The generator ran perfectly for a month and accomplished nothing visible because the GSC submission step was skipped.
Verifying it's working¶
# sitemap live + fresh
curl -sI https://<site>/sitemap.xml | head -3
ls -l castopod/public/sitemap.xml # mtime should be last cron run
# is real Googlebot fetching it? (spoofed-UA scanners are ~80% of "Googlebot" traffic)
zgrep -h "GET /sitemap.xml" /var/log/apache2/<vhost>-access.log* | awk '$1 ~ /^66\.249\./'
In GSC, expect "Discovered – currently not indexed" to grow first (sitemap URLs entering the queue), then convert to crawled/indexed over following weeks. Track indexed count and episode-crawl share — not the crawled-not-indexed pile, which is permanent Castopod system-page noise (embeds, oembed, fediverse endpoints, pagination).
Related¶
- Castopod post didn't appear on Mastodon
- Castopod stale federated avatar
- Deployment + analysis: MajorVault
20-Projects/TTT-SEO/(task-generate-sitemap, gsc-analysis-2026-07-03)