MCPcopy
hub / github.com/JohannesKaufmann/html-to-markdown

github.com/JohannesKaufmann/html-to-markdown @v2.5.2 sqlite

repository ↗ · DeepWiki ↗ · release v2.5.2 ↗
498 symbols 1,811 edges 129 files 73 documented · 15%
README

html-to-markdown

A robust html-to-markdown converter that transforms HTML (even entire websites) into clean, readable Markdown. It supports complex formatting, customizable options, and plugins for full control over the conversion process.

Use the fully extendable Golang library or a quick CLI command. Alternatively, try the Online Demo or REST API to see it in action!

Here are some cool features:

  • Bold & Italic: Supports bold and italic—even within single words.

  • List: Handles ordered and unordered lists with full nesting support.

  • Blockquote: Blockquotes can include other elements, with seamless support for nested quotes.

  • Inline Code & Code Block: Correctly handles backticks and multi-line code blocks, preserving code structure.

  • Link & Image: Properly formats multi-line links, adding escapes for blank lines where needed.

  • Smart Escaping: Escapes special characters only when necessary, to avoid accidental Markdown rendering. 🗒️ ESCAPING.md

  • Remove/Keep HTML: Choose to strip or retain specific HTML tags for ultimate control over output.

  • Plugins: Easily extend with plugins. Or create custom ones to enhance functionality.

  • Table Plugin: Converts tables with support for alignment, rowspan and colspan.


Usage

💻 Golang library | 📦 CLI | ▶️ Hosted Demo | 🌐 Hosted REST API


Golang Library

Installation

go get -u github.com/JohannesKaufmann/html-to-markdown/v2

Or if you want a specific commit add the suffix /v2@commithash

[!NOTE]
This is the documentation for the v2 library. For the old version switch to the "v1" branch.

Usage

Go V2 Reference

package main

import (
    "fmt"
    "log"

    htmltomarkdown "github.com/JohannesKaufmann/html-to-markdown/v2"
)

func main() {
    input := `<strong>Bold Text</strong>`

    markdown, err := htmltomarkdown.ConvertString(input)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(markdown)
    // Output: **Bold Text**
}

Use WithDomain to convert relative links to absolute links:

package main

import (
    "fmt"
    "log"

    htmltomarkdown "github.com/JohannesKaufmann/html-to-markdown/v2"
    "github.com/JohannesKaufmann/html-to-markdown/v2/converter"
)

func main() {
    input := `<img src="https://github.com/JohannesKaufmann/html-to-markdown/raw/v2.5.2/assets/image.png" />`

    markdown, err := htmltomarkdown.ConvertString(
        input,
        converter.WithDomain("https://example.com"),
    )
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(markdown)
    // Output: ![](https://example.com/assets/image.png)
}

The function htmltomarkdown.ConvertString() is a small wrapper around converter.NewConverter() and the base and commonmark plugins. If you want more control, use the following:

package main

import (
    "fmt"
    "log"

    "github.com/JohannesKaufmann/html-to-markdown/v2/converter"
    "github.com/JohannesKaufmann/html-to-markdown/v2/plugin/base"
    "github.com/JohannesKaufmann/html-to-markdown/v2/plugin/commonmark"
)

func main() {
    input := `<strong>Bold Text</strong>`

    conv := converter.NewConverter(
        converter.WithPlugins(
            base.NewBasePlugin(),
            commonmark.NewCommonmarkPlugin(
                commonmark.WithStrongDelimiter("__"),
                // ...additional configurations for the plugin
            ),

            // ...additional plugins (e.g. table)
        ),
    )

    markdown, err := conv.ConvertString(input)
    if err != nil {
        log.Fatal(err)
    }
    fmt.Println(markdown)
    // Output: __Bold Text__
}

[!NOTE]
If you use NewConverter directly make sure to also register the commonmark and base plugin.


Collapse & Tag Type

You can specify how different HTML tags should be handled during conversion.

  • Tag Types: When collapsing whitespace it is useful to know if a node is block or inline.
  • So if you have Web Components/Custom Elements remember to register the type using TagType or RendererFor.
  • Additionally, you can remove tags completely from the output.
  • Pre-built Renderers: There are several pre-built renderers available. For example:
  • RenderAsHTML will render the node (including children) as HTML.
  • RenderAsHTMLWrapper will render the node as HTML and render the children as markdown.

[!NOTE]
By default, some tags are automatically removed (e.g. <style>). You can override existing configuration by using a different priority. For example, you could keep <style> tags by registering them with PriorityEarly.

Here are the examples for the screenshot above:

conv.Register.TagType("nav", converter.TagTypeRemove, converter.PriorityStandard)

conv.Register.RendererFor("b", converter.TagTypeInline, base.RenderAsHTML, converter.PriorityEarly)

conv.Register.RendererFor("article", converter.TagTypeBlock, base.RenderAsHTMLWrapper, converter.PriorityStandard)

Plugins

Published Plugins

These are the plugins located in the plugin folder:

Name Description
Base Implements basic shared functionality (e.g. removing nodes)
Commonmark Implements Markdown according to the Commonmark Spec
GitHubFlavored planned
TaskListItems planned
Strikethrough Converts <strike>, <s>, and <del> to the ~~ syntax.
Table Implements Tables according to the GitHub Flavored Markdown Spec
VimeoEmbed planned
YoutubeEmbed planned
ConfluenceCodeBlock planned
ConfluenceAttachments planned

[!NOTE]
Not all the plugins from v1 are already ported to v2. These will soon be implemented...

These are the plugins in other repositories:

Name Description
[Plugin Name](Your Link) A short description

Writing Plugins

You want to write custom logic?

  1. Write your logic and register it.

- 🧑‍💻 Example code, register

  1. Optional: Package your logic into a plugin and publish it.
  2. 🗒️ WRITING_PLUGINS.md


CLI - Using it on the command line

Using the Golang library provides the most customization, while the CLI is the simplest way to get started.

Installation

Homebrew Tap

brew install JohannesKaufmann/tap/html2markdown

Debian

A deb package is available. See the Setup Instructions.

Note: Support for other Linux distributions is tracked in #119

Pre-compiled Binaries

Download pre-compiled binaries for Linux, macOS or Windows from the releases page. Extract the archive and copy the executable to a location in your system PATH (e.g. /usr/local/bin).

Installation via Go

If you have Go installed, you can install the CLI directly using:

go install github.com/JohannesKaufmann/html-to-markdown/v2/cli/html2markdown@latest

This will download the source code and compile it into an executable in your Go binary directory (typically $GOPATH/bin).

Build from Source

Binaries are automatically built via GoReleaser and attached to each release.

To build locally (requires Go):

go build ./cli/html2markdown

Version

html2markdown --version

[!NOTE]
Make sure that --version prints 2.X.X as there is a different CLI for V2 of the converter.

Usage

$ echo "<strong>important</strong>" | html2markdown

**important**
$ curl --no-progress-meter http://example.com | html2markdown

# Example Domain

This domain is for use in illustrative examples in documents. You may use this domain in literature without prior coordination or asking for permission.

[More information...](https://www.iana.org/domains/example)
$ html2markdown --input file.html --output file.md

$ html2markdown --input "src/*.html" --output "dist/"

Use --help to learn about the configurations, for example:

  • --domain="https://example.com" to convert relative links to absolute links.
  • --exclude-selector=".ad" to exclude the html elements with class="ad" from the conversion.
  • --include-selector="article" to only include the <article> html elements in the conversion.
  • --plugin-strikethrough or --plugin-table to enable plugins.

(The cli does not support every option yet. Over time more customization will be added)



FAQ

Character Encoding

Regardless of which method you use (ConvertString(), ConvertNode(), etc.), the input is expected to already be UTF-8 encoded. Under the hood, Go's html.Parse() is used to build the DOM and it requires UTF-8. It does not detect or convert other charsets.

If your HTML uses a different charset (e.g. ISO-8859-1, Windows-1252), the replacement character may appear in the output instead of the correct letters.

This library does not handle charset detection or conversion. It is your responsibility to decode the HTML to UTF-8 before passing it in. When fetching HTML over HTTP, the Content-Type header tells you the charset. When reading from a file, you may need to detect it from <meta> tags or by inspecting the bytes. The golang.org/x/net/html/charset package can help with these cases.

Extending with Plugins

  • Need your own logic? Write your own code and then register it.
  • Don't like the defaults that the library uses? You can use PriorityEarly to run you logic earlier than others.

  • 🧑‍💻 Example code, register

  • If you believe that you logic could also benefit others, you can package it up into a plugin.

  • 🗒️ WRITING_PLUGINS.md

Bugs

You found a bug?

Open an issue with the HTML snippet that does not produce the expected results. Please, please, plase submit the HTML snippet that caused the problem. Otherwise it is very difficult to reproduce and fix...

Security

This library produces markdown that is readable and can be changed by humans.

Once you convert this markdown back to HTML (e.g. using goldmark or blackfriday) you need to be careful of malicious content.

This library does NOT sanitize untrusted content. Use an HTML sanitizer such as bluemonday before displaying the HTML in the browser.

🗒️ SECURITY.md if you find a security vulnerability

Goroutines

You can use the Converter from (multiple) goroutines. Internally a mutex is used & there is a test to verify that behaviour.

Escaping & Backslash

Some characters have a special meaning in markdown (e.g. "*" for emphasis). The backslash \ character is used to "escape" those characters. That is perfectly safe and won't be displayed in the final render.

🗒️ ESCAPING.md

Contributing

You want to contribute? Thats great to hear! There are many ways to help:

Helping to answer questions, triaging issues, writing documentation, writing code, ...

If you want to make a code change: Please first discuss the change you wish to make, by opening an issue. I'm also happy to guide you to where a change is most likely needed.

Extension points exported contracts — how you extend this code

Plugin (Interface)
Plugin can be used to extends functionality beyond what is offered by commonmark. [4 implementers]
converter/plugin.go
Printer (Interface)
(no doc) [3 implementers]
cli/html2markdown/cmd/print.go
Context (Interface)
- - - - - - // Context extends the normal context.Context with some additional methods useful for the process of convert [1 …
converter/ctx.go
HandlePreRenderFunc (FuncType)
- - - - - - - - - - - - - Pre-Render - - - - - - - - - - - - - //
converter/register.go
ConvertFunc (FuncType)
(no doc)
internal/tester/round_trip.go
ConvertOptionFunc (FuncType)
(no doc)
converter/convert.go
ReadWriterWithStat (Interface)
(no doc) [1 implementers]
cli/html2markdown/cmd/util_pipe.go
AssembleAbsoluteURLFunc (FuncType)
- - - - - - - - - - - - - - - - - - - - - //
converter/ctx.go

Core symbols most depended-on inside this repo

WriteString
called by 66
converter/register.go
Error
called by 59
cli/html2markdown/cmd/errors.go
ConvertString
called by 34
converter/convert.go
WriteRune
called by 34
converter/register.go
NewConverter
called by 34
converter/converter.go
Write
called by 31
converter/register.go
WithPlugins
called by 29
converter/plugin.go
NewBasePlugin
called by 28
plugin/base/base.go

Shape

Function 299
Method 140
Struct 29
FuncType 13
TypeAlias 12
Interface 5

Languages

Go100%

Modules by API surface

converter/ctx.go35 symbols
converter/register.go28 symbols
plugin/table/table.go18 symbols
cli/html2markdown/cmd/exec_test.go17 symbols
plugin/commonmark/commonmark.go15 symbols
cli/html2markdown/cmd/files_test.go15 symbols
plugin/strikethrough/strikethrough.go12 symbols
plugin/table/utils.go11 symbols
plugin/table/2_collect.go11 symbols
cli/html2markdown/cmd/print.go11 symbols
plugin/commonmark/handle_pre_render.go10 symbols
plugin/base/base.go9 symbols

Dependencies from manifests, versioned

github.com/JohannesKaufmann/domv0.3.1 · 1×
github.com/agnivade/levenshteinv1.2.1 · 1×
github.com/andybalholm/cascadiav1.3.4 · 1×
github.com/aymanbagabas/go-osc52/v2v2.0.1 · 1×
github.com/bmatcuk/doublestar/v4v4.10.0 · 1×
github.com/lucasb-eyer/go-colorfulv1.4.0 · 1×
github.com/mattn/go-isattyv0.0.22 · 1×
github.com/muesli/termenvv0.16.0 · 1×
github.com/pmezard/go-difflibv1.0.0 · 1×
github.com/rivo/unisegv0.4.7 · 1×
github.com/sebdah/goldie/v2v2.8.0 · 1×
github.com/sergi/go-diffv1.4.0 · 1×

For agents

$ claude mcp add html-to-markdown \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact