DEV Community

Cover image for Autonomous Heading Hierarchy Auditing: Semantic Structure for Humans & Machines
Sameer Hassan
Sameer Hassan

Posted on

Autonomous Heading Hierarchy Auditing: Semantic Structure for Humans & Machines

In modern web development, styling frameworks like Tailwind CSS make it deceptively easy to choose HTML tags based on visual font size rather than document semantics:

<!-- ❌ ANTI-PATTERN: Jumps from H1 to H4 for styling reasons -->
<h1>Plyxo Intelligence Platform</h1>
<h4 class="text-sm font-semibold text-slate-500">Autonomous Diagnostics</h4>
Enter fullscreen mode Exit fullscreen mode

While this might look acceptable on screen, it causes severe damage under the hood:

  1. Screen Reader Accessibility (WCAG 2.1 Criterion 1.3.1): Visually impaired users rely on heading hotkeys (e.g. pressing H in NVDA/VoiceOver) to navigate page sections. Skipped heading levels cause navigation disorientation.
  2. Answer Engine Parsing (Perplexity, ChatGPT): AI scrapers extract headings into hierarchical outline trees before summarization. Disjointed heading trees fragment the document's semantic entity relationships.
  3. Google Core Ranking Signals: Search crawlers use heading nesting (H1 ➔ H2 ➔ H3) to determine topical hierarchy and keyword importance.

In ⚡ PLYXO (CRO • SEO • AIO • AEO • GEO), our Claude-SEO audit engine parses and enforces strict heading hierarchy rules.


1. The Strict Heading Tree Rules

┌─────────────────────────────────────────────────────────────┐
│                VALID SEMANTIC HEADING TREE                  │
└─────────────────────────────────────────────────────────────┘
                               │
               <h1> Primary Page Title (Exact 1)
                               │
            ┌──────────────────┴──────────────────┐
            ▼                                     ▼
   <h2> Major Section A                  <h2> Major Section B
            │                                     │
      ┌─────┴─────┐                               ▼
      ▼           ▼                      <h3> Sub-Topic B1
<h3> Sub A1   <h3> Sub A2
Enter fullscreen mode Exit fullscreen mode

Mandatory Invariants:

  • Single H1 Invariant: Exactly one <h1> per page.
  • No Level Skipping: You cannot jump from <h2> directly to <h4> without an intervening <h3>.
  • Style Decoupled from Semantics: Use Tailwind utility classes (text-lg, text-sm, font-bold) to adjust visual sizing without modifying the heading tag.

2. Programmatic Heading Tree Auditing in TypeScript

Here is the AST tree verification algorithm used in Plyxo to validate heading structures:

import * as cheerio from 'cheerio';

export interface HeadingNode {
  level: number;
  text: string;
  line?: number;
}

export interface HeadingAuditReport {
  isValid: boolean;
  h1Count: number;
  violations: string[];
  outline: HeadingNode[];
}

export function auditHeadingHierarchy(htmlContent: string): HeadingAuditReport {
  const $ = cheerio.load(htmlContent);
  const headings: HeadingNode[] = [];
  const violations: string[] = [];

  $('h1, h2, h3, h4, h5, h6').each((_, el) => {
    const tagName = el.tagName.toLowerCase();
    const level = parseInt(tagName.replace('h', ''), 10);
    const text = $(el).text().trim();
    headings.push({ level, text });
  });

  const h1Elements = headings.filter(h => h.level === 1);
  if (h1Elements.length === 0) {
    violations.push('Critical: Missing <h1> tag. Every page must have exactly one primary <h1>.');
  } else if (h1Elements.length > 1) {
    violations.push(`Warning: Multiple <h1> tags found (${h1Elements.length}). Consolidate into a single primary <h1>.`);
  }

  // Validate sequential nesting
  let prevLevel = 1;
  for (let i = 0; i < headings.length; i++) {
    const current = headings[i];
    if (i > 0 && current.level > prevLevel + 1) {
      violations.push(
        `Hierarchy Violation: Heading jumped from <h${prevLevel}> ("${headings[i - 1].text}") to <h${current.level}> ("${current.text}").`
      );
    }
    prevLevel = current.level;
  }

  return {
    isValid: violations.length === 0,
    h1Count: h1Elements.length,
    violations,
    outline: headings,
  };
}
Enter fullscreen mode Exit fullscreen mode

3. Why This Matters for Answer Engines (GEO)

When Perplexity AI or Claude Search ingests your documentation, it converts heading hierarchies into an outline graph. If your headings cleanly demarcate topics (What is X ➔ Architecture of X ➔ Code Example for X), the LLM easily extracts precise paragraph quotes and attributes citations to your domain.

👉 Audit your website's semantic structure with Plyxo on GitHub

Top comments (0)