This site is not affiliated with or endorsed by Cloudflare, Inc. It simply showcases experiments built using Cloudflare services.
Cloudflare Experiments
Web Scraping & Parsing

HTML to Markdown

Convert any webpage HTML into clean Markdown from the edge

Fetch a webpage and convert its HTML into clean Markdown for notes, LLM prompts, and content pipelines - all from Cloudflare's edge.

Features

  • Converts headings, paragraphs, emphasis, links, images, lists, code, and blockquotes
  • Prefers <article> / <main> content when present (falls back to <body>)
  • Resolves relative link and image URLs against the page URL
  • Strips script, style, svg, and similar non-content tags
  • Caps HTML input at 1MB and Markdown output at 200k characters
  • Stateless; no bindings required

API Reference

GET /markdown

Fetches HTML and returns title plus Markdown.

Prop

Type

Example Request

curl "https://your-worker.workers.dev/markdown?url=https://example.com"

Success Response

url string

Final page URL after redirects

title string | null

Document <title> when present

markdown string

Converted Markdown body

{
  "url": "https://example.com/",
  "title": "Example Domain",
  "markdown": "# Example Domain\n\nThis domain is for use in illustrative examples…"
}

Error Response

{
  "error": "Expected HTML, got content-type: application/json",
  "code": "NOT_HTML"
}

Error Codes

  • 400 - Missing or invalid url (INVALID_URL)
  • 400 - Response was not HTML (NOT_HTML)
  • 502 - Fetch failed (FETCH_ERROR)

Use Cases

  • Turn blog posts into Markdown for note-taking apps
  • Prepare page content for LLM prompts without raw HTML noise
  • Build content migration / archival pipelines on Workers
  • Complement readability extraction with a portable text format

Limitations

  • Does not execute JavaScript; client-rendered content is not included
  • Table conversion is not fully structured (tables flatten as block text)
  • Complex nested layouts may produce extra blank lines
  • Conversion is heuristic, not a full HTML5 / CommonMark guarantee

Use in your project

Copy these files into an existing Worker. Prefer Deployment to try the full experiment first. Source: apps/experiments/html-to-markdown.

DependenciesNoneBindingsNonePlatformFetch API
import { FETCH_TIMEOUT_MS, MAX_HTML_BYTES, USER_AGENT } from "../constants/defaults";export type PageFetchResult =  | { ok: true; url: string; html: string }  | { ok: false; code: "FETCH_ERROR" | "NOT_HTML"; error: string };export async function fetchHtml(url: string): Promise<PageFetchResult> {  const controller = new AbortController();  const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT_MS);  try {    const res = await fetch(url, {      method: "GET",      redirect: "follow",      signal: controller.signal,      headers: { "User-Agent": USER_AGENT, Accept: "text/html,*/*" },    });    clearTimeout(timeoutId);    if (!res.ok) {      return { ok: false, code: "FETCH_ERROR", error: `HTTP ${res.status}` };    }    const contentType = res.headers.get("content-type") ?? "";    if (!contentType.includes("text/html") && !contentType.includes("application/xhtml")) {      return {        ok: false,        code: "NOT_HTML",        error: `Expected HTML, got content-type: ${contentType || "unknown"}`,      };    }    const text = await res.text();    return {      ok: true,      url: res.url || url,      html: text.length > MAX_HTML_BYTES ? text.slice(0, MAX_HTML_BYTES) : text,    };  } catch (e) {    clearTimeout(timeoutId);    return {      ok: false,      code: "FETCH_ERROR",      error: e instanceof Error ? e.message : "Unknown error",    };  }}

Deployment

Click the deploy button

Deploy to Cloudflare Workers

Deploy

Follow the deployment wizard. No bindings or secrets required.

Test your deployment

curl "https://your-worker.workers.dev/markdown?url=https://example.com"

Local Development

cd apps/experiments/html-to-markdown
npm install
npm run dev

Test locally:

curl "http://localhost:8787/markdown?url=https://www.cloudflare.com"

Cloudflare Features Used

Next Steps

On this page