Your page sets <title>Best Wireless Headphones 2026 | Acme Reviews</title> but the visible <h1> reads “We tested 47 pairs of headphones so you don’t have to.” Google sees two competing signals about what the page is about, declines to use either, and rewrites your SERP title to a clipped fragment from the second paragraph. Click-through drops. This is one of the most common preventable causes of Google title rewrites — and unlike many ranking concerns it is fully within your control.
Common causes
Ordered by frequency.
1. CMS title field and H1 source are different fields
The CMS has a “SEO Title” and a separate “Headline” field. Editors fill in “Headline” but the template uses “SEO Title” for <title> and “Headline” for <h1>. They drift apart from day one.
How to spot it: Check three articles. If <title> and <h1> rarely match, the field design is the root cause.
2. Template appends a brand suffix only to <title>
<title> becomes “How to Bake Sourdough | Acme Cooking” while <h1> stays “How to Bake Sourdough.” Minor mismatch but Google treats the appended brand as user-hostile noise on long titles.
How to spot it: <title> ends with ” | Brand” or ” - Brand”; <h1> does not.
3. H1 is creative / clickbait, <title> is SEO-optimized
The editorial team writes a punchy H1 (“Why my sourdough finally stopped collapsing”). The SEO team rewrites the title tag to be keyword-dense (“Sourdough Bread Recipe — Step-by-Step Guide”). Both are intentional and opposed.
How to spot it: H1 reads like a blog headline, <title> reads like a category page. Both can be good copy independently; together they confuse search engines.
4. Multiple H1s on the page
Page has <h1>Category Name</h1> in a hero region and <h1>Article Title</h1> in the main content. Google does not know which is the page’s H1.
How to spot it: document.querySelectorAll('h1').length > 1 in DevTools.
5. H1 is an image with no alt text
<h1><img src="/heading.svg"></h1> — the visible heading is an SVG with no alt. Google has no text for the H1 at all and falls back to <title> alone, which can then be rewritten if it lacks context.
How to spot it: View source, search for <h1> and confirm it contains no text content other than empty <img> tags.
6. Dynamic H1 set by JavaScript after first render
The HTML response has <h1>Loading...</h1> and JS replaces it post-mount. Googlebot crawls and indexes the unrendered HTML; <h1> looks broken.
How to spot it: curl the page and look at <h1>. If it says “Loading…” or is empty, the dynamic title pattern is at fault. See also Dynamic Title Set by JavaScript Not Indexed.
Before you start
- Pull a list of 10-20 pages where Google rewrote the title in the last 30 days (Search Console → Performance, filter by impressions, then check rendered SERP).
- Note whether the rewrites are consistent (same pattern every time) or random.
- Capture the current
<title>and<h1>for each affected URL. - Decide your policy: should H1 and
<title>match exactly, or should<title>extend H1 with brand suffix?
Information to collect
- The CMS field names that drive
<title>and<h1>. - The template code that emits each.
- Whether your site has a global brand-suffix transform on
<title>. - Any pages with multiple
<h1>elements (run a crawl with structural extraction). - Server-rendered HTML for affected URLs (do not rely on DevTools, which shows post-hydration state).
Step-by-step fix
Ordered cheapest first.
Step 1: Audit current state
for url in $(cat affected-urls.txt); do
html=$(curl -s "$url")
title=$(echo "$html" | grep -oE '<title>[^<]+</title>' | head -1)
h1=$(echo "$html" | grep -oE '<h1[^>]*>[^<]+</h1>' | head -1)
echo "$url | $title | $h1"
done
Pipe the output into a spreadsheet. Quickly see where mismatches concentrate.
Step 2: Unify the CMS field
Collapse “SEO Title” and “Headline” into a single source field for content where they should always agree:
// content schema
title: z.string().min(20).max(65), // single source
// template
<title>{article.title}{brandSuffix(article.section)}</title>
<h1>{article.title}</h1>
For content types where they should differ intentionally (e.g., listicles), keep both fields but enforce a similarity check in CI.
Step 3: Add a similarity check in CI
function tokenJaccard(a: string, b: string): number {
const toks = (s: string) => new Set(s.toLowerCase().match(/\w+/g) ?? []);
const A = toks(a), B = toks(b);
const inter = [...A].filter(x => B.has(x)).length;
return inter / (A.size + B.size - inter);
}
for (const article of allArticles) {
const score = tokenJaccard(article.title, article.h1);
if (score < 0.5) {
console.warn(`Low similarity: ${article.slug}: ${score.toFixed(2)}`);
}
}
Fail the build (or warn) when title/H1 share less than half their content words.
Step 4: Strip the brand suffix from <title> for long titles
If <title> exceeds ~60 characters before the brand suffix, drop the suffix:
const FULL = `${article.title} | ${BRAND}`;
const titleTag = FULL.length > 65 ? article.title : FULL;
Or unify by putting the brand in both:
<title>{article.title} | {BRAND}</title>
<h1>{article.title}</h1> // brand omitted from H1, kept in template chrome only
Either policy is fine — just be consistent.
Step 5: Enforce one <h1> per page
In your template:
{article && <h1>{article.title}</h1>}
{!article && pageType === 'category' && <h1>{categoryName}</h1>}
{/* no h1 in hero block — switch to h2 */}
Crawl the site post-fix and assert exactly one <h1> per page.
Step 6: Render H1 text server-side, always
Never set H1 from JavaScript after first render. Either ship the final H1 in HTML, or accept that Google may use a different signal.
Step 7: Re-request indexing on the fixed URLs
Send your top 10-20 URLs through URL Inspection → Request indexing. Track SERP titles weekly; rewrites typically stop within 2-3 crawls of the fix.
Verify
- Title and H1 for sampled URLs match or are clearly the same idea.
- No URL has more than one
<h1>. - Search Console shows fewer Google-rewritten titles week over week.
- Click-through rate stabilizes or recovers on previously-rewritten URLs.
curlof any URL shows the final H1 text directly in the response.
Long-term prevention
- Pick one editorial policy: either H1 and
<title>match, or<title>is H1 plus a controlled suffix. Document it. - Single source field for the headline in CMS; derive
<title>and<h1>from it. - CI assertion for title/H1 similarity and singular H1.
- Avoid dynamic H1 patterns; if you must, ship the final text server-side.
- Audit Google-rewrite incidents monthly to catch regressions before they affect rankings.
Common pitfalls
- Adding a session ID or A/B variant to
<title>only. Editors do not see it; Google does. - Treating “Google rewrote my title” as random and giving up. It is highly deterministic — the trigger is usually fixable.
- Setting
<h1>invisible via CSSdisplay:nonethinking Google ignores hidden text. Google still parses it as the H1 and the cloaking pattern is risky. - Wrapping H1 in a
<div>with role=“heading” instead of an actual<h1>element. Use the real tag. - Keeping a five-word H1 and a sixteen-word
<title>. The mismatch in length itself is a signal Google interprets as untrustworthy.
FAQ
Q: Should <title> and <h1> be identical?
They can differ but should share the bulk of meaningful words. A common pattern: H1 = “Sourdough Bread Recipe,” <title> = “Sourdough Bread Recipe — Step-by-Step Guide | Acme.” The added clarifier is fine; a completely unrelated <title> is not.
Q: Can I have zero H1?
Technically valid HTML, but Google uses H1 as one of several signals for what the page is about. Zero H1 forces fallback to <title> and body text, which makes rewrites more likely.
Q: Does Google always rewrite mismatched titles?
No. Rewrites happen when Google decides your <title> is “not aligned with the page.” Mismatch with H1 is one of several triggers. Fixing it does not guarantee Google keeps your title forever — just makes rewrites less common.
Q: My H1 is a logo image. Is that bad for SEO?
Yes — Google needs text. Use a real <h1> with text content, then style it with CSS to show the logo, or move the logo to a sibling element and keep H1 textual.