HTML to Markdown

Paste HTML source and get GitHub-flavored Markdown back, with the structure kept and stray symbols escaped.

0 characters

Or drop an .html/.txt file onto the box above.

Lists

How to use

  1. Paste HTML into the left box: page source, a CMS export, an email template, the output of a rich-text editor. A fragment is fine; it does not need <html> or <body>.
  2. The Markdown appears on the right as you type. The line under it lists anything that was approximated (a table with no header row, an image with no address).
  3. Pick a Bullet character if your style guide wants * rather than -.
  4. Copy Markdown (or Ctrl+Enter in the input box) or Download .md.

What this converter does with real-world HTML

HTML in the wild is rarely the clean semantic kind. Rich-text editors emit <span style="font-weight:700"> instead of <strong>, CMS exports leave unclosed tags, page source carries scripts, styles and comments, and whitespace is scattered across lines the browser would collapse. This converter parses HTML the tolerant way a browser does, reads inline styles as well as tag names, drops what carries no content, and writes GitHub-flavored Markdown that keeps the structure: headings, lists with their nesting, tables, code with its language, links, images and quotes.

The output is meant to be read back as written, so characters that Markdown would interpret are escaped only where they would be interpreted. It is a converter, not a page cleaner: navigation and footers in a full page are converted along with the article. For text copied from Google Docs, Word or a web page (where the formatting lives on the clipboard, not in source you can see), Google Docs to Markdown runs the same converter on a formatted paste.

Example

Load sample inserts release notes as semantic HTML: 3 headings, a paragraph with <strong>, <em>, <code> and a link, a nested list, a numbered list, a quote, a fenced code block with a language class, a table and an image. It becomes:

## Release notes: v2.4.0

This release adds **scheduled exports** and fixes the *timezone* bug in `report.py`. Full details on the [changelog](https://example.com/changelog).

### Added

- Scheduled exports
  - Daily, weekly or monthly
  - CSV and JSON formats
- Dark mode for the dashboard

### Upgrade

1. Back up the database
2. Run `pip install -U reporter`

> Exports created before 2.4 keep their old schedule.

```bash
reporter export --format csv --schedule weekly
```

| Setting | Default |
| --- | --- |
| `format` | csv |
| `schedule` | none |

![Dashboard in dark mode](https://example.com/dashboard.png)

Options explained

Edge cases and common errors

Do the same thing in code

Shell (pandoc)

pandoc -f html -t gfm --wrap=none page.html -o page.md
curl -s https://example.com/post | pandoc -f html -t gfm --wrap=none

JavaScript (Node.js)

import TurndownService from "turndown";
import { gfm } from "turndown-plugin-gfm";

const td = new TurndownService({ headingStyle: "atx", codeBlockStyle: "fenced" });
td.use(gfm); // tables, strikethrough, task lists
const markdown = td.turndown(html);

Python

from markdownify import markdownify as md
markdown = md(html, heading_style="ATX", bullets="-")

Those libraries read tag names; none of them treats font-weight:700 as bold without a custom rule, which is the difference that matters for editor and Docs output. To go the other way, from Markdown to a formatted document, use Markdown to Google Docs; to remove the formatting entirely, Markdown to Plain Text.

HTML to Markdown FAQ

Which HTML elements are converted?

Headings h1–h6, paragraphs, line breaks, bold and italic (b, strong, i, em, and font-weight or font-style in a style attribute), strikethrough (s, del, line-through), inline code and pre blocks (with a language from a class="language-x"), links, images, ordered and unordered lists with nesting and start numbers, task-list checkboxes, tables with alignment, block quotes and horizontal rules. Everything else (div, span, section, article, font, center) is transparent: its text is kept, the tag is not.

What happens to scripts, styles, comments and broken markup?

script, style, noscript, svg, iframe and template elements are removed with their contents; comments and doctype declarations are dropped. Unclosed tags are closed where a browser would close them (a second

closes the first, a heading closes an open paragraph), stray closing tags are ignored, and attribute quotes may be missing. The output never contains a script even if the input did.

Why are some characters escaped with a backslash?

Because in Markdown they mean something. A literal asterisk would start italics, a square bracket a link, a hash at the start of a line a heading, a hyphen a bullet, “1.” a numbered list. The converter escapes those where they would be misread and leaves them where they would not: an underscore inside snake_case_name stays as it is, a hash in the middle of a sentence too.

Does it convert a whole web page?

It converts whatever HTML you give it, so a full page includes the navigation, sidebars and footer as text and lists. For an article, copy the HTML of the article element only, or paste the rendered page into Google Docs to Markdown, which reads the formatted copy rather than the source. Nothing is fetched by URL: the page has no server to fetch with.

Is the HTML uploaded anywhere?

No. Parsing and conversion run in JavaScript in this page; there is no server. Nothing you paste leaves your browser.

Runs entirely in your browser: this page is a static file with no server behind it, so nothing you paste can be uploaded. Last reviewed by Parthesh Gupta. Implements GitHub Flavored Markdown.