A crawl audit reports “80 pages share the exact same <title>.” You investigate and they are all MySite Blog, or all MySite — Tag Page, or all Article on MySite. Google cannot tell them apart in search results, click-through rate is poor for the whole cluster, and the audit tool keeps your site flagged red.
Fastest fix: export every URL and its <title> from a crawler, sort by title, and attack the biggest identical group first. For each group, give the page a unique, descriptive title (frontmatter title: for articles, a page-number suffix for pagination, a localized title for bilingual pairs). Then add a build-time check that fails CI if two indexable pages share a title, so the problem cannot come back.
One thing to know before you start: as of June 2026 there is no native “duplicate titles” report inside Google Search Console. The old HTML Improvements report (which used to list duplicate and missing titles) was retired years ago. To find duplicates today you crawl the site yourself, and to confirm Google is unhappy you look at the Performance report for pages with high impressions and a low CTR. So the audit you are reacting to almost certainly came from Screaming Frog, Sitebulb, Ahrefs, or Semrush, not from Google directly.
Why duplicate titles actually hurt
Duplicate titles cause keyword cannibalization (Google cannot decide which of your pages should rank for a query, so all of them rank worse) and they tank CTR because the snippets look interchangeable. They also push Google to rewrite your title for you: a Q1 2025 study found Google rewrote roughly 76% of title tags it saw, up from about 61% in 2023, and in March 2026 Google confirmed it is testing AI-generated headline rewrites in standard results. When your title is generic or duplicated, you are handing Google a reason to replace it with something it invents. A unique, specific title is the best way to keep the title link you actually wrote.
Common causes
Ordered by hit rate, highest first. Find your bucket before you start editing.
1. Template fallback applies when the per-page title is missing
You wrote title: in frontmatter for the article body, but the template falls back to MySite Blog when the field is empty. Several articles where you never filled in a title now share that fallback string.
How to spot it: every page with the fallback also has an empty or missing title: in frontmatter. List them with:
grep -rL "^title:" src/content/articles --include="*.mdx"
2. Paginated lists (“Page 2”, “Page 3”) share the parent’s title
Your /blog/ page is MySite Blog. /blog/page/2/ is also MySite Blog, and so is /blog/page/3/. Pagination changed the URL but not the title.
How to spot it: URL patterns like /page/N/ or ?page=N carrying an identical <title>. The URL differentiates; the title does not.
3. Bilingual pages without locale markers
/en/articles/topic/ and /zh/articles/topic/ both emit <title>Topic</title>. Google can deduplicate them despite the distinct URLs, especially when the hreflang annotations are missing or mismatched.
How to spot it: a translationKey pair with an identical title. The ZH version should contain Chinese characters; if both read Topic, the template never localized the title.
4. Auto-generated tag or archive pages
Fifty tag pages all titled Tagged: ${tagName} — but the template emitted Tagged: with no substitution, so every page literally reads <title>Tagged: </title>.
How to spot it: a run of pages with format-string artifacts in the <title>. Template variable interpolation failed.
5. CMS or bulk-edit collapsed many titles into one
A find-and-replace or a normalize script overwrote title: across many files. They now share a single template-derived title.
How to spot it: look for a recent bulk commit that rewrote titles.
git log --all -p -S "title:" -- src/content/articles/
Look for one edit that set many title: lines to the same value.
6. Syndicated or imported content kept the original site’s title
Articles imported from a partner blog kept their original <title>, which is now the <title> for 50 of your pages — all identical to the partner’s old format.
How to spot it: the shared title is suspiciously branded for a different site, or contains a date format your site does not use.
Diagnosis at a glance
| Symptom you see in the crawl export | Likely bucket | Fix it with |
|---|---|---|
Identical fallback string, frontmatter title: empty | Template fallback (1) | Make title: required; fail build if missing |
/page/2/, ?page=2 share parent title | Pagination (2) | Append — Page 2; self-canonical each page |
Same translationKey, no Chinese chars on ZH page | Bilingual collision (3) | Localize the title; verify hreflang |
<title> contains ${...} or trailing : | Tag/archive template bug (4) | Fix variable interpolation |
| Many titles changed in one recent commit | Bulk-edit overwrite (5) | Restore from git log or rewrite per page |
| Title branded for another site / odd date format | Imported content (6) | Rewrite to your own style |
Shortest path to fix
Ordered by ROI. Step 1 audits; Steps 2 and 6 prevent recurrence.
Step 1: Crawl, export, and group duplicates
# Use Screaming Frog, Sitebulb, Ahrefs Site Audit, or your own crawler.
# Export URL + <title> as CSV, then group by title and sort by count descending.
You will see the top duplicate clusters. Fix the largest first — clearing 80 pages with one shared title beats chasing five small duplications.
Step 2: For each duplicate group, decide the differentiation
| Cluster type | Fix |
|---|---|
| Template fallback | Make title: required; fail build if missing |
| Pagination | Append — Page 2 / — Page 3, and give each paginated page a self-referencing canonical (do NOT canonical them all to page 1) |
| Bilingual collision | Localize each language’s title (e.g. EN Topic, ZH 主题), and confirm reciprocal hreflang |
| Tag page format-string bug | Fix the template variable substitution |
| Bulk-edit overwrite | Restore from git log or rewrite per page |
| Imported syndicated content | Rewrite titles to match your style |
On pagination specifically: Google stopped using rel="prev" / rel="next" for indexing back in 2019 and treats paginated pages as ordinary pages, so the only thing that makes /page/2/ distinct is a distinct title and a self-referencing canonical. Pointing every paginated page’s canonical at page 1 tells Google to ignore pages 2 onward, which is the opposite of what you usually want.
Step 3: Rewrite titles to be search-distinct
A unique title is not enough; it should also be searchable and survive Google’s rewrite. Add specifics, keep it roughly 30 to 60 characters (the band Google most often leaves untouched), and front-load the distinguishing words. Brand names get stripped from titles often, so put the brand at the end if at all.
Bad: "Article" (unique but useless)
Good: "Claude API streaming responses, step by step (2026)"
Differentiate through specificity, not by tacking on numbers or v2.
Step 4: Re-submit the sitemap and request re-indexing
After the titles are fixed:
# Astro and most static-site generators rebuild the sitemap on build.
pnpm build
Then in Google Search Console: Sitemaps -> resubmit the sitemap URL. For specific high-traffic pages, use URL Inspection -> Request Indexing. Google will not show the new titles until it recrawls, so submitting explicitly speeds it up. Expect days to a couple of weeks before the SERP snippets refresh.
Step 5: For unavoidable duplicates, use noindex or canonical
Some duplicates are legitimate — /login, /404, near-identical /about cousins, printer-friendly variants. For pages you never want ranked, add a noindex robots meta tag. For two URLs that genuinely serve the same content (a tracking-parameter variant, say), pick one and add a rel="canonical" pointing the duplicate at the keeper. Reserve the unique-title rule for indexable, organic-traffic-eligible pages.
Step 6: Add a CI assertion so it cannot recur
// scripts/check-unique-titles.mjs
import fs from "node:fs";
import path from "node:path";
import matter from "gray-matter";
const seen = new Map();
const issues = [];
function walk(dir) {
for (const name of fs.readdirSync(dir)) {
const p = path.join(dir, name);
if (fs.statSync(p).isDirectory()) walk(p);
else if (p.endsWith(".mdx") || p.endsWith(".md")) {
const { data } = matter(fs.readFileSync(p, "utf8"));
if (data.draft) continue;
const title = (data.title || "").trim();
if (!title) { issues.push(`MISSING TITLE: ${p}`); continue; }
// Key by lang so the same translationKey in en/ and zh/ doesn't false-positive
// only if their titles are byte-identical (a real bilingual collision).
if (seen.has(title)) issues.push(`DUPLICATE: ${p} == ${seen.get(title)}`);
else seen.set(title, p);
}
}
}
walk("src/content/articles");
if (issues.length) {
console.error(issues.join("\n"));
process.exit(1);
}
Wire it into prebuild. Now both duplicate and missing titles fail CI before they ever ship.
How to confirm it’s fixed
- Re-run your crawler and re-export URL +
<title>. The largest duplicate cluster should drop to a count of 1 per title (or only legitimatenoindexpages remain). - Run
node scripts/check-unique-titles.mjslocally; it should exit 0. - In Search Console, open URL Inspection on a fixed page, click View crawled page, and check the
<title>Google last saw. After a recrawl it should show the new title. If it still shows the old one, request indexing again and wait. - A week or two later, check the Performance report for the affected pages — CTR on the previously-duplicated cluster should start climbing as snippets refresh.
Prevention
- Per-page title is required; the build fails without it (no silent template fallback).
- CI assertion: no two indexable pages share a
<title>. - Pagination, language, and tag templates emit distinct titles by construction.
- Quarterly: crawl and audit for new duplicates from imported or migrated content.
- Bulk-edit scripts must preserve per-page titles; if they rewrite, log the change and review it.
- Differentiate by specificity (descriptive titles), not by appending
v2.
FAQ
Does Google penalize duplicate title tags? There is no specific “duplicate title” penalty, but the effect is real: duplicate titles cause keyword cannibalization and weak CTR, and they make Google more likely to rewrite your title with its own (often AI-generated, as of 2026) text. The damage is lost ranking and lost clicks, not a manual action.
Where does Search Console show duplicate titles in 2026? It does not, directly. The HTML Improvements report that used to list them was retired. Use a crawler (Screaming Frog, Sitebulb, Ahrefs, Semrush) to find duplicates, and use the GSC Performance report — high impressions with low CTR — to spot pages whose snippets are underperforming.
Are duplicate titles on paginated pages a problem?
Yes. Google treats /page/2/ as a normal page now (rel="prev"/rel="next" have been ignored since 2019), so each paginated page needs a distinct title and a self-referencing canonical. Appending — Page N is the simplest fix.
Is it okay for the English and Chinese versions to share a title?
No — give each language its own native-language title and pair them with reciprocal hreflang tags. If both read Topic, Google may collapse them and pick one to show, wasting the other language’s reach.
How long until Google shows the new titles? After you fix the titles and request indexing, expect anywhere from a few days to about two weeks for the SERP snippets to refresh, depending on how often Google crawls the page.
Related
Tags: #Content ops #Site quality #Site audit #Troubleshooting #Duplicate title