Skip to content

Heading structure SEO: headings, landmarks and link text

Heading structure SEO for people and machines: match the title and H1, keep heading levels logical, add main and nav landmarks, and write descriptive link text.

By Crawlito · 9 min read

In short

  • Google lists the title element, the main visual title and heading elements such as h1 among the sources it uses to build title links, so a title and H1 that agree send one clear signal.
  • Multiple H1s are allowed by the HTML standard and Google says heading order does not matter for Search, so a second H1 is a style issue, not a blocker.
  • The HTML standard does say each heading must be at most one level deeper than the one before it, so an h1 followed by an h3 is non-conforming.
  • The HTML standard allows only one main element without the hidden attribute per document; main, nav, aside and top-level header and footer map to ARIA landmarks that mark where each region is.
  • Google says good anchor text is descriptive, reasonably concise and relevant; 'click here' and 'read more' tell a crawler nothing about the target page.
On this page

Heading structure helps search engines and AI tools in a plain way: it tells any program reading your HTML what the page is about, where the main content starts and how its parts relate. That means a <title> and an <h1> that agree, heading levels that nest logically, main and nav landmarks around the right blocks, link text that names its destination, and lists and tables written as real HTML. None of it is a ranking lever on its own. It removes guesswork for every parser that reads the page.

This post covers each part with before and after HTML, how to check it from the command line or the browser console, and which "rules" are actually rules.

Why page structure matters to crawlers that read raw HTML

Google renders pages, and it still treats your HTML as evidence. Its title link documentation lists the sources it draws on, including the <title> element, the main visual title, heading elements such as <h1>, og:title, other large and prominent text, anchor text on the page and the text of links pointing to it. When those disagree, Google picks one, and it may not be the one you wanted.

AI crawlers are less documented. OpenAI, Anthropic and Perplexity publish what their bots are for and how to control them, but none of them says how their systems parse page structure. What has been measured is narrower: in Vercel and MERJ's December 2024 analysis, the major AI crawlers it tracked, including OpenAI's crawlers, ClaudeBot and PerplexityBot, did not run JavaScript at the time, so they read the raw HTML your server sends. Whatever extraction they do happens on that document. Open-source extractors such as Mozilla Readability, a standalone version of the library used for Firefox Reader View, guess the main content by scoring blocks on their tag names, class and id names, text length and link density. Clean structure makes that guess easy. A page built from anonymous <div> elements makes it hard.

Google is also clear that none of this is special AI markup. Its AI features page says there are no additional technical requirements for AI Overviews or AI Mode beyond being indexed and eligible for a snippet. Good structure is ordinary HTML done properly, which is covered in more depth in Google AI Overviews: the technical requirements.

How to align the title and the H1

The <title> is the page's name in the browser tab and in search results. The <h1> is the visible headline. They do not have to be identical, but they should describe the same thing. Google's advice is that titles be descriptive and concise, distinct for each page, and free of repeated or boilerplate text. It also says that when a page has more than one large, prominent heading, it may use the first one, and it suggests putting the main title in "the first visible <h1> element on the page".

Before: a generic title, the site logo marked up as the H1, and the real headline styled to look big.

html
<title>Home | Acme</title>
...
<header>
  <h1><img src="/logo.svg" alt="Acme"></h1>
</header>
<div class="hero-title">Waterproof hiking boots for wide feet</div>

After: the title and H1 say the same thing, and the logo is just a link.

html
<title>Waterproof hiking boots for wide feet | Acme</title>
...
<header>
  <a href="/"><img src="/logo.svg" alt="Acme home"></a>
</header>
<main>
  <h1>Waterproof hiking boots for wide feet</h1>
</main>

Two common causes of a mismatch are templates that use the site name as the H1 on every page, and CMS themes that print the post title in a styled <div> or <p>. The first gives every URL the same H1. The second leaves the real headline out of the heading structure entirely.

Are multiple H1s a problem?

No, not by themselves. The HTML standard says plainly that "a document can contain multiple top-level headings" and follows that with an example using three <h1> elements. Google's SEO starter guide says that, from Search's perspective, it does not matter if headings are out of order, and that there is no ideal number of headings.

MDN notes that multiple <h1> elements are allowed as long as they are not nested, but still recommends one per page as best practice, and that is sensible: one H1 that matches the title is the clearest possible signal. So treat it as a priority order:

SituationSeverityWhy
No H1, or the H1 is empty or an image with no alt textHighNothing on the page names its topic
The only H1 is the logo or site name on every pageHighEvery page claims the same topic
Title and H1 describe different thingsMediumGoogle and other parsers get two competing names
Two H1s that both describe the page, for example a headline and a hero headingLowAllowed by the standard, mildly confusing
One H1 per page that matches the titleNoneThe clearest structure

Audits that fail a page for a second H1 and pass it with no H1 at all have the order backwards.

How to keep heading levels logical

Headings are an outline. The HTML standard does have a firm rule here, and it is the one most people miss: each heading "must have a heading level that is less than, equal to, or 1 greater than" the heading before it. An <h1> followed by an <h3> is non-conforming. Google says out-of-order headings do not matter for Search, but screen reader users navigate by these levels, and table-of-contents generators build their tree from them.

Before: headings chosen for their font size.

html
<h1>Waterproof hiking boots for wide feet</h1>
<h4>Free returns within 60 days</h4>
<h2>How to choose a size</h2>
<h5>Measuring your foot</h5>
<p>Stand on a sheet of paper...</p>

After: levels follow the outline, and the promo line is a paragraph styled with CSS.

html
<h1>Waterproof hiking boots for wide feet</h1>
<p class="promo">Free returns within 60 days</p>
<h2>How to choose a size</h2>
<h3>Measuring your foot</h3>
<p>Stand on a sheet of paper...</p>

Two habits keep this right. Use a heading only when the text introduces a section, never to make text bigger: MDN says to use CSS font-size for that. And write headings that make sense out of context. "Overview" and "Details" tell a reader skimming the outline nothing; "How to choose a size" does.

Which landmarks to use: main, nav, article and the rest

Landmarks are HTML elements that mark the regions of a page. The W3C's landmark guidance maps them to ARIA roles:

ElementLandmarkNotes
<main>mainThe dominant content. Only one main without the hidden attribute per document
<nav>navigationGive each nav a distinct label if there are several
<header>bannerOnly when it is not inside article, aside, main, nav or section
<footer>contentinfoSame condition as header
<aside>complementaryContent only loosely related to the main content
<section>regionOnly when it has an accessible name, from aria-label or aria-labelledby
<article>noneA self-contained piece such as a blog post or product card

The rule for main comes from the HTML standard: "a document must not have more than one main element that does not have the hidden attribute specified", and its only ancestors may be html, body, div, a form without an accessible name, or custom elements. A main inside an article or section is non-conforming.

Before: everything is a div, so a parser has to guess where the menu ends and the article starts.

html
<div class="top">
  <div class="menu"><a href="/">Home</a> <a href="/boots">Boots</a></div>
</div>
<div class="content">
  <div class="post-title">How to waterproof leather boots</div>
  <div class="post-body">...</div>
</div>
<div class="sidebar">Related posts...</div>

After: the same layout with landmarks.

html
<header>
  <nav aria-label="Main">
    <ul>
      <li><a href="/">Home</a></li>
      <li><a href="/boots">Boots</a></li>
    </ul>
  </nav>
</header>
<main>
  <article>
    <h1>How to waterproof leather boots</h1>
    ...
  </article>
</main>
<aside aria-labelledby="related">
  <h2 id="related">Related posts</h2>
  ...
</aside>
<footer>...</footer>

The visible page does not change. What changes is that "the main content" now has a name in the markup. Keep expectations realistic: Google's starter guide notes that Search "can rarely depend on semantic meanings hidden in the HTML specification", so landmarks help extractors and assistive technology rather than acting as a Google ranking signal.

Google's link guidance has two parts. First, Google can generally crawl a link only if it is an <a> element with an href attribute. It lists links built from <span> elements, onclick handlers or javascript: URLs as not recommended: it may still try to resolve them, but you should not rely on it. Second, anchor text should be "descriptive, reasonably concise, and relevant" to the page it is on. Google's test is simple: read the anchor text out of context, and if it is not specific enough to make sense by itself, rewrite it.

Before:

html
<p>We tested five boot waxes. <a href="/blog/boot-wax-test">Click here</a> to read more.</p>
<span onclick="location.href='/boots/wide'">Shop wide boots</span>
<a href="/blog/care">Read more</a>

After:

html
<p>We tested five boot waxes: see the <a href="/blog/boot-wax-test">boot wax comparison</a>.</p>
<a href="/boots/wide">Shop wide-fit boots</a>
<a href="/blog/care">Read more about leather boot care</a>

The same standard is an accessibility requirement: WCAG 2.4.4, Link Purpose (In Context), a Level A criterion, asks that each link's purpose be clear from its text or its context. Descriptive internal links also help crawlers discover and label your pages, which internal links and broken links covers in detail.

Use real lists and tables, not styled divs

Specifications, prices, steps and comparisons are the kind of facts people look up, and they are easy to lose in markup. Put them in elements that carry their structure.

Before: a "table" built from divs, where the relationship between label and value exists only in the CSS.

html
<div class="specs">
  <div class="row"><div>Weight</div><div>540 g</div></div>
  <div class="row"><div>Upper</div><div>Full-grain leather</div></div>
</div>

After: a real table with header cells, so "540 g" is tied to "Weight" in the markup itself.

html
<table>
  <caption>Specifications</caption>
  <tbody>
    <tr><th scope="row">Weight</th><td>540 g</td></tr>
    <tr><th scope="row">Upper</th><td>Full-grain leather</td></tr>
  </tbody>
</table>

Use <ol> for steps where order matters, <ul> for unordered items and <dl> for term and definition pairs. If the same facts also appear in your JSON-LD, keep them identical: structured data for AI search explains why mismatches are a problem.

How to check your page structure

Check the raw HTML first, because that is what a crawler that does not run JavaScript reads. This command prints the title and every heading in the server response:

bash
curl -s -A "Mozilla/5.0 (compatible; GPTBot/1.4; +https://openai.com/gptbot)" https://example.com/page \
  | perl -0ne 'print "title: $1\n" if /<title[^>]*>(.*?)<\/title>/is;
    while (/<(h[1-6])\b[^>]*>(.*?)<\/\1>/gis) { my ($h, $t) = (uc $1, $2);
    $t =~ s/<[^>]+>//g; $t =~ s/\s+/ /g; print "$h: $t\n" }'

Look for: a title and an H1 that match, no skipped levels, and headings that are present at all. If the output is empty but the page shows headings in the browser, the content is injected by JavaScript, and raw HTML vs rendered HTML explains what to do next. More curl techniques are in how to see your page as an AI crawler.

Then check the rendered page in the browser console, running each snippet on its own (the console only prints the result of the last expression):

js
// Heading outline
[...document.querySelectorAll("h1,h2,h3,h4,h5,h6")]
  .map((h) => `${h.tagName}: ${h.textContent.trim()}`).join("\n");

// Landmarks: expect exactly one visible main
({ main: document.querySelectorAll("main:not([hidden])").length,
   nav: document.querySelectorAll("nav").length });

// Generic link text
[...document.querySelectorAll("a[href]")]
  .filter((a) => /^(click here|here|read more|learn more|more)$/i.test(a.textContent.trim()))
  .map((a) => a.href);

Firefox and Chrome DevTools can also show the accessibility tree, which includes landmark roles and headings the way assistive technology receives them.

Frequently asked questions

Do multiple H1 tags hurt SEO?

Not on their own. The HTML standard allows several top-level headings, and Google says heading order does not matter for Search. One H1 that matches the title is still the clearest choice, and a missing H1 is a bigger problem than a second one.

Does the title tag have to match the H1 exactly?

No. They should describe the same topic, but the title often adds the brand name or a shorter phrasing. Google lists both as sources for title links, so large differences invite it to choose one for you.

Do AI crawlers use headings and landmarks?

OpenAI, Anthropic and Perplexity do not document how their systems parse page structure. Vercel and MERJ's December 2024 measurements found that the major AI crawlers, including GPTBot, ClaudeBot and PerplexityBot, did not run JavaScript, so the headings, landmarks and lists in your raw HTML are the structure they can see.

Is skipping a heading level an error?

Under the HTML standard, yes: a heading must be at most one level deeper than the one before it. Google says heading order does not matter for Search, but a skipped level breaks the outline for screen reader users and other tools.

Should I add ARIA roles like role="main" as well as the main element?

No. The main, nav, aside, header and footer elements already map to landmark roles. Add ARIA only when you cannot use the native element.

Check your own page

Fix the title and H1 first, then heading levels, landmarks and link text, and re-run the curl command above to confirm the raw HTML carries the change. To see how one page looks to a crawler, run the free check: it covers a single public page and needs no account. For a whole site, an audit runs deterministic checks, including a missing H1, skipped heading levels and a missing main landmark, across up to 500 pages, and delivers a PDF with the evidence and prioritized fixes.

Filed under Structure and schema. Topics: headings, internal-links, ai-crawlers, google, checklist