Updated 2026-10-21
Duplicate titles and meta descriptions on a docs site
Docs sites grow by copying pages. A new section starts as a copy of an old one, every product area gets an "Overview" and a "Configuration" page, and the framework fills in whatever the front matter leaves out. The result is dozens of pages that tell search engines the same thing in their <title> and <meta name="description">.
Google asks for a distinct description per page and descriptive, concise titles (Google Search Central: snippets, title links). When fifty pages share one description, Google writes its own snippet from the page text, and search results for your docs look alike, so people have a harder time picking the right page.
Where the duplicates come from
Docusaurus
Each doc's description comes from its description front matter. Without it, Docusaurus uses the first line of Markdown content as the description (docs front matter). It skips imports, code blocks and the # title, but not everything else, so these patterns produce repeats:
- Pages that open with the same
## Overviewor## Prerequisitesheading get "Overview" or "Prerequisites" as their description. - Pages that open with the same admonition (
:::notefollowed by "This feature is in beta.") all get that sentence. - Versioned docs repeat every page once per version, with identical titles and descriptions.
Titles come from title front matter, then the Markdown # heading, then the doc id, followed by the site title. Two pages called "Configuration" in different sections become two identical "Configuration | My Project" titles.
Starlight
Every page has a required title; description is optional. The site-wide description in your Starlight config is used for every page that doesn't set its own (Starlight configuration). So the more pages you have without front matter descriptions, the more pages share the site description.
VitePress
The description in .vitepress/config renders on every page, and a page's front matter description overrides it (VitePress site config). A page's title is its front matter title or the text of its first <h1>, plus the titleTemplate suffix. The same failure modes as Starlight: one description everywhere, and repeated headings become repeated titles.
Find them in your build
Check the HTML your framework produced, not the source files: that's what crawlers read, and it includes the fallbacks. Build first, then point these at the output folder (build for Docusaurus, dist for Starlight, .vitepress/dist for VitePress).
Descriptions used on more than one page, with a count:
grep -rhoE --include='*.html' '<meta name="description" content="[^"]*"' build | sort | uniq -cd | sort -rn
Titles used on more than one page:
grep -rhoE --include='*.html' '<title[^>]*>[^<]*' build | sed 's/<title[^>]*>//' | sort | uniq -cd | sort -rn
To see which files share a given description:
grep -rlF --include='*.html' 'content="Overview"' build
Attribute order and quoting vary between frameworks; if a command prints nothing, open one built page and adjust the pattern to match its tag. For the live site, the free site checker reads your sitemap and lists every duplicated title and description with the pages that share it, across up to 50 pages. For a single live page, the free SEO checker shows the title and description exactly as crawlers get them.
Fix them per framework
Docusaurus
Set both fields in the front matter of each doc. description also becomes og:description.
---
title: Configure the CLI
description: Every option in headlark.config.json, with defaults and an example for monorepos.
sidebar_label: Configuration
---
title is for the browser tab and search results; sidebar_label keeps the short name in the sidebar. For old versions you don't want in search results, set noIndex on the version in the docs plugin options:
// docusaurus.config.js, inside the docs plugin or preset options
docs: {
versions: {
'1.x': { noIndex: true },
},
},
Starlight
---
title: Configure the CLI
description: Every option in headlark.config.json, with defaults and an example for monorepos.
---
Keep the site-wide description in astro.config.mjs for the home page, and treat any other page that still shows it as unfinished. Starlight joins the page and site titles with titleDelimiter (default |); the page title is the part that has to be unique.
VitePress
---
title: Configure the CLI
description: Every option in headlark.config.json, with defaults and an example for monorepos.
---
To catch pages that still inherit the site description, a transformPageData hook in .vitepress/config.mts can list them during the build:
export default defineConfig({
description: 'Docs for the example CLI',
transformPageData(pageData) {
if (!pageData.frontmatter.description) {
console.warn(`no description: ${pageData.relativePath}`)
}
},
})
Writing ones that stay unique
- Lead with what the page is about, not the section. "Configure the CLI" beats "Configuration"; "Deploy to Netlify" beats "Netlify".
- Put the distinguishing detail in the description: the option names, the platform, the error message the reader searched for. Aim for one or two sentences, roughly 70 to 155 characters, so it isn't cut off.
- Don't fill descriptions with keywords. Google is explicit that keyword lists don't help.
- Reused partials and generated pages (API references, changelogs per version) need a description built from the data that differs, such as the class name or version number.
- Re-run the duplicate check in CI so a copied page doesn't reintroduce the problem.
Automating it with Headlark
Writing and maintaining a description for every page is the part that slips on a large docs site. Headlark's build step runs after your framework's build, on the HTML in build, dist or .vitepress/dist:
"build": "docusaurus build && headlark build --site-url https://docs.example.com"
- Each page gets a title and description written from that page's own content, so two pages only end up alike if they say the same thing.
- Your canonical, robots directives and JSON-LD types are kept; an empty result never replaces one of your tags.
- Unchanged pages come from cache on every rebuild.
- Docusaurus and VitePress switch pages in the browser after the first load and can apply their own title from their route data, so the browser tab may show your original title after a click. Crawlers and link previewers load each page's HTML and see the rewritten tags.
Review the results on your most visited pages; it takes minutes when the rest is done.
Try it
The free plan covers one site and 25 pages. Add your site, copy its secret key, and your next build ships with SEO.