All posts
8 min read

Tables of Contents and AI Extraction: Structure as Signal

A table of contents with real anchor links exposes your document outline to AI parsers and enables fragment deep links in citations. Here is how to build one.

A table of contents in a nav element on the left with anchor links mapping one-to-one onto heading ids in a document outline, and a citation deep-linking to one section fragment.

A table of contents is not a usability nicety. To an AI parser, a ToC with real anchor links is a machine-readable map of your document: it declares what the page covers, names each section in the author's own words, and pins every section to a stable URL fragment. That's three extraction signals in one block of HTML - topical coverage, section labels, and addressability - and you get all three for the cost of a nav element and some heading ids.

The addressability part is the underrated half. Answer engines sometimes cite deep links - yoursite.com/guide#pricing-model rather than the bare URL - and they can only do that when your headings carry ids worth linking to. A page without anchors can only ever be cited as a whole; a page with them can be cited section by section, which matters a lot on long pages where the relevant passage is four thousand words in.

This post covers what a ToC actually communicates to a parser, how fragment deep links show up in citations, the implementation that works, and the WordPress-specific details.

What a ToC tells a parser

Extraction pipelines don't read pages the way people do. They segment HTML into a content tree, and heading elements are the primary segmentation signal: each h2 opens a section, each h3 a subsection, and passages get associated with the heading above them. We walk through that segmentation in what AI crawlers look for on your pages.

A ToC reinforces that segmentation in three concrete ways.

  • It states coverage up front. A list of eight section titles near the top of the page is a compressed declaration of everything the page answers. Retrieval systems matching a query against your page get a dense, early block of topic terms - in effect, keywords you chose as section names.
  • It confirms the outline. When the ToC links match the heading structure one-to-one, a parser gets two independent representations of the same hierarchy that agree with each other. Pages assembled from templates and widgets often have broken or decorative heading structures; a consistent ToC-to-heading mapping is evidence the outline is real.
  • It labels sections with anchor text. Each ToC entry is anchor text pointing at a section. Anchor text is a classic relevance signal - the same reason internal links work, as we cover in internal linking for AEO topic clusters - and a ToC is a block of perfectly accurate internal anchor text you control completely.

None of this requires the parser to "understand" tables of contents as a concept. Every signal above falls out of ordinary HTML parsing: a nav full of same-page links, heading elements with ids, anchor text matching heading text.

Fragment deep links in AI citations

URI fragments - the #section-id part of a URL, defined in RFC 3986 - resolve client-side: the browser scrolls to the element whose id matches. Search and answer engines have used this for years to send users to the relevant part of a long page. Google's featured snippets pioneered jump links, and modern browsers extended the idea with the Scroll To Text Fragment spec (#:~:text=...), which highlights an exact passage on arrival.

Answer engines inherit this behavior unevenly, but the pattern is real: citations sometimes carry fragments, landing users directly on the section that supported the claim. When that happens, two good things follow. The user who clicks lands on the exact answer instead of the top of a long page, which is the difference between a bounce and a conversion. And your section - not just your domain - becomes the referenced unit, which is how a single deep guide earns citations across many distinct queries.

The precondition is simply that stable, meaningful ids exist on your headings. An engine can't deep-link to #section-4 if your headings have no ids, and it won't trust ids that change between crawls. Auto-generated ids derived from heading text ("pricing-model", "how-it-works") are ideal: human-readable, stable as long as the heading is stable, and self-describing in the URL.

Implementation: a nav element and matching ids

The whole pattern is about fifteen lines of HTML. The load-bearing details:

  • Use a semantic nav element with a label: <nav aria-label="Table of contents">. The nav element tells parsers and assistive tech this block is navigation, not body content - so it gets treated as structure rather than mistaken for a content list.
  • Use a real list of real anchors. A ul of <a href="#section-id"> links. Every href must point at an id that actually exists on a heading in the page.
  • Put ids on the headings themselves. <h2 id="pricing-model">Pricing model</h2>. Ids on wrapper divs work in browsers but weaken the direct heading-to-anchor association that parsers read.
  • Match anchor text to heading text. The ToC entry and the heading should say the same thing, or a tight abbreviation of it. Divergent labels waste the confirmation signal.
  • Render it server-side. A ToC assembled by client-side JavaScript after page load is invisible to most AI crawlers - GPTBot and PerplexityBot do little to no JavaScript execution, a constraint we detail in SSR vs CSR for AI crawlers. The nav, the links, and the heading ids all need to be in the initial HTML response.
  • Keep it near the top. After the intro, before the first h2. That's where both readers and truncation-prone ingestion pipelines will find it.

Skip the fancy variants. Collapsed-by-default ToCs are fine if the collapse is CSS-only and the links remain in the HTML; ToCs inside JavaScript accordion widgets that inject links on click are not. Floating sidebar ToCs work when they're rendered in the markup, but check what they look like in the raw HTML source, not in the browser.

The ToC is only as good as the heading outline

A ToC can't fix a broken outline - it can only expose one. Before adding the nav, make the headings themselves worth mapping.

  • One h1 per page, the title. Everything else starts at h2.
  • No skipped levels. An h4 directly under an h2 tells the parser your hierarchy is decorative. Nest h2 to h3 to h4 in order.
  • Headings as claims or questions, not teasers. "How fragment deep links appear in citations" segments and retrieves better than "Going deeper". The heading is the retrieval label for every passage under it.
  • Sections that stand alone. Since fragments make sections independently addressable, write each section to be readable from a cold start - a fragment click lands mid-page with zero preceding context.

Heading semantics are part of the broader case for structural markup, which we make in semantic HTML for AI extraction: elements that declare meaning beat styled divs every time a machine reads your page.

WordPress specifics

WordPress makes this pattern nearly free, with a few traps.

The block editor can add HTML anchors to any heading block: select the heading, open the Advanced panel, and set the anchor. Many themes and the core Table of Contents block generate ids automatically from heading text. Either way, verify the output - view the rendered page source and confirm the ids are present in the HTML, not added later by a script.

If you use a ToC plugin, the audit question is always the same: does it output a server-rendered nav with plain anchor links, or does it inject the ToC with JavaScript? Plugins that build the ToC in PHP at render time pass; plugins that assemble it in the browser fail for most AI crawlers even though they look identical to a human visitor.

Two more WordPress-specific checks. First, aggressive "SEO-friendly" plugins sometimes strip or rewrite heading ids on save - after any plugin change, confirm old fragment URLs still resolve, because inbound deep links break silently. Second, page builders often wrap headings in several layers of styled divs; make sure the id ends up on the h2/h3 itself. Our WordPress AEO guide covers the wider setup, and the Citevera WordPress plugin flags heading-structure problems directly in the editor.

Testing your ToC like a crawler

Don't trust the browser view - test the raw HTML.

  • Fetch the page with curl (curl -s https://yoursite.com/guide/ | grep 'id="') and confirm every heading id appears in the response body.
  • Check the nav is present in the same output: grep -i '<nav' should show your ToC with its links.
  • Click a fragment URL directly in a fresh tab - yoursite.com/guide/#section-id - and confirm it lands on the right section.
  • Diff ToC hrefs against heading ids. Every href="#x" needs a matching id="x"; orphaned links are common after content edits.

Frequently asked questions

Does a table of contents directly improve AI citation rates?

No mechanism guarantees that, and you should distrust anyone claiming a measured lift. What a ToC verifiably does is expose your document outline in parseable form, add accurate anchor-text labels for every section, and make sections individually addressable via fragments. Those are the raw materials retrieval and citation systems work with.

Should the ToC list h2s only, or h3s too?

List every h2, and include h3s only when a subsection answers a distinct query someone might land on directly. A two-level ToC on a long guide is useful structure; a four-level ToC reproducing every h4 is noise for readers and adds little for parsers.

Do heading ids need to contain keywords?

They should be readable slugs of the heading text, which naturally contain the section's key terms. Don't stuff them - #pricing-model is right, #best-cheap-pricing-model-2026-guide is spam. The id's job is stability and self-description, and it appears verbatim in any deep-link citation.

What happens to fragment links if I rename a heading?

If your ids are auto-generated from heading text, renaming the heading changes the id and silently breaks every existing deep link to that section. When editing a heading on a page that already earns citations, keep the old id explicitly - set it as the anchor manually - so inbound fragments keep resolving.

See what your structure looks like to a machine

The gap between "has a ToC" and "has a parseable ToC" is exactly the kind of thing that's invisible in a browser and obvious in raw HTML. A Citevera audit checks your heading hierarchy, anchor integrity, and server-rendered structure across the site and turns the failures into copy-paste fixes. And if you suspect crawlers aren't reaching the HTML at all, start with the free AI crawler access checker.