Title Tags
A title tag is the text in a page's head that names the page, and it is what search results and browser tabs display. Every page needs exactly one, it should describe that page rather than the site, and no two indexable pages should share it.
What we measured
We ran a title audit across all 216 of our own exported pages. Zero pages are missing a title, zero have more than one, and among indexable pages zero titles are duplicated. The two findings are both non-defects: /404 and /_not-found share a title and are both noindex, which is a framework artifact rather than a mistake, and one indexable title runs 65 characters against a 60 character guideline that is not a limit.
Why it matters
- The title is usually the first thing a person reads about your page, before they have seen the page at all. It is doing sales work, not just classification.
- Two pages with the same title are two pages competing to be the same result. Search engines have to pick one, and the choice may not be yours.
- A template that emits one title for a whole section is the common cause, which means the fix is one change rather than fifty.
- It is one of the few things you control completely, right up until Google decides to rewrite it.
The failure
// src/app/services/[slug]/page.tsx
export const metadata = {
title: "Services | Axion Deep Digital",
};
// Every service page now ships the same title:
// /services/technical-seo -> "Services | Axion Deep Digital"
// /services/web-design -> "Services | Axion Deep Digital"
// /services/local-seo -> "Services | Axion Deep Digital"A static metadata export on a dynamic route. Nothing errors, every page renders, and every page in the section is now indistinguishable from its siblings in a search result.
The fix
export async function generateMetadata({ params }) {
const { slug } = await params;
const service = getService(slug);
return {
title: { absolute: `${service.name} | Axion Deep Digital` },
};
}Derived rather than declared, which is why our 216 pages have no duplicate titles among indexable pages without anyone maintaining a list. Using absolute here suppresses the layout's template suffix, which is what pushes a good title past the display limit.
Verify the fix
Changing the code is not the same as fixing the problem. Confirm it.
- Run the script against your rendered output. Templates decide titles, so the source will not tell you what actually shipped.
- Treat a duplicate as a finding only when more than one indexable page shares the title. Noindex pages cannot compete with each other.
- For anything flagged LONG, look at the title before changing it. 60 characters is a display guideline, not a limit, and a clear 65 character title beats a truncated-sounding 58 character one.
- Check that each title describes its own page rather than the site. A title that is unique and still says nothing passes the script and fails the reader.
- Compare against what Google actually displays, using Search Console or a site: query. Google rewrites titles routinely, and a rewrite is a signal your title did not match the query as well as the page did.
import re, glob, collections
titles = collections.defaultdict(list)
for f in sorted(glob.glob("out/**/*.html", recursive=True)):
html = open(f, encoding="utf-8", errors="ignore").read()
if "<html" not in html:
continue
path = "/" + f[len("out/"):].replace(".html", "")
noindex = 'content="noindex' in html
found = re.findall(r"<title>(.*?)</title>", html, re.S)
if not found:
print("NO TITLE", path, "(noindex)" if noindex else "(INDEXABLE)")
continue
if len(found) > 1:
print("MULTIPLE TITLES", path, len(found))
title = found[0].replace("&", "&").strip()
titles[title].append((path, noindex))
if len(title) > 60:
print("LONG", len(title), path, "(noindex)" if noindex else "(INDEXABLE)")
for title, pages in titles.items():
indexable = [p for p, ni in pages if not ni]
if len(indexable) > 1:
print("DUPLICATE across", len(indexable), "indexable pages:", title)
for p in indexable:
print(" ", p)It only reports a duplicate when more than one INDEXABLE page shares the title. That single condition is what turned our two raw findings into zero defects, and it is the difference between an audit you can act on and a list you have to triage by hand.
Exceptions and misconceptions
60 characters is a guideline, not a limit
Search results truncate by pixel width, not character count, so the real limit depends on the characters you used. One of our indexable titles runs 65 characters and we left it alone, because it reads correctly and shortening it would cost more meaning than the truncation risk is worth.
Google rewrites titles, and that is not a failure
Google may replace your title with page text it considers a better match for the query. You cannot prevent it, and chasing it is wasted effort. Write the title for the person, not for the guarantee.
A duplicate on noindex pages is usually a framework artifact
Our /404 and /_not-found pages share a title because the framework emits both. Neither is indexable, so neither can compete with anything. An audit tool counting this as a duplicate title issue is counting a non-problem.
The title is not the H1
The title lives in the head and is what search results show. The H1 lives on the page. They should agree, but they serve different readers and do not have to be identical.
Watch it
Primary sources
- Google Search Central: influencing title links in search results
- WHATWG HTML Standard: the title element
- MDN: the title element
The measurement above comes from our study, State of Small Business Websites 2026.
Related lessons
Check your own site for this
DeepAudit AI renders your page in a real browser and reports the affected code, so you can see exactly where each finding came from. Free, no signup.
Run a free auditLast reviewed 2026-09-17. Checks covered: Title Tag, Multiple Title Tags, Title Duplicates.