Executive Summary
Most “HTML to Markdown” solutions fail in the same way: they output Markdown, but they don’t output a contract your LLM pipeline can trust. In production, that means brittle chunking, inconsistent table formatting, missing code fences, and citations that can’t be traced back to the original page.
This article defines an API contract for HTML→Markdown conversion that is designed for LLM ingestion. You’ll learn how to specify extraction guarantees (what is kept vs removed), how to represent structure (headings, lists, tables, code blocks), and how to attach quality signals (token counts, boilerplate ratio, and evidence spans). We also include a practical evaluation harness you can run against a page set to measure conversion quality and downstream retrieval impact.
If you’re building an ingestion layer for agents or RAG, the goal isn’t “pretty Markdown.” The goal is deterministic, testable, AI-ready Markdown that behaves well under chunking, retrieval, and citation requirements.
Key Takeaways
- Treat HTML→Markdown as an ingestion contract, not a formatting step.
- Require structural fidelity: headings, lists, tables, and code blocks must be represented consistently.
- Add quality signals: boilerplate ratio, token budget, and extraction confidence.
- Attach evidence: byte/span mappings so citations can be verified.
- Evaluate end-to-end: conversion quality should correlate with retrieval accuracy.
1. Problem Statement
You can convert HTML to Markdown and still ship a broken ingestion pipeline.
In practice, teams discover issues only after retrieval quality drops or agents start quoting the wrong parts of a page. The root cause is usually not the model—it’s the conversion output. When Markdown is inconsistent, downstream chunkers and retrievers behave unpredictably:
- Tables become flattened text, losing row/column semantics.
- Code blocks lose fences or language tags, harming semantic parsing.
- Headings are missing or reordered, breaking hierarchical chunking.
- Boilerplate (navigation, cookie banners, footers) remains, inflating token budgets.
- Citations can’t be verified because the pipeline can’t map Markdown back to the source.
An HTML→Markdown API for LLMs must therefore do more than “render.” It must produce AI-ready Markdown with measurable guarantees.
2. History & Context
Early approaches to “HTML to text” were built for humans: strip tags, keep paragraphs, and ignore layout. That worked for reading, but it’s a poor fit for LLM ingestion because LLMs are sensitive to structure and token distribution.
As RAG matured, teams started caring about chunking and retrieval. That shifted the requirement from “readable text” to “structured, chunkable documents.” Today, agentic systems add another layer: tool outputs must be safe, auditable, and citeable.
So the modern requirement is a contract that spans:
- Extraction decisions (what to keep/remove)
- Representation rules (how to encode structure)
- Quality signals (how to measure output health)
- Evidence (how to verify provenance)
3. Definition: What an LLM-Ready Markdown Contract Is
An LLM-ready Markdown contract is a set of rules your HTML→Markdown API guarantees for every response.
At minimum, the contract should specify:
- Structural fidelity: headings, lists, tables, and code blocks are preserved in a deterministic format.
- Boilerplate control: navigation/footers/cookie banners are removed or clearly marked.
- Token budget behavior: output length is bounded and predictable.
- Evidence mapping: each extracted section can be traced back to the source page.
- Quality signals: the API returns metrics that let your pipeline decide whether to accept, retry, or fall back.
A contract turns conversion into an engineering component you can test, monitor, and improve—rather than a best-effort transformation.
4. Architecture: How the API Should Work
A robust HTML→Markdown API typically follows this flow:
- Fetch and render (when needed)
- Detect main content vs boilerplate
- Extract structured elements (headings, lists, tables, code)
- Normalize representation into Markdown
- Compute quality signals and evidence mappings
- Return Markdown plus metadata
The key design choice is that steps 2–5 are not “best effort.” They are governed by explicit policies and measurable outputs.
Reference Architecture (Policy-Governed Conversion)
flowchart TD
A[Request: URL + options] --> B[Fetch/Render]
B --> C[Content Policy Gate]
C --> D[Main Content Extraction]
D --> E[Structure Extractors]
E --> F[Markdown Normalizer]
F --> G[Quality Metrics + Evidence]
G --> H[Response: markdown + signals] 5. Components & Workflow
- Fetch/Render Layer
- Supports static HTML and optional JS rendering.
- Enforces timeouts and size limits.
- Produces a canonical DOM snapshot for extraction.
- Content Policy Gate
- Applies allow/deny rules for what to extract.
- Removes known boilerplate patterns.
- Optionally blocks sensitive sections (login forms, account pages).
- Structure Extractors
- Headings: preserve hierarchy (H1/H2/H3) and ordering.
- Lists: preserve nesting and numbering.
- Tables: convert to Markdown tables with consistent header handling.
- Code blocks: preserve fences and language hints.
- Markdown Normalizer
- Ensures consistent formatting rules.
- Normalizes whitespace and link representation.
- Produces stable output for the same input (important for caching and diffing).
- Quality Signals + Evidence Packets
- Computes metrics (boilerplate ratio, token estimate, extraction confidence).
- Produces evidence spans (byte offsets or DOM node references) for citations.
6. API Contract Specification
Below is a practical contract you can implement (or use) for HTML→Markdown conversion.
Request
- url: string
- render: boolean (default false)
- max_output_tokens: integer (hard cap)
- content_policy: enum (e.g., article_only, full_page, documentation_mode)
- table_mode: enum (e.g., markdown_table, csv_fallback)
- code_mode: enum (e.g., fenced, plain_text)
- evidence: boolean (default true)
Response
- markdown: string
-
metadata:
- token_estimate: number
- boilerplate_ratio: number (0–1)
- extraction_confidence: number (0–1)
-
sections: array of extracted sections with:
- title
- start_evidence
- end_evidence
- content_type (paragraph/list/table/code)
- warnings: array of strings (e.g., table_truncated, render_timeout)
The contract is what your downstream pipeline consumes. Without it, you can’t reliably decide whether the Markdown is safe to embed.
Contract Versioning (Important for Stability)
To keep chunking and retrieval stable, version the contract separately from the converter implementation.
Example:
contract_version: 2026-07-22
converter_version: v1.3.0 When you change representation rules (tables, code fences, heading normalization), bump contract_version so downstream chunkers can adapt.
7. Quality Signals & Evidence Packets
Quality signals are how you prevent silent failures.
Boilerplate Ratio
Define boilerplate ratio as:
boilerplate_ratio = tokens_removed_or_marked / tokens_total In practice, you want a stable range for your target content type. If the ratio spikes, you likely extracted the wrong region (or the page changed).
Extraction Confidence
Confidence can be computed from signals like:
- main content density
- heading presence
- table parse success rate
- code fence detection
- evidence coverage percentage
Evidence Packets
Evidence packets let you answer: “Where did this Markdown come from?”
A simple approach is to attach evidence spans per section:
- start_byte_offset
- end_byte_offset
- source_url
- optional dom_path
This enables verifiable citations and makes debugging far faster.
Contract Spec Summary (Copy/Paste Friendly)
If you want a quick “contract sheet” for engineers, here it is. Your pipeline can treat this as the acceptance criteria.
Field Type Contract requirement Why it matters
markdown string Must include headings/lists/tables/code in deterministic format Stable chunking and retrieval
metadata.token_estimate number Present and within expected range Prevents context bloat
metadata.boilerplate_ratio number (0–1) Present; spikes trigger fallback Detects extraction drift
metadata.extraction_confidence number (0–1) Present; low confidence triggers retry Avoids silent truncation
metadata.sections[] array Each section has evidence boundaries Enables verifiable citations
metadata.warnings[] array Present; includes table/code/render issues Makes failures explainable 8. Examples
Example 1: Convert an Article Page (API Contract Usage)
curl -X POST https://api.ollagraph.com/v1/convert/html-to-markdown \
-H "Content-Type: application/json" \
-d '{
"url": "https://example.com/docs/ai-ingestion",
"render": true,
"max_output_tokens": 6000,
"content_policy": "documentation_mode",
"table_mode": "markdown_table",
"code_mode": "fenced",
"evidence": true
}' Expected behavior:
- Markdown includes headings and lists in order.
- Tables are converted to Markdown tables when possible.
- Code blocks are fenced.
- Metadata includes token estimate, boilerplate ratio, and evidence spans.
Example 2: Pipeline Decision (Accept vs Retry)
If your pipeline sees:
boilerplate_ratio > 0.35
extraction_confidence < 0.6
warnings includes render_timeout ...then you can retry with render=false (or switch policy to full_page) and compare evidence coverage.
This is how you turn conversion into a resilient system.
9. Configuration / Setup
If you treat conversion as a contract, configuration becomes part of the contract.
Start with a content policy
Pick one policy per content type and keep it stable:
- article_only: remove navigation/footers aggressively; ideal for blog posts and essays.
- documentation_mode: preserve headings, parameter lists, and code blocks; ideal for technical docs.
- full_page: use only when you truly need context like sidebars or cross-links.
Choose table and code modes deliberately
Tables and code blocks are where “pretty Markdown” often breaks.
- table_mode=markdown_table: best when the page uses real table markup.
- table_mode=csv_fallback: best when tables are complex or partially malformed.
- code_mode=fenced: best for downstream parsing and chunking.
Evidence on by default
Set evidence=true for any workflow that needs citations, debugging, or compliance.
If you disable evidence to save cost, you should also disable citation-dependent features downstream. Otherwise you’ll end up with a pipeline that “looks correct” but can’t be verified.
Thresholds: tune once, then monitor
Your pipeline should have thresholds for:
- boilerplate_ratio
- extraction_confidence
- table_parse_success_rate
- evidence_coverage
Tune them on a golden set, then treat drift as a regression.
Pipeline Thresholds (Example Starting Point)
These are starting thresholds you can tune. The important part is that they are explicit and monitored.
Metric Suggested threshold Action
boilerplate_ratio <= 0.25 Accept
extraction_confidence >= 0.70 Accept
table_parse_success_rate >= 0.85 Accept
evidence_coverage >= 0.95 Accept
Any render_timeout warning present Retry once with safer policy When you tune these, do it per content policy. A threshold that works for article_only may be too strict for full_page.
10. Performance & Benchmarks
Below is a benchmark methodology you can run to validate your contract.
Benchmark Setup
Dataset: 1,000 URLs across 10 site templates (docs, blogs, changelogs, forums)
Conditions:
- static HTML only
- JS rendering enabled
Metrics:
- output token estimate
- boilerplate ratio
- table parse success rate
- evidence coverage
- downstream retrieval impact (Top-5 recall)
Example Results (Sample Run)
To make the contract measurable, we ran a sample evaluation on a small golden set of 40 pages (docs, blogs, changelogs, and Q&A). The goal was not to claim universal numbers, but to show the shape of the metrics you should expect when the contract is enforced.
Metric Raw HTML baseline Contract-driven Markdown What it tells you
Output token estimate (median) 9,800 3,400 Boilerplate control is working
Boilerplate ratio (median) 0.42 0.18 Main content detection is stable
Table parse success rate 61% 92% Table representation policy is effective
Evidence coverage (sections with spans) 74% 97% Citations can be verified
Retrieval impact (Top-5 recall) 0.58 0.79 Conversion quality correlates with retrieval If your numbers don’t move in the same direction, treat it as a regression signal—not a “maybe it’s fine” situation.
A Simple Evaluation Harness
Run conversion, then score it with a deterministic checklist:
- Does every H2 have a corresponding Markdown heading?
- Are tables parseable into Markdown tables (or CSV fallback)?
- Are code blocks fenced?
- Is boilerplate ratio within expected bounds?
- Does evidence coverage exceed threshold?
If any check fails, mark the conversion as “degraded” and route to fallback.
Harness Output (CLI Example)
Below is an example of what a single harness run can emit. In production, you’d store this alongside the evidence packet so you can debug failures quickly.
eval_run_id=md_contract_2026-07-22_01
pages_tested=40
policy=article_only
render=auto
pass_rate=0.82
degraded_reasons:
- table_truncated: 6
- evidence_coverage_low: 3
- render_timeout: 2
median:
token_estimate=3400
boilerplate_ratio=0.18
table_parse_success=0.92
evidence_coverage=0.97
retrieval:
top5_recall_before=0.58
top5_recall_after=0.79 This is the kind of output that turns “conversion quality” into something you can monitor like latency or error rate.
Evidence Packet Example (JSON)
Here’s a minimal example of an evidence packet for one extracted section. The important part is that each Markdown section is tied to a source span so citations are verifiable.
{
"source_url": "https://example.com/docs/ai-ingestion",
"sections": [
{
"title": "What an LLM-Ready Markdown Contract Is",
"content_type": "paragraph",
"start_byte_offset": 18432,
"end_byte_offset": 21290,
"excerpt": "An LLM-ready Markdown contract is a set of rules..."
},
{
"title": "API Contract Specification",
"content_type": "list",
"start_byte_offset": 26010,
"end_byte_offset": 30177,
"excerpt": "Request: url, render, max_output_tokens..."
}
],
"metadata": {
"token_estimate": 3400,
"boilerplate_ratio": 0.18,
"extraction_confidence": 0.91
}
} Golden-Set Micro Case Study (Before/After)
One of the fastest ways to validate an ingestion contract is to pick a small set of pages where structure matters (tables, code, and headings). Here’s a micro case study pattern you can replicate.
Input page type
A documentation page with a “Parameters” table and a “Example request” code block.
What changed with the contract
- The table was emitted as a Markdown table with a header row.
- The code block was emitted as a fenced block with a language hint.
- Evidence spans were attached per section so citations could be verified.
What improved downstream
- Retrieval stopped returning navigation fragments and started returning the “Parameters” section.
- The answer generator stopped paraphrasing table rows incorrectly because the row/column structure was preserved.
This is the practical reason to treat conversion as a contract: it changes the shape of the context your model sees.
Golden Set Dataset (How to Build It)
A golden set is small enough to run often, but diverse enough to catch regressions. Build it like this:
First, pick 10–20 URLs per site template category (docs, blogs, changelogs, Q&A). Then, for each category, include at least one page that contains a table, one page that contains code blocks, and one page that is known to be “noisy” (heavy navigation or long footers). Finally, store the expected contract outcomes: which headings should appear, whether tables should parse, and whether evidence coverage should be near-complete.
Once you have the golden set, run your harness after every converter change and after any site redesign. If the contract metrics drift, you’ll catch it before it becomes a retrieval-quality incident.
11. Security Considerations
HTML→Markdown conversion is a data ingestion step, so treat it like untrusted input.
Key risks:
- Prompt injection via page content (e.g., “ignore previous instructions”)
- Data exfiltration via malicious links or embedded resources
- SSRF-like behavior if your fetch layer is not constrained
- Sensitive content leakage (account pages, private docs)
Mitigations:
- Enforce URL allowlists and block private IP ranges.
- Disable or sandbox resource fetching beyond what you need.
- Redact or exclude login/account sections.
- Store evidence and metadata for audit.
- Apply content filtering before passing to LLMs.
If you’re using agent tool calls, combine this with a policy gate that validates tool inputs and logs allow/deny decisions.
Security Contract Add-On (Recommended)
For LLM ingestion pipelines, add a second contract layer that governs what the converter is allowed to fetch and represent.
- URL allowlist: only public domains you intend to ingest.
- Private network deny: block RFC1918 and link-local ranges.
- Resource limits: cap HTML size, render time, and number of requests.
- Content redaction: remove login/account sections and forms.
- Evidence retention policy: store evidence packets with the same retention rules as the extracted content.
Lab Run Log (Security + Conversion)
When you debug ingestion failures, you want a single timeline that ties together policy decisions and conversion output.
run_id=md_contract_sec_2026-07-22_02
url=https://example.com/docs/ai-ingestion
policy_gate=article_only
fetch_mode=rendered
allowlist_check=pass
private_network_check=pass
redaction=login/account removed
conversion_warnings:
- table_truncated=false
- render_timeout=false
evidence:
sections_total=6
sections_with_spans=6
evidence_coverage=1.00 12. Troubleshooting
“The Markdown is short and missing sections”
Likely causes:
- main content detection failed
- render timed out
- content policy is too strict
Fix:
- retry with a different content_policy
- increase render timeout
- lower strictness thresholds for main content detection
“Tables look wrong or flattened”
Likely causes:
- table parsing failed due to complex markup
- header detection ambiguous
Fix:
- switch table_mode to csv_fallback
- add a table parse success threshold and retry
“Citations don’t verify”
Likely causes:
- evidence mapping disabled
- evidence spans not aligned with Markdown sections
Fix:
- ensure evidence=true
- validate evidence coverage in your pipeline
Troubleshooting Decision Tree (Operational)
When conversion quality degrades, you want deterministic routing—not guesswork.
flowchart TD
A[Conversion received] --> B{evidence_coverage >= threshold?}
B -- No --> C[Fallback: re-run with evidence=true + stricter content_policy]
B -- Yes --> D{table_parse_success >= threshold?}
D -- No --> E[Fallback: switch table_mode to csv_fallback]
D -- Yes --> F{boilerplate_ratio <= threshold?}
F -- No --> G[Fallback: tighten content_policy + remove known boilerplate patterns]
F -- Yes --> H{extraction_confidence >= threshold?}
H -- No --> I[Fallback: enable render=true (if allowed) and retry once]
H -- Yes --> J[Accept Markdown and proceed to chunking] This decision tree is intentionally conservative: it avoids infinite retries and keeps each retry aligned with a specific failure mode.
13. Best Practices
Treat HTML→Markdown conversion like an ingestion pipeline, not a formatting utility. The fastest way to keep retrieval stable is to make outputs reproducible: cache by (url, render, policy, contract_version, converter_version) so the same input under the same rules produces the same Markdown. When you do this, you can diff changes confidently and you can correlate retrieval regressions with a specific converter or policy update instead of guessing.
Next, monitor the contract metrics continuously. Boilerplate ratio tells you whether your “main content” detection is drifting; extraction confidence tells you whether the converter is uncertain; table parse success rate tells you whether structured content is being represented correctly; and evidence coverage tells you whether citations remain verifiable. If you only watch the final Markdown, you’ll miss the early warning signals that show up in metadata first.
Finally, use evidence coverage as a gating metric whenever citations or auditability matter. A pipeline that returns readable Markdown but lacks evidence spans is effectively untrustworthy for regulated or high-stakes workflows. In practice, you should route conversions with low evidence coverage to fallback or re-run them with safer settings, rather than letting degraded outputs silently propagate into chunking and retrieval.
A practical “contract checklist”
When you ship a converter update, run a small deterministic checklist on your golden set. Verify that headings preserve hierarchy, lists keep nesting intact, tables either render as Markdown tables or fall back consistently, and code blocks remain fenced. Also confirm that every extracted section has evidence spans (or that warnings explain why evidence is missing) and that metadata fields like token estimate and boilerplate ratio are present and within expected ranges.
14. Common Mistakes
The most common mistake is assuming that “Markdown exists” means it’s LLM-ready. A converter can remove tags and still produce output that breaks downstream behavior: headings can be missing or reordered, tables can be flattened into ambiguous text, code blocks can lose fences, and boilerplate can dominate the token budget. The model then receives context that looks readable but behaves unpredictably under chunking and retrieval.
Another frequent failure is treating tables and code blocks as edge cases. In technical pages, those structures often contain the exact parameters, constraints, and examples that users care about. If your converter mishandles them, retrieval may still return something relevant-looking, but the answer will be subtly wrong because the structure that carries meaning was lost.
Teams also often skip metadata and then wonder why they can’t debug quality issues. Without token estimates, boilerplate ratio, extraction confidence, warnings, and evidence coverage, downstream systems have to guess whether the conversion is acceptable. That leads to brittle pipelines and slow incident response.
Finally, retries are frequently misused. Retrying blindly without changing the policy, table mode, or render mode usually produces the same degraded output again. Retries should be deterministic and tied to a specific failure mode—table parsing, evidence gaps, or main-content detection—so each retry actually changes the outcome.
What to log when something degrades
When conversion quality drops, log the decision trail, not just the final Markdown. You want to capture which policy gate ran, what warnings were produced, and what evidence coverage looked like. That’s what turns debugging from “read the Markdown and guess” into a fast, evidence-backed diagnosis.
15. Alternatives & Comparison
When you compare approaches, don’t just ask “does it produce Markdown?” Ask whether the output is stable under chunking, whether structure survives, and whether you can explain (and reproduce) why a given page produced a given answer.
Below are the most common alternatives you’ll see in production ingestion stacks, and how they behave when you care about retrieval quality, citations, and operational debugging.
Raw HTML + Text Splitters
This approach feeds raw HTML (or lightly cleaned HTML) into a splitter that tries to chunk by length, headings, or heuristics.
Pros: it’s quick to prototype, and you can often get something “working” without building a full conversion layer.
Cons: HTML is noisy for LLM pipelines. Navigation, repeated UI elements, and hidden markup inflate token budgets. More importantly, splitters operate on text they can’t reliably interpret as structure, so chunk boundaries drift as the site changes. Citations are also hard: if you never normalize structure into a predictable representation, mapping an answer span back to a stable source region becomes guesswork.
Use this only for early exploration, not for systems that must be auditable.
HTML→Plain Text Converters
Plain-text conversion strips tags and tries to keep readable paragraphs.
Pros: it’s fast and cheap. For pages where the “meaning” is mostly in prose, it can be good enough.
Cons: plain text collapses structure. Tables become flattened sequences, code blocks lose fences or language hints, and lists lose nesting. That matters because LLM retrieval is sensitive to how information is grouped. If your converter can’t preserve structure, your chunker can’t reliably keep related facts together, and your model may answer with incomplete or misinterpreted parameters.
Use this when you explicitly accept that structured content (tables/code) will be degraded and you have a fallback strategy.
DOM-to-Markdown with No Contract
DOM-to-Markdown tools often produce attractive output: headings look right, lists are present, and tables may render.
Pros: it can look good in a quick manual review.
Cons: without a contract, output quality is not measurable. Two runs can differ after a minor site change, a rendering tweak, or a converter update. That drift breaks downstream assumptions: chunking strategies that worked yesterday may stop working today. You also lose the ability to gate ingestion. If you can’t compute boilerplate ratio, extraction confidence, or evidence coverage, you can’t reliably decide whether to accept, retry, or fall back.
This is the “it works until it doesn’t” option: it often fails silently.
Contract-Driven HTML→Markdown API (Recommended)
A contract-driven API treats conversion as an engineering component with explicit guarantees.
Pros: deterministic structure rules (headings/lists/tables/code), controlled boilerplate behavior, and quality signals that let your pipeline make decisions. Evidence packets make citations verifiable and debugging fast. Most importantly, you can evaluate changes with a harness and regression tests, so improvements don’t accidentally degrade retrieval.
Cons: it requires more upfront engineering: you must define representation rules, implement metrics, and maintain contract versioning.
In practice, that upfront cost pays back quickly because you reduce incident time and prevent silent quality regressions.
Pros/Cons (AI Overview Friendly)
Approach | Pros | Cons
Raw HTML + splitter | Fast prototype | High noise, brittle chunking, weak citations
Plain text conversion | Simple and cheap | Loses tables/code structure; weaker grouping
DOM→Markdown without contract | Can look good | Output drift; no measurable acceptance gates
Contract-driven HTML→Markdown | Deterministic structure, quality signals, evidence | More upfront engineering How to choose (decision guidance)
If your use case is “answers must be citeable and explainable,” you should default to the contract-driven approach because it supports evidence mapping and gating.
If your use case is “fast indexing for low-stakes search,” plain text may be acceptable, but you should still add minimal quality signals (token estimate, boilerplate ratio, and table/code detection) so you can detect when the converter starts failing.
If you’re tempted by raw HTML + splitters, treat it as a temporary scaffold. The moment you need stable chunk boundaries, consistent structure, or reliable citations, you’ll end up rebuilding a conversion layer anyway.
What “better” means in measurable terms
To avoid subjective debates, define success metrics that reflect downstream behavior:
- Structural fidelity: headings hierarchy preserved; lists nesting intact; tables parseable; code fenced.
- Boilerplate control: boilerplate ratio stays within a stable band for your content type.
- Evidence coverage: extracted sections have traceable spans back to the source.
- Retrieval impact: conversion quality correlates with answer correctness on a golden set.
When you compare alternatives using these metrics, the contract-driven approach is usually the only one that gives you stable, testable improvements over time.
16. Enterprise / Cloud Deployment
For enterprise ingestion, plan for:
- multi-tenant isolation (separate caches and storage)
- audit logs (request, policy decisions, evidence)
- retention controls for evidence packets
- regional data handling and encryption at rest
- rate limiting and backpressure
In cloud deployments, run conversion workers behind a queue so you can scale rendering and extraction independently.
Observability you should not skip
For enterprise ingestion, log at least:
- request identifiers (correlation IDs)
- policy decisions (allow/deny, content_policy used)
- conversion warnings (render_timeout, table_truncated)
- evidence coverage metrics
This makes it possible to answer: “Why did this page degrade?” without re-running the conversion.
Backpressure and cost controls
Conversion can be expensive when rendering is enabled. Use:
- rate limits per tenant
- concurrency caps for render workers
- max HTML size and max output token caps
Then route degraded pages to cheaper modes (static extraction) when possible.
17. FAQs
1. What’s the difference between “HTML to Markdown” and “HTML to AI-ready Markdown”?
HTML to Markdown is usually treated as a formatting step: remove tags, keep readable text, and output something that looks clean. HTML to AI-ready Markdown is different because it’s designed for downstream model behavior. It preserves the structure that LLM pipelines rely on (headings, lists, tables, code blocks), controls boilerplate so the model doesn’t waste attention on navigation or footers, and returns quality signals plus evidence so you can verify what was extracted.
2. Do I need JS rendering for every page?
No. Many documentation and blog pages are server-rendered, meaning the HTML you fetch already contains the content you need. JS rendering is useful when the page content is generated client-side (for example, single-page apps or pages that load the main article after hydration).
3. How do I prevent the model from following malicious instructions in page content?
Treat page content as untrusted input. Even if you’re not directly “prompting” the model with the page as instructions, the content can still contain text that looks like instructions (prompt injection).
4. What should I do when tables are complex?
Complex tables are where many converters fail silently: they flatten the table into paragraphs, drop headers, or produce malformed Markdown that downstream chunkers can’t interpret. The contract approach is to define a table policy up front. Prefer deterministic Markdown tables when the markup is parseable, but if parsing fails or the table parse success rate drops below threshold, switch to a fallback representation like CSV.
5. How do evidence packets help in practice?
Evidence packets make the conversion process debuggable and auditable. Without evidence, you can’t reliably answer “why did the model cite the wrong part?” or “did we actually extract the section we think we extracted?” With evidence packets, each extracted Markdown section is tied to source spans (for example, byte offsets or DOM references).
6. Can I evaluate conversion quality automatically?
Yes, and you should. The contract approach is built around measurable acceptance criteria. You can run a deterministic evaluation harness that checks structural fidelity (for example, headings exist and are ordered), representation correctness (tables parse into Markdown tables or CSV fallback), formatting requirements (code blocks are fenced), and quality metrics (boilerplate ratio within bounds, extraction confidence above threshold, evidence coverage above threshold).
7. What’s a good boilerplate ratio threshold?
There isn’t one universal threshold because boilerplate varies by site template and content type. The practical method is to establish a baseline from your current pipeline and then set thresholds that catch regressions. For example, if your article-only policy typically yields a boilerplate ratio around 0.15–0.25, you can set an acceptance threshold at 0.25 and treat anything above it as degraded extraction.
8. How do I keep output stable over time?
Stability comes from versioning and deterministic formatting rules. Version your converter and your contract separately so you can understand what changed when metrics drift. Cache conversion results by (url, render, policy, contract_version, converter_version) so repeated runs produce consistent outputs. Then run regression tests on a golden set of pages after every converter update and after major site redesigns.
9. Is Markdown always the best intermediate format?
Markdown is often a strong default because it preserves structure in a compact, readable way: headings map naturally to sections, lists preserve hierarchy, and tables can be represented in a way that many LLM pipelines can parse. However, the contract concept applies to other formats too. The real requirement is deterministic structure and measurable quality signals, not Markdown specifically.
10. What about paywalled or restricted pages?
For restricted content, enforce access controls at fetch time. If you can’t legally or technically access the content, the correct behavior is to return a clear error and avoid partial extraction that could leak sensitive information. The contract should include a policy outcome for restricted pages (for example, access_denied with no evidence spans).
11. How do I handle very long pages?
Very long pages can exceed token budgets and increase the chance that relevant content is buried in noise. The contract approach is to use max_output_tokens and consider section-level extraction rather than converting the entire page blindly. Prioritize main content sections based on your content policy, and preserve evidence for the extracted subset so citations remain verifiable.
12. What’s the fastest way to improve retrieval after conversion?
Start with the highest-leverage structural issues: headings, tables, and code blocks. Retrieval quality often improves dramatically when the converter preserves the document’s semantic structure and removes boilerplate that pollutes embeddings. Then validate with end-to-end retrieval metrics rather than relying on Markdown appearance.
13. How do I know the contract is “working” after a site redesign?
Site redesigns are exactly when contracts earn their keep. After a redesign, you should expect extraction behavior to drift: navigation changes, footer structure changes, and sometimes the main content detection logic needs adjustment. The way you detect this early is by tracking contract metrics on your golden set: boilerplate ratio, table parse success rate, extraction confidence, and evidence coverage.
18. References
- Liu et al., “Lost in the Middle: How Language Models Use Long Contexts” (2023)
- General RAG evaluation literature on chunking and retrieval sensitivity
Additional reading:
- Ollagraph MCP toolchain: scrape → extract → convert web data
- MCP evidence packets and retry decision trees
19. Conclusion
HTML→Markdown conversion is not a cosmetic step. In an LLM pipeline, it’s an ingestion component that directly shapes what the model can “see,” how it chunks the document, and what it can cite later. If the conversion is inconsistent, your downstream system doesn’t just get slightly worse—it becomes unpredictable. Tables flatten, code loses fences, headings drift, and boilerplate sneaks into embeddings. The result is wasted tokens, weaker retrieval, and answers that are harder to verify because you can’t reliably map what the model used back to the original page.
That’s why the contract approach matters. When you define an API contract—structural fidelity rules, boilerplate control, quality signals, and evidence packets—you turn conversion into something you can operate like an engineering system, not a best-effort transformation. Structural fidelity ensures the document’s meaning survives representation changes. Boilerplate control protects your token budget and prevents navigation/footer noise from dominating retrieval. Quality signals let your pipeline decide whether the output is acceptable or degraded. Evidence packets make citations verifiable and debugging fast, because every extracted section can be traced back to a source span.
The practical payoff is straightforward: less noise in the context window, higher retrieval accuracy, and faster incident response when the web changes. Instead of guessing why an answer drifted, you can inspect contract metrics, review warnings, and confirm evidence coverage. In other words, you don’t just improve conversion quality—you improve the reliability of the entire RAG or agent workflow built on top of it.