/en/tool/heading-structure/ works by URL or from code
Enter a URL — our server will fetch the page and list all headings in order, including the length of each one, the amount of text in the section below it, and any empty or hidden headings. It also parses pasted code and can process about twenty URLs at once.
Indentation shows the level; the marker on the left shows the level itself. A red marker indicates something to fix.
Tree
Line by line
| Level | Heading | Note | Characters | Words | Section |
|---|
One row per URL: number of headings, number of H1 headings, missing heading levels, and duplicate text.
List is empty
| URL | Total | Headings | H1 | Empty | Hidden | Gaps | Duplicates |
|---|
The server reads the markup exactly as the site returns it. Headings added by a script in the browser are not included — either here or when checking a single URL.
Enter the page address and click “Load”. The server will fetch the page using your selected browser and extract its headings and title — you do not need to open the code manually.
Look at the banner at the top: it compares the title and H1. Different texts are normal; an exact repeat is a reason to rewrite one of them.
Read the tree on the left and the table on the right. The table shows the length of each heading and how many words follow it before the next heading.
Fix things from top to bottom: first the number of H1 elements, then skipped levels, then headings longer than 70 characters and sections shorter than 40 words.
Empty and hidden headings are marked in both modes. Headings using role="heading" are marked too: in pasted code, they appear in their original position, while through the address they appear at the end of the list with the “out of order” label because the server returns them separately.
Download the result as a file: “CSV table” for a report and “MD table of contents” for a ready-made list with anchor links.
The input data is the same as the default field values: you can calculate it mentally and confirm that the tool is telling the truth.
There are seven headings in total: one H1, three H2, two H3, and one H4.
There is exactly one H1, and it comes first. It does not exactly match the title — that is normal: the title is longer and includes the workshop name.
After “Wheels”, “Spokes” appears at level four: level three is skipped, and the line is marked.
“Cable care” has three words beneath it, so the section is marked as short: here, the heading is more likely styling than a section.
If you enter the key phrase “choose a bicycle” in the field, the summary will show that it appears in H1 but does not appear in H2 at all.
Two issues stand out: the jump from H2 to H4 for “Spokes” and the three-word section under “Cable care”. Everything else is in order — the counters show seven headings and one H1.
Only the address you entered and the selected browser signature. The server opens the page on your behalf — the same-origin policy prevents this in a browser — and returns the headers, title, and response code. Neither the address nor the response is stored anywhere. Code pasted into the field never goes to the server: it is parsed on your device.
Yes. The server returns headings without text along with the others and marks those hidden with hidden, display:none, visibility:hidden, or aria-hidden. It also counts the words between neighboring headings, so the section length is visible from the address too. There is one thing it cannot see: headings added by a script in the browser — they simply do not exist in the markup returned by the site. You can find them by copying the code from the developer tools and pasting it into the second tab.
HTML allows several, and neither the browser nor the validator will object. But H1 answers the question “what is this page about?”, and there should be one answer. Two H1 elements usually mean that both the article heading and the site name ended up in the template.
For the HTML validator, no: the code remains valid. For someone using a screen reader, yes: they navigate by headings as if they were a table of contents, and a gap in the numbering makes it harder to understand what belongs under what.
These are not search engine rules but readability thresholds used by parsing tools. A heading longer than 70 characters stops being a table-of-contents line and becomes a sentence. A section shorter than 40 words usually means the heading was added for styling rather than to mark a section. Both thresholds are reasons to take a look, not requirements to make changes.
Yes, in both modes. For a screen reader, an element with role="heading" and aria-level is the same kind of heading as h2, and it is marked in the tree. The difference is where it appears: in pasted code, it appears where it occurs in the markup, while through the address the server returns such headings in a separate list, without their position in the document. That is why they appear at the end with the “out of order” label and do not count toward skipped levels. Headings inside hgroup after the first are treated as subheadings and are also excluded from level checks: they are captions for the neighboring heading, not separate sections.
Exactly: on the page, they really are headings, and a crawler sees them along with the others. If you need the structure of the content only, paste a piece of code without the header and footer into the second tab.
Headings are the page’s table of contents: they show both people and crawlers what it consists of and what each section is about. No tool can measure how much this affects rankings, and there is no promise to make here. A clear structure is useful in its own right.
Writes the title and description and instantly shows how they appear in search results.
Open
Shows the full path from the URL to the final page and the response codes.
Open