100% Local · Free · No Sign-up

Convert HTML to Clean Markdown (GFM)

Convert an .html file or a pasted fragment into clean, GitHub-flavoured Markdown. DOMPurify sanitises the markup first, then Turndown maps semantic HTML5 — article, table, pre, code, blockquote — to CommonMark and GFM, entirely inside your browser.
Drop your HTML file here to convert to MarkdownDrag & drop files here, or click anywhere to browse · .html, .htm

Processing happens 100% in your browser — nothing is uploaded.

Presentation is discarded, and spans cannot be expressed

Inline styles, stylesheets, and class-based layout have no Markdown equivalent and are stripped. Cells spanning rows or columns are emitted as ordinary cells, since GFM pipe tables cannot express spans — merged-header tables need manual repair, and nested tables flatten.
100% Local Processing — Your files never leave your device

How to convert HTML to Markdown

  1. Input: drop an .html or .htm file onto the dropzone, or paste raw markup — a full document or a single fragment both work.
  2. Process: DOMPurify sanitises the markup, then Turndown maps it to GitHub-flavoured Markdown locally in your browser.
  3. Copy: send the Markdown to your clipboard or save it as a .md file.

Why Convert HTML to Markdown with MD Convert?

  • Sanitised before it is converted, never after

    DOMPurify runs first, so scripts, event handlers, and javascript-scheme URLs are gone before Turndown or the preview ever sees the markup. Style and form elements plus every style attribute are explicitly forbidden — you can convert customer-supplied or scraped HTML without executing any of it.

  • GFM tables with pipe escaping and header synthesis

    The first row is promoted to a header and a delimiter row is generated from its cell count, so tables that omit a thead still produce valid GFM. Literal pipes inside cells are escaped and cell newlines collapse, so one value can never split its row and shift your data.

  • Semantic structure in, portable Markdown out

    ATX headings, fenced code blocks with the language lifted from the code element's class, hyphen bullets, nesting blockquotes, inlined links, and hard breaks as two trailing spaces. The output needs no reformatting to travel between GitHub, GitLab, Obsidian, Hugo, and Jekyll.

  • 100% local — your markup never leaves the device

    Both libraries are ordinary browser JavaScript. Nothing is uploaded, nothing is retained, and conversion keeps working with the network disconnected — which is what makes it usable for internal templates and proprietary markup.

HTML to Markdown: Before and After

Semantic HTML5 in, GitHub-Flavored Markdown out. Note the presentational span and the inline style attribute: both are discarded, because Markdown has nowhere to put them.

Input · html
<article>
  <h2>Release notes</h2>
  <p style="color:#c00">Shipped <strong>v2.1</strong> with
    <em>streaming</em> parsers.</p>
  <blockquote><p>Peak memory is now flat.</p></blockquote>
  <table>
    <tr><th>Engine</th><th>Status</th></tr>
    <tr><td>pdf</td><td>stable</td></tr>
    <tr><td>xml</td><td>beta | preview</td></tr>
  </table>
  <pre><code class="language-ts">const md = convert(file);</code></pre>
  <span class="badge">decorative</span>
</article>
Output · Markdown
## Release notes

Shipped **v2.1** with _streaming_ parsers.

> Peak memory is now flat.

| Engine | Status |
| --- | --- |
| pdf | stable |
| xml | beta \| preview |

```ts
const md = convert(file);
```

decorative

Understanding the HTML Format: WHATWG HTML Living Standard

Format
HyperText Markup Language
Media type
text/html

Technical Specifications & HTML5 Mapping Rules

  • Inert Sanitisation Order: DOMPurify executes before Markdown conversion to strip scripts, event handlers, style blocks, and dangerous URL schemes; unsanitised markup never touches the preview DOM.
  • GFM Table Synthesis & Spans: The first row promotes to a header with a synthesised delimiter row; in-cell pipes escape to \|; row/colspans flatten to ordinary cells (GFM tables cannot express merged cells).
  • Presentational & CSS Stripping: Inline styles, stylesheets, and presentational tags (<font>, <span>) are discarded; structural tags map directly to semantic Markdown elements.
  • Code Fencing & Language Classes: Preformatted <code> blocks preserve whitespace byte-for-byte; language classes (e.g., language-typescript) are lifted directly into fenced code-block info strings.
  • Whitespace Collapsing Rules: Runs of whitespace within block elements collapse to single spaces per HTML standards; line breaks require explicit <br> or separate paragraph blocks.

Developer Alternative: CLI (Pandoc), Node.js & Python Extraction

For batch jobs or server-side pipelines, Pandoc, Turndown, and markdownify produce the same kind of Markdown outside the browser.

Bash (Pandoc)
# Convert HTML file directly to GitHub-Flavored Markdown using Pandoc
pandoc -f html -t gfm input.html -o output.md
JavaScript (Turndown)
// Programmatic HTML to Markdown conversion using Node.js & Turndown
import TurndownService from "turndown";

const turndownService = new TurndownService({ headingStyle: "atx", codeBlockStyle: "fenced" });
const markdown = turndownService.turndown("<article><h1>Hello</h1><p>Text</p></article>");
console.log(markdown);
Python (markdownify)
# Programmatic HTML to Markdown conversion using Python markdownify
# requires: pip install markdownify
from markdownify import markdownify as md

markdown_text = md("<article><h1>Hello</h1><p>Text</p></article>", heading_style="ATX")
print(markdown_text)

HTML to Markdown: Comparing the Practical Approaches

MethodPrivacyGFM tablesSanitisationSetupBatch / automationCost
This tool (Turndown + DOMPurify)Highest — markup never leaves the tabYes, with pipe escaping and header synthesisBuilt in, and runs before conversionNone — paste or drop a fileOne document at a timeFree
Pandoc CLIHigh — runs locallyYes, via the gfm writerNone; it converts what you give itLocal installStrong — scriptableFree
Turndown in your own Node scriptHigh — your infrastructureOnly if you add the plugin or rulesOnly if you add a sanitiserCode plus dependenciesStrongFree
Hosted conversion APIsLow — markup is uploaded to a third partyVaries by providerOpaqueAPI keyStrongPer-request
Asking a chat model to convertLow — the markup becomes a promptUsually, but silently reformats contentNot a sanitiserNonePoor at scalePer-token

How You Can Verify the Privacy Claim

Browser-only

Zero server upload

Conversion runs inside your browser tab. Open DevTools, switch to the Network panel, and convert a file: for every format except URL to Markdown you will see no request carrying your document — because there is no endpoint to send it to.

In your tab

Parses on the main thread

Parsing stays inside your browser tab — this format’s parser needs DOM APIs. Nothing is uploaded. Everything is plain JavaScript — no native plugin, no WebAssembly toolchain, nothing to install.

No account

Nothing to sign up for

No login, no quota, no paywall, and no tracking tied to your files. Analytics are cookieless and aggregate only. Read the privacy policy for the full data-flow breakdown, including the one proxied exception.

The parsers doing the work

No proprietary black box: each format is handled by a widely audited open-source library, running client-side at the version pinned in our lockfile.

HTML to Markdown — FAQ

Are HTML tables converted to GFM pipe tables?

Yes. Custom rules emit pipe tables, promote the first row to a header even when the markup has no thead, escape literal pipes inside cells, and pass table sections through so the header and body stay contiguous. Row and column spans cannot be represented and become ordinary cells.

What happens to inline styles and style attributes?

They are removed during sanitisation, along with stylesheet, form, input, and button elements. Markdown has no styling layer, so only semantic structure survives — this is intentional, not a gap.

Is it safe to convert HTML from an untrusted source?

Yes. Sanitisation runs before conversion, not after, so scripts, event handlers, and javascript-scheme links are removed before anything is rendered or converted. Nothing in the input is executed at any stage.

Do code blocks keep their language for syntax highlighting?

Yes. A code element inside a pre becomes a fenced block, and the language is lifted from the conventional language- class name, so markup from a syntax highlighter keeps its tag. A pre with no code element inside is fenced without a language hint.

In-Depth HTML Guides