---
title: "\"Multiple H1 Tags\" Warning: What It Breaks for AI Crawlers, and How to Fix the Theme That Adds the Second One"
slug: multiple-h1-tags-fix
published: 2026-11-13T13:31:07.270059+00:00
updated: 2026-11-13T13:31:07.270059+00:00
author: "M Asif Rahman"
author_url: https://ar.bd
category: "AI Readiness"
tags: check:C3, platform:wordpress, h1, headings, structured html, content extraction
description: "Several h1 elements are not a Google penalty, but a first-h1-wins extractor reads your logo as the page title. The causes, the fix, and a counter script."
url: https://aiscan.site/blog/multiple-h1-tags-fix
---

Several `<h1>` elements will not get your page penalised by Google, and Google's own documentation says so. What they do break is extraction: an agent that takes the first `<h1>` as the page title reads your logo or site name instead of the headline, and AIScan's C3 check marks the page down because it counts exactly one. The fix is usually one block setting or one template line, and it takes about ten minutes.

| Question | Answer |
|---|---|
| **Is "multiple H1 tags" a Google ranking problem?** | No. Google Search Central lists "there's no magical, ideal amount of headings" among its SEO myths |
| **Is it invalid HTML?** | No. The HTML Living Standard only asks that at least one heading in the outline be level 1 |
| **So why fix it?** | A first-h1-wins extractor takes the wrong title, and AIScan's C3 counts one `<h1>` as a pass |
| **Which AIScan check** | C3, Structured HTML, in the `content` dimension (weight 4, one point each for a single `<h1>`, a non-empty `<title>`, a meta description and one JSON-LD block) |
| **How common** | 47 of 836 scanned hosts serve two or more `<h1>` on the homepage (12 November 2026) |
| **Usual culprit** | A site title or logo wrapped in `<h1>` on every page by the theme |
| **Time to fix** | 10 minutes, plus a re-scan |

## What the standards actually say, and what tools do anyway

Two claims get mixed up here. The first is that several `<h1>` elements are an error. They are not. The [HTML Living Standard's headings and outlines section](https://html.spec.whatwg.org/multipage/sections.html#headings-and-outlines) asks that if a document has any headings, at least one of them be level 1, and that each heading after the first be no more than one level deeper than the one it follows. Nothing there caps `<h1>` at one. [Google's SEO starter guide](https://developers.google.com/search/docs/fundamentals/seo-starter-guide) is blunter still, filing heading count and heading order under things people worry about for no reason.

The second claim is that it costs you nothing. That one is wrong, for a narrow and practical reason. A pipeline that extracts a page title in one pass takes the first `<h1>` in document order. When the theme puts the site name in the first `<h1>`, every page on the site reports the same title, and the headline you wrote lands in the body text with no more weight than a paragraph. Audit tools flag the pattern because of this, not because of a penalty.

AIScan grades it the same way. [C3, Structured HTML](/docs/checks/content) looks at four signals on the homepage and gives one point each: a single `<h1>`, a non-empty `<title>`, a `<meta name="description">`, and at least one `application/ld+json` block. Two `<h1>` elements lose that first point.

## How often it happens, from our own scans

Across the 836 hosts in our scan corpus (latest site-scope scan per host, 12 November 2026), the C3 evidence splits like this:

| `<h1>` in the served homepage | Hosts | Share |
|---|---|---|
| 0 | 213 | 25.5% |
| 1 | 576 | 68.9% |
| 2 or more | 47 | 5.6% |

So the headline problem on the web is the opposite one: a quarter of homepages serve no `<h1>` at all, usually because the heading is rendered by JavaScript and never reaches the HTML a crawler receives. That case is a separate defect, and the [render-blindness corpus study](/blog/empty-dom-render-blindness-corpus) has the numbers. The 47 hosts with two or more are the group this guide is for.

## Step 1: find out which `<h1>` is the extra one

Count them in the HTML your server returns, not in the browser inspector, because a crawler that does not run your bundle sees the former. This script names each one, so you can tell the logo from the headline:

```python
#!/usr/bin/env python3
"""h1count.py - count the <h1> elements in the HTML a crawler receives."""
import re, sys, urllib.error, urllib.request

UA = "Mozilla/5.0 (compatible; h1count/1.0)"

def h1s(url):
    req = urllib.request.Request(url, headers={"User-Agent": UA, "Accept": "text/html"})
    html = urllib.request.urlopen(req, timeout=20).read().decode("utf-8", "ignore")
    html = re.sub(r"<(script|style|template)[\s\S]*?</\1>", "", html, flags=re.I)
    found = []
    for m in re.finditer(r"<h1\b[^>]*>([\s\S]*?)</h1>", html, re.I):
        text = re.sub(r"\s+", " ", re.sub(r"<[^>]+>", "", m.group(1))).strip()
        found.append(text[:70] or "(empty)")
    return found

for url in sys.argv[1:]:
    try:
        found = h1s(url)
    except urllib.error.HTTPError as e:
        print(f"{url}\n  HTTP {e.code}, not checked")
        continue
    print(f"{url}\n  h1 count: {len(found)}  -> {'PASS' if len(found) == 1 else 'FAIL'}")
    for i, text in enumerate(found, 1):
        print(f"    {i}. {text}")
```

Run it on 13 November 2026 against our own sites and wordpress.org:

```
$ python3 h1count.py https://aiscan.site/ https://wordpress.org/
https://aiscan.site/
  h1 count: 1  -> PASS
    1. Is your site AI agent ready?
https://wordpress.org/
  h1 count: 1  -> PASS
    1. Meet WordPress
```

A one-liner does the counting without the labels: `curl -s https://yoursite.com/ | grep -o '<h1' | wc -l`.

## Step 2: fix it at the cause

**Cause A, the Site Title block on a WordPress block theme.** WordPress core ships `core/site-title` with a `level` attribute whose default is `1`, so a Site Title block inserted by hand renders as `<h1>`. The default themes do not have the bug: both Twenty Twenty-Four and Twenty Twenty-Five set `{"level":0}` in their header pattern, which renders a `<p>`. If your header was built by hand or by a third-party theme, open **Appearance > Editor**, open the **Header** template part, select the **Site Title** block, and set its heading level to Paragraph or H2 with the level control in the block toolbar. Save the template part, not the page. The [core blocks reference](https://developer.wordpress.org/block-editor/reference-guides/core-blocks/) lists the attribute if you prefer to edit the block markup directly.

**Cause B, a classic theme that wraps the site name in `<h1>` on the front page.** Twenty Twenty-One is the readable example: its `template-parts/header/site-branding.php` emits the site title inside `<h1>` when `is_front_page()` is true, and a plain `<p>` everywhere else. That is why so many sites fail C3 on the homepage and pass on inner pages. Override that one file in a child theme and change the `<h1>` to a `<p>`, keeping the existing class so the styling survives.

**Cause C, a page builder hero.** Hero and heading widgets carry their own HTML tag setting, and a hero that was duplicated from a template often keeps H1 while the post title block below it is also H1. Set the hero's heading tag to H2 and leave the post title as the single H1.

**Cause D, a plugin or widget adding a title.** Archive titles, breadcrumb headings and some banner plugins add a heading of their own. Deactivate the suspect plugin, re-run the counter, reactivate. The count tells you which one owns the extra element.

## When two `<h1>` elements are fine

If a page genuinely carries two independent purposes, two `<h1>` elements describe it honestly, and screen readers will read both. Accept the C3 point loss in that case. It is also fine to leave an empty `<h1>` out entirely on a page whose title sits in a `<title>` element and an `<h2>`, although C3 wants one. Do not chase the count by deleting the headline readers need.

Maintenance: a theme or builder update can put the level back. Re-run the counter after a theme update and after any header edit.

## Verify the fix

Run `npx aiscan-cli yoursite.com` and open **C3, Structured HTML** on the [content checks page](/docs/checks/content). It should list a single `<h1>` along with the title, meta description and JSON-LD points. By hand, `python3 h1count.py https://yoursite.com/` should print `h1 count: 1 -> PASS` and name your headline, not your logo.

**On WordPress**, the other three C3 signals (title, meta description and schema) live in your SEO plugin. [ThinkRank](https://thinkrank.ai) owns all three in one place instead of leaving two plugins to fight over the same tags, and it migrates settings from Rank Math, Yoast, AIOSEO and SEOPress. Yoast and Rank Math control the same fields if you already run one of them.

Related fixes: heading levels that skip a step are a different finding, covered in [heading order and skipped levels](/blog/fix-heading-order-skipped-levels), and the per-platform steps for the title, meta and schema points are in [title, meta and schema by platform](/blog/title-meta-schema-by-platform).

## Your next step

Count the `<h1>` elements on your homepage, fix the one the theme adds, then scan the site at [aiscan.site](https://aiscan.site/) and check C3. More short fixes are in the [guides](/guides).

