Foundational guide · Foundations

How to Turn a Website Into LLM-Ready Markdown

Why clean, structured text often matters more than raw HTML in AI workflows.

AG

Written by Aaron Grainger

Independent Content Strategist & Product-Marketing Writer · Published Nov 12, 2024

Primary audience
AI application developers
Also useful for
AI engineers and technical founders
Tone
Educational
Reading time
4 min
Published
Nov 12, 2024

Direct answer

Turning a page into LLM-ready Markdown means keeping the structures that carry meaning — headings, lists, tables, code, link targets — and discarding everything that only serves rendering. Start from the page's main content region, strip navigation and chrome, preserve heading hierarchy, and attach the canonical URL and retrieval time. The result should read like the article, not like the website. Verify with a simple test: can a person answer the page's core question from the Markdown alone?

On this page
  1. Raw HTML versus readable semantic content
  2. What counts as noise
  3. What to preserve deliberately
  4. A conceptual before and after
  5. A simple normalization sketch
  6. Limitations and edge cases

Raw HTML versus readable semantic content

A modern page is mostly instructions for a browser. Wrapper elements, utility classes, inline styles, analytics payloads, and framework state can account for the overwhelming majority of the bytes. None of it tells a language model anything about the subject of the page.

What does carry meaning is a small set of structures: the heading hierarchy that shows how the content is organised, lists that show enumeration, tables that show relationships, code blocks that must be reproduced exactly, and link targets that show what the page points at. Markdown preserves all of these in a fraction of the space.

What counts as noise

  • Primary and secondary navigation, breadcrumbs, and mega-menus
  • Cookie and consent notices, region pickers, and app-install prompts
  • Footers with sitemap-scale link lists repeated on every page
  • Related-content rails, newsletter forms, and share widgets
  • Advertising slots and their placeholder text
  • Text duplicated from the page title, site name, or section index

The problem with retaining these is not only length. Every page in a site carries the same footer, so a retrieval index built from unnormalized pages contains hundreds of near-identical passages. A query that happens to match footer vocabulary will retrieve an arbitrary selection of them.

What to preserve deliberately

ElementWhy it mattersCommon mistake
Heading hierarchyGives the chunker natural boundaries and the model a structural mapMultiple H1s, or the site name used as H1
ListsSignals enumeration and stepsFlattened into prose, losing order
TablesEncodes relationships between valuesSerialised into an unordered run of numbers
Code blocksMust be exact; language mattersDropped as low-prose-density content
Link targetsShows what the page referencesAnchor text kept, destination discarded
Canonical URLDeduplication and citationReplaced with the requested URL
Title and descriptionCheap, high-signal metadataNot captured at all

A conceptual before and after

Before — raw fragment
<div class="wrap lg:grid-cols-12">  <nav aria-label="Main"><ul><li><a href="/">Home</a></li>…</ul></nav>  <div class="cookie-bar">We use cookies…</div>  <main>    <h1 class="t-1">Rotating API keys</h1>    <p class="lede">Keys can be rotated without downtime.</p>    <pre><code class="lang-bash">sf keys rotate --id KEY_ID</code></pre>  </main>  <aside class="rail">You might also like…</aside></div>
After — normalized
---title: Rotating API keyscanonical_url: https://example.com/docs/auth/rotationretrieved_at: 2026-09-14T09:41:00Z--- # Rotating API keys Keys can be rotated without downtime. ```bashsf keys rotate --id KEY_ID```

A simple normalization sketch

Illustrative workflow pseudocode
# Illustrative only — not a runnable API.doc = retrieve(url="https://example.com/docs/auth/rotation", format="markdown") doc = strip_regions(doc, ["nav", "footer", "aside", ".cookie-bar"])doc = protect(doc, ["pre", "code", "table"])   # never drop thesedoc = collapse_repeats(doc)                     # remove site-wide duplicated text record = {    "title": doc.title,    "canonical_url": doc.canonical_url or url,    "content": doc.markdown,    "retrieved_at": now_iso(),} assert len(record["content"]) > 300, "page produced no usable content"

Is this page ready for an LLM workflow?

  • The Markdown reads like the article, with no navigation or consent text
  • There is exactly one H1 and the heading hierarchy is sane
  • Every code block and table from the page is present and intact
  • Link destinations are preserved, not just anchor text
  • Canonical URL, title, and retrieval time are stored with the content
  • Content length is plausible for this page type
  • No text is repeated verbatim from other pages on the same site
  • A person could answer the page's core question from the Markdown alone

Limitations and edge cases

  • Pages whose meaning is visual — charts, diagrams, annotated screenshots — lose information that Markdown cannot carry. Capture the caption and alt text and note the loss.
  • Deeply nested or merged-cell tables do not survive flattening cleanly; consider extracting them into structured records separately.
  • Single-page applications may render the main content region only after interaction, so normalization rules built for the server response will find nothing.
  • Some documentation encodes meaning in tabs or accordions; naive extraction may concatenate mutually exclusive variants into one confusing document.
  • Aggressive boilerplate removal can delete short but essential content, such as a one-line deprecation notice in a styled callout.

Questions that keep coming up

Practical takeaway

  • HTML encodes presentation; Markdown retains the structure a model can use.
  • Boilerplate does not just waste tokens — it competes during retrieval.
  • Tables and code blocks are the most common casualties of aggressive cleaning.
  • Metadata beats the last five percent of body text.
  • Normalize once, store it, and reuse it for retrieval, diffing, and extraction.

Related content

Version history

Current: 1.0 · Published

  1. 1.0Nov 12, 2024First published.

Was this useful?

Sourceframe is an independent product concept created for research, product-design, and technical-content exploration. It is not an operating company, and nothing here describes a live commercial service. All examples, schemas, and code are illustrative unless a page says otherwise. No client data, customer outcomes, performance results, or partnerships are described anywhere on this site.