Screaming Frog or Ahrefs reports “247 pages with duplicate meta description.” Search Console’s legacy HTML Improvements report flags the same. You’re tempted to spend a weekend rewriting all 247 — don’t. Duplicate meta descriptions don’t cause a ranking penalty (Google confirmed this years ago); they cost you CTR by making your SERP listings look interchangeable. The fix is targeted, not site-wide: rewrite the top 50 traffic pages with unique descriptions; for the long tail, either auto-generate from page metadata or drop the meta entirely and let Google synthesize per query.
Common causes
Ordered by hit rate, highest first.
1. Template fallback to site-wide description
const description = article.description || site.description;
When article.description is empty, your site’s tagline is emitted. Every article without an explicit description gets the same tagline.
How to spot it: Count occurrences of your site tagline in HTML descriptions across the site. If > 20 pages share it, this is the cause.
2. CMS field never filled per article
The meta description field exists in your CMS but isn’t required. Authors leave it blank. Template fallback kicks in.
How to spot it: Audit your articles’ description frontmatter. Count how many are empty or set to a template default.
3. Auto-generated category / tag / archive pages
/category/ai-tools/, /category/productivity/, /category/tools/ all use a generic template description like “Browse our latest articles on this topic.”
How to spot it: Look at the meta description of 5 random category pages. Generic and identical = bug.
4. Pagination pages share parent’s description
/blog/page/2/, /blog/page/3/, etc. all use /blog/’s description. Sometimes they shouldn’t even be indexed.
How to spot it: curl -s https://yoursite.com/blog/page/2/ | grep -oP 'description" content="\K[^"]+' — if identical to /blog/’s, that’s it.
5. Auto-extracting first 155 chars of content
A template “smartly” takes the first 155 characters of the article body as description. For articles starting with the same boilerplate (“In this guide we’ll cover…”), all descriptions become near-duplicate.
How to spot it: Compare descriptions of 5 articles. If they all start with the same 3-4 words, the auto-extraction is too aggressive.
6. Translation pages all share the source-language description
EN and ZH versions of the same article share the EN description (translation not applied to meta). Across many articles, you have N pairs of duplicates.
How to spot it: Compare description frontmatter in /en/article.mdx vs /zh/article.mdx. If they’re identical, the translation skipped meta.
Shortest path to fix
Step 1: Export the duplicate map
# Pull descriptions from all URLs in sitemap
curl -s https://yoursite.com/sitemap.xml | grep -oP '<loc>\K[^<]+' | \
while read url; do
desc=$(curl -s "$url" | grep -oP 'description" content="\K[^"]+')
echo -e "$desc\t$url"
done | sort | uniq -c -d -f1 -w200 | sort -rn | head -50
Sorts duplicates by count, descending. The top 10 are your priority.
Step 2: Prioritize by traffic, not by count
Cross-reference duplicate URLs with Search Console → Performance → Pages (sorted by impressions). Focus on the intersection: pages that have duplicate descriptions AND high impressions.
You probably have 50-200 such pages. These get unique descriptions. Long-tail duplicates can wait or get the auto-generator treatment.
Step 3: Write unique descriptions for top-50
Per article, follow this template:
[primary keyword phrase] + [unique number/detail] + [user value]
Examples:
| Bad (template default) | Good |
|---|---|
| ”AI Productivity Guide — Latest tools and tips" | "12 AI tools I paid for in 2026 + the 8 I dropped after one week" |
| "Browse our category page" | "47 hands-on debugging guides for Astro on Vercel” |
Constraint: 140-160 English chars, 60-80 CJK chars.
Step 4: For long-tail, generate from metadata
Template helper:
function generateDescription(article) {
const intro = article.firstParagraph?.slice(0, 100);
const stats = `${article.wordCount} words · ${article.readTime} min read · ${article.tags.join(", ")}`;
return `${intro} — ${stats}`.slice(0, 160);
}
This produces unique descriptions automatically using each article’s own metadata.
Step 5: Or omit the meta entirely for long-tail
For pages where you can’t write a strong unique description, don’t set one at all. Google will synthesize per query — often better than a weak template description.
{article.description && (
<meta name="description" content={article.description} />
)}
No description tag is better than a duplicate weak one.
Step 6: Make description required in CMS for new articles
In your content config (Astro src/content/config.ts):
const article = z.object({
title: z.string(),
description: z.string().min(50).max(160), // required
// ...
});
This blocks new articles from being committed without a description.
Step 7: Add CI duplication check
// scripts/check-description-uniqueness.mjs
import fs from 'node:fs';
import matter from 'gray-matter';
const seen = new Map();
const issues = [];
for (const file of fs.readdirSync('src/content/articles/en')) {
const { data } = matter(fs.readFileSync(`src/content/articles/en/${file}`, 'utf8'));
const desc = data.description?.trim();
if (desc && seen.has(desc)) {
issues.push(`DUPE: ${file} == ${seen.get(desc)}`);
} else if (desc) {
seen.set(desc, file);
}
}
if (issues.length) { console.error(issues.join('\n')); process.exit(1); }
Step 8: Submit sitemap and wait
Re-submit sitemap. Search Console reflects changes over 2-4 weeks.
When this is not on you
Google often generates its own snippet per query anyway. A unique meta description gives you control over the default snippet shown when query matches the page broadly — but for very specific queries, Google’s synthesized snippet often wins.
Easy to misdiagnose as
Auto-generating from first 155 chars of content sounds clever but can be worse than no description: if articles share boilerplate openings, descriptions become near-duplicates again.
Prevention
- Make
descriptiona required field in CMS schema (Zod or similar enforcement). - Template fallback should be empty (let Google decide) not a canned tagline.
- CI duplication check at build time; fail on duplicate descriptions.
- For category / tag / pagination pages: either write a unique intro per page or
noindexthem. - Audit duplicate-description count quarterly via crawl tool; rewrite if > 10% of pages.
FAQ
- How many duplicate metas is too many? Even one duplicate on a high-impression page hurts CTR. Below 10 high-traffic duplicates, you’re fine.
- Should I rewrite all duplicates? No — prioritize by traffic. Long-tail duplicates can wait or be handled algorithmically.
Related
- Meta description replaced by Google
- Article date vs JSON-LD date mismatch
- Google rewrote my title
- Description rewritten
Tags: #SEO #Troubleshooting #Debug #Structured data #Duplicate meta