HTML to Markdown Converter - URL or HTML to GFM avatar

HTML to Markdown Converter - URL or HTML to GFM

Pricing

from $1.20 / 1,000 converted pages

Go to Apify Store
HTML to Markdown Converter - URL or HTML to GFM

HTML to Markdown Converter - URL or HTML to GFM

Convert a page (by URL) or raw HTML to clean GitHub-Flavored Markdown - headings, links, fenced code, tables, strikethrough. Single, bulk, or inline HTML. $0.0015 per page no start fee, cheaper than paid converters; failed fetches free.

Pricing

from $1.20 / 1,000 converted pages

Rating

0.0

(0)

Developer

Broke to Built

Broke to Built

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

8 days ago

Last modified

Share

HTML to Markdown Converter - URL or Raw HTML to Clean GitHub-Flavored Markdown

Send a page URL (or raw HTML), get it back as clean Markdown with links made absolute, plus the page title.

You give itYou get backYou pay (Free plan)
One page URL, a list of up to 50, or raw HTML with a base URLPer page: title and the Markdown$0.0015 per page

Pay per result only: no subscription, no start fee. A failed fetch returns an error instead of Markdown and is not charged. Paid Apify plans get Store discounts on the price above.

Try it in one click

The input form is already filled in with this example. Press Start and you get the output below.

{
"url": "https://info.cern.ch/hypertext/WWW/TheProject.html"
}

Real output from that exact input (run on 2026-09-24; long arrays shortened to a few entries and long text cut for display):

[
{
"ok": true,
"url": "https://info.cern.ch/hypertext/WWW/TheProject.html",
"title": "The World Wide Web project",
"markdown": "The World Wide Web project\n\n# World Wide Web\n\nThe WorldWideWeb (W3) is a wide-area [hypermedia](https://info.cern.ch/hyp…",
"length": 2435
}
]

Give it a URL or an HTML string, get clean GitHub-Flavored Markdown back - real code fences with language hints, real GFM tables, strikethrough, and links, with the scripts, styles and hidden elements stripped out. Single page, bulk list, or inline HTML. $0.0015 per page, no start fee. Failed fetches are recorded free.

Feeding pages to an LLM is the common case: Markdown carries the same structure as HTML at a fraction of the tokens. Docs migration, turning a knowledge base into a RAG corpus, and archiving articles as text all want the same thing.

What you get

Per page or HTML string, one record with these exact fields:

  • ok - true when the conversion produced Markdown
  • url - the final URL after redirects (null when you passed raw HTML with no baseUrl)
  • title - the page's <title>, when it has one
  • markdown - the converted document
  • length - character length of the Markdown
  • error - present instead of markdown when the fetch failed. Never charged.

Conversion specifics that matter in practice:

  • ATX headings (#), - bullets, inlined links, **bold**, *italic*, ~~strikethrough~~
  • Fenced code blocks, with the language taken from class="language-js", lang-js or highlight-js
  • <table> rebuilt as a GFM pipe table, with | inside cells escaped
  • <script>, <style>, <noscript>, <iframe>, <svg>, <link>, <meta> and elements hidden via display:none or hidden are removed before conversion
  • Only <body> is converted, so head metadata never leaks into the text
  • Relative links and images are rewritten to absolute URLs using the page URL (or baseUrl for raw HTML)

Example 1: raw HTML, showing what survives conversion

Input:

{
"html": "<html><head><title>Release notes</title></head><body><h1>v2.1</h1><p>Ships <del>beta</del> <strong>stable</strong> support.</p><pre><code class=\"language-js\">const x = 1;</code></pre><table><tr><th>Flag</th><th>Default</th></tr><tr><td>retry</td><td>3</td></tr></table><script>alert(1)</script></body></html>"
}

Output (real run, 2026-08-15):

{
"ok": true,
"url": null,
"title": "Release notes",
"markdown": "# v2.1\n\nShips ~~beta~~ **stable** support.\n\n```js\nconst x = 1;\n```\n\n| Flag | Default |\n| --- | --- |\n| retry | 3 |",
"length": 114
}

The <script> is gone, the <del> became ~~beta~~, the code block kept its js language hint, the table is valid GFM, and the <title> was captured separately instead of being dumped into the text.

Example 2: one live page

Input:

{ "url": "https://example.com" }

Output (real run, 2026-08-15):

{
"ok": true,
"url": "https://example.com/",
"title": "Example Domain",
"markdown": "# Example Domain\n\nThis domain is for use in documentation examples without needing permission. Avoid use in operations.\n\n[Learn more](https://iana.org/domains/example)",
"length": 167
}

Note url is the URL after redirects. Any relative link on a page (/docs/install) is rewritten against that final URL, so the Markdown still resolves when you store it somewhere else.

Example 3: bulk, for a docs migration

Input:

{
"urls": [
"https://example.com/docs/intro",
"https://example.com/docs/install",
"https://example.com/docs/api"
],
"maxUrls": 200
}

One record per URL, each charged once. A URL that 404s becomes {"ok": false, "error": "HTTP 404"} and is not charged. When urls is filled, the single url field is ignored - you are charged for the pages you listed and nothing else.

Pricing

$0.0015 per page converted. No start fee. One event covers one page fetched and converted, or one raw HTML string converted, including the title extraction. A failed fetch (DNS failure, timeout, 4xx, 5xx) is recorded and never charged.

Honest comparison, prices read from the Apify Store API on 2026-08-07:

ActorPricingCost of one page
This actor$0.0015 per page, no start fee$0.0015
shoebill-dev27/html-to-markdown$0.005 start + $0.002 per item$0.007
scrapeworks/pandoc-document-converter$0.00005 start + $0.005 per result$0.005

Those are single-page costs. On a 500-page docs migration the start fee amortizes, so the honest comparison there is per-item: $0.0015 against $0.002 and $0.005.

When NOT to use this

  • JavaScript-rendered pages. This fetches server HTML. If the content only exists after the page runs its scripts (most single-page apps, infinite-scroll feeds), you will get the shell, not the article. Render it yourself with a browser actor and pass the result in as html.
  • Pages behind a login or a bot wall. Requests are plain unauthenticated GETs with a normal User-Agent. There is no proxy rotation, no cookie jar, no CAPTCHA handling.
  • PDFs, Word documents, or images. This is an HTML converter. Use a PDF text extractor for those.
  • Pixel-faithful layout. Deeply nested tables and CSS grid layouts are flattened into valid Markdown, which is a lossy target by design.
  • A single page, once, by hand. Browser extensions do that for free. This is worth paying for in a pipeline, across many pages, or as a tool an agent can call.

Honest limits

  • Server-side HTML only, as above. 20 second fetch timeout per page.
  • Up to 200 pages per run (maxUrls, default 50).
  • Nested tables are simplified; a table inside a table cell will not round-trip.
  • Raw HTML mode takes priority: if you pass html, no URL is fetched in that run. Pass baseUrl when you want relative links inside that HTML resolved to absolute ones.

FAQ

How do I convert a web page to Markdown for an LLM or RAG pipeline? Send {"url": "https://..."} and use the markdown field. It typically costs a fraction of the tokens the raw HTML would, and it keeps the headings, lists and tables that chunking relies on.

Can I pass HTML I already fetched or rendered myself? Yes, that is the html field, and it is the recommended path for JavaScript-heavy sites: render the page with your own browser or a browser actor, then send the DOM here. Add baseUrl so relative links resolve.

Does it keep code blocks and their language? Yes. <pre><code class="language-js"> becomes a fenced block tagged js. Common class conventions (language-, lang-, highlight-) are all recognized.

Are HTML tables converted to Markdown tables? Yes, as GFM pipe tables, with a header separator row and | characters inside cells escaped so the table does not break. Ragged rows are padded to the widest row.

How many pages can I convert in one run? Up to 200. Put them in urls; each is one record and one charge, and one bad URL does not stop the rest.

Do relative links break when I move the Markdown elsewhere? No. Links and image sources are resolved against the page's final URL (after redirects), so they come out absolute.

Why did a page come back with almost no Markdown? Almost always JavaScript rendering: the server HTML really was near-empty. Check length - if it is tiny for a page you know is long, render it first and pass html.

Use from code or AI agents

curl -s "https://api.apify.com/v2/acts/EliAI~html-to-markdown/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-X POST -H 'Content-Type: application/json' \
-d '{"url":"https://github.com/apify/apify-sdk-js"}'

Agents: connect Apify MCP and call the EliAI/html-to-markdown tool.

  • Capability: convert a page URL, a bulk list of URLs, or a raw HTML string into GitHub-Flavored Markdown
  • Required input: url, urls, or html
  • Returns: one record per page; markdown and title are the payload
  • Bounded: 200 pages per run; failures isolate per page
  • Side effects: none beyond fetching the pages you named
  • Markdown to HTML (EliAI/markdown-to-html) - the inverse trip, with a table of contents and sanitized output.

Who uses it

  • RAG developers converting documentation pages to Markdown to cut tokens before embedding
  • Docs teams migrating a legacy HTML knowledge base into a Markdown docs repo
  • Researchers archiving articles as readable text files with links kept
  • Newsletter writers pulling a web article into Markdown to quote and edit it
  • AI agent builders giving an agent a tool that reads a web page as Markdown instead of raw HTML

Changelog

  • 2026-09-24: New summary at the top of this page: what you send, what you get, the price, and a real output from the prefilled example.