You shipped a site from an Astro / Next.js / Hugo starter template months ago. Site works. Then someone shares your article in Slack and the link unfurls with the title… but the URL preview says example.com. Or your RSS feed reader shows your articles but clicks go to https://your-domain.com/article literally (the placeholder string). The bug: the starter template had placeholder URLs (example.com, localhost, your-domain) baked into config and you never replaced them. These are silent because most user flows ignore RSS/OG, but for aggregators, RSS readers, and social previews, they break completely.
Common causes
Ordered by hit rate, highest first.
1. Starter template default never updated
// site.config.mjs (Astro starter default)
export const SITE = {
url: 'https://example.com', // ← never updated
};
You shipped the template but never replaced example.com.
How to spot it:
grep -rn "example.com\|your-domain\|localhost:[0-9]" src/
Any match in src/ likely affects production.
2. OG generation uses literal placeholder
<meta property="og:url" content={`https://example.com${article.slug}`} />
The template was supposed to be a placeholder you’d fix, but it shipped as-is.
How to spot it: View source of any page, search for og:url. Should be your real domain.
3. SITE_URL env var missing in production
const url = process.env.SITE_URL || 'https://example.com';
If SITE_URL isn’t set in production env, fallback fires.
How to spot it: Platform dashboard → env vars → check if SITE_URL is set in production.
4. RSS template uses old URL field
rss.xml.js:
return rss({
site: 'https://your-domain.com', // ← placeholder
// ...
});
5. Sitemap is correct but RSS / OG aren’t
Different parts of the codebase use different sources of truth. You updated the sitemap path but missed RSS or OG.
How to spot it: curl yourdomain.com/sitemap.xml shows your domain, but curl yourdomain.com/rss.xml shows placeholder.
6. Generated OG image URLs have placeholder
Static OG image at https://your-domain.com/og.png referenced from meta tags. If domain is placeholder, image fails to load on social platforms.
Shortest path to fix
Step 1: Find all placeholder URLs
grep -rn "example\.com\|your-domain\|localhost:[0-9]\|<YOUR_DOMAIN>" src/ public/ astro.config.mjs site.config.mjs
List every match. Each needs to be updated or removed.
Step 2: Replace with canonical URL
Don’t just find/replace blindly; understand each context:
site.config.mjs SITE.url→ canonical site URL- RSS template’s
site→ canonical site URL - OG generation → derives from SITE_URL or constant
- Meta tag templates → use
${SITE.url}/${path}
Single source of truth. Reference it everywhere.
Step 3: Set env var in production
# Vercel
vercel env add SITE_URL production
# Enter: https://yourdomain.com
# Netlify (dashboard)
# Site settings → Environment variables → add SITE_URL
Verify with platform-specific deploy preview that the value is picked up.
Step 4: Rebuild and verify
npm run build
curl http://localhost:4321/rss.xml | head -20
curl http://localhost:4321/ | grep -E "og:|canonical"
Should all use canonical URL.
Step 5: Verify on production
curl https://yourdomain.com/rss.xml | head -20
curl https://yourdomain.com/ | grep -E "og:url|canonical"
Step 6: Force-refresh third-party caches
- Facebook / LinkedIn / Slack: paste URL into respective debuggers (Facebook Sharing Debugger, LinkedIn Post Inspector) → “Scrape again.”
- RSS aggregators (Feedly etc.): they’ll pick up the update on next poll.
Step 7: Add CI check
# Post-build
if grep -E "example\.com|localhost:[0-9]" dist/ -r; then
echo "ERROR: placeholder URL in build output"
exit 1
fi
When this is not on you
Some integrations cache OG / RSS data for days. Even after fixing the source, third-party previews may take a few days to refresh — manually trigger refresh in their debuggers.
Easy to misdiagnose as
People assume “no one reads RSS anymore” — but aggregators (Slack link unfurls, Discord, RSS readers, AI assistants that crawl) still parse them. Wrong RSS = wrong links propagate everywhere.
Prevention
- Make SITE_URL a required env var with no default fallback. Build fails if missing.
- CI test that fetches
sitemap.xml,rss.xml, and a sample page; asserts all URLs match canonical. - When using starter templates, audit for
example.comimmediately after cloning. - Use a single config constant for site URL referenced by all templates.
- Don’t hardcode URLs in template literals; always pull from config.
FAQ
- Do search engines penalize wrong RSS? Not directly, but it breaks discovery flows and external link surfaces.
- Should canonical be absolute? Yes — always use absolute https URLs in canonical, sitemap, RSS, OG, and JSON-LD.