Installation
Install html-to-markdown for your language using the commands below. Each binding wraps the same Rust core, so behavior matches across runtimes. Pick a tab under Language bindings for copy-paste snippets, feature flags, and a quick verification step where applicable.
Requirements
Section titled “Requirements”| Language | Min version | Package |
|---|---|---|
| Rust | 1.85 | html-to-markdown-rs on crates.io |
| Python | 3.10 | html-to-markdown on PyPI |
| TypeScript / Node.js | Node.js 18 | @xberg-io/html-to-markdown on npm |
| Go | 1.26 | github.com/xberg-io/html-to-markdown/packages/go/v3 |
| Ruby | 3.2 | html-to-markdown on RubyGems |
| PHP | 8.2 | xberg-io/html-to-markdown on Packagist |
| Java | 25 | io.xberg:html-to-markdown on Maven Central |
| C# | .NET 10 | XbergIo.HtmlToMarkdown on NuGet |
| Elixir | 1.14 | html_to_markdown on Hex |
| R | 4.2 | htmltomarkdown on CRAN |
| C | — | libhtml_to_markdown (GitHub Releases) |
| WebAssembly | — | @xberg-io/html-to-markdown-wasm on npm |
| Swift | Swift 6.0 | HtmlToMarkdown SwiftPM package |
| Dart | 3.11 | h2m on pub.dev |
| Kotlin Android | Android minSdk 21 | io.xberg:html-to-markdown-android on Maven Central |
| Zig | 0.16 | html_to_markdown_rs Zig package |
Language bindings
Section titled “Language bindings”Add to Cargo.toml:
[dependencies]html-to-markdown-rs = "3.6"Or via cargo add:
cargo add html-to-markdown-rsVerify:
use html_to_markdown_rs::convert;
fn main() { let result = convert("<h1>Hello</h1>", None).unwrap(); println!("{}", result.content.unwrap()); // # Hello}Feature flags
Section titled “Feature flags”By default only the metadata feature is enabled. Opt in to additional features as needed:
| Feature | Enables | Default | Availability |
|---|---|---|---|
metadata |
HtmlMetadata extraction and all extract_* options |
yes | Available by v3.6 |
visitor |
HtmlVisitor trait and ConversionError::Visitor |
no | Available by v3.6 |
inline-images |
data-URI decoding and inline SVG extraction | no | Available by v3.6 |
serde |
Serialize/Deserialize on all public option and result types |
no | Available by v3.6 |
full |
all of the above | no | Available by v3.6 |
# With visitor supporthtml-to-markdown-rs = { version = "3.6", features = ["visitor"] }
# Everythinghtml-to-markdown-rs = { version = "3.6", features = ["full"] }pip install html-to-markdownUsing uv:
uv add html-to-markdownVerify:
python -c "from html_to_markdown import convert; print(convert('<h1>Hello</h1>').content)"# # HelloRequires Python 3.10+. The package ships precompiled wheels for Linux (x86_64, aarch64), macOS (Apple Silicon, x86_64), and Windows (x64). A source distribution is also available if no wheel matches your platform.
npm install @xberg-io/html-to-markdownUsing pnpm or yarn:
pnpm add @xberg-io/html-to-markdownyarn add @xberg-io/html-to-markdownVerify:
import { convert } from '@xberg-io/html-to-markdown';
const result = convert('<h1>Hello</h1>');console.log(result.content);// # HelloRequires Node.js 18+. The package ships both ESM and CJS outputs with bundled TypeScript types. No separate @types/ package needed.
go get github.com/xberg-io/html-to-markdown/packages/go/v3Verify:
package main
import ( "fmt" htmltomarkdown "github.com/xberg-io/html-to-markdown/packages/go/v3")
func main() { result, err := htmltomarkdown.Convert("<h1>Hello</h1>", nil) if err != nil { panic(err) } fmt.Println(*result.Content) // # Hello}Requires Go 1.26+. The module bundles a precompiled libhtml_to_markdown.a static library for each supported platform — no separate Rust toolchain needed.
gem install html-to-markdownOr add to your Gemfile:
gem 'html-to-markdown', '~> 3.8'Verify:
ruby -e "require 'html_to_markdown'; puts HtmlToMarkdown.convert('<h1>Hello</h1>')[:content]"# # HelloRequires Ruby 3.2+. Precompiled native gems are available for Linux and macOS. On unsupported platforms bundle install will compile the extension from source, which requires a Rust toolchain.
This is a native PHP extension (Rust ext-php-rs), installed with PIE — not composer require (Composer cannot load a native extension):
pie install xberg-io/html-to-markdownVerify:
<?phprequire 'vendor/autoload.php';
use function HtmlToMarkdown\convert;
$result = convert('<h1>Hello</h1>');echo $result['content'];// # HelloRequires PHP 8.2+. PIE downloads the prebuilt extension binary matching your PHP version and platform from the GitHub release (PHP 8.2–8.5 on Linux x86_64/arm64, macOS arm64, and Windows x86_64).
Maven — add to pom.xml:
<dependency> <groupId>io.xberg</groupId> <artifactId>html-to-markdown</artifactId> <version>3.6.8</version></dependency>Gradle — add to build.gradle:
implementation 'io.xberg:html-to-markdown:3.6.8'Or Kotlin DSL (build.gradle.kts):
implementation("io.xberg:html-to-markdown:3.6.8")Verify:
import io.xberg.htmltomarkdown.HtmlToMarkdown;
public class Main { public static void main(String[] args) { var result = HtmlToMarkdown.convert("<h1>Hello</h1>"); System.out.println(result.content()); // # Hello }}Requires Java 25+. The JAR extracts the native libhtml_to_markdown shared library at startup. No separate install step is needed — the library is bundled for Linux x86_64, macOS arm64/x86_64, and Windows x64.
dotnet add package XbergIo.HtmlToMarkdownOr via the NuGet Package Manager in Visual Studio — search for XbergIo.HtmlToMarkdown.
Verify:
using HtmlToMarkdown;
var result = HtmlToMarkdownConverter.Convert("<h1>Hello</h1>");Console.WriteLine(result.Content);// # HelloTargets .NET 10. The package bundles native binaries for Linux, macOS, and Windows via NativeLibrary P/Invoke.
Add to mix.exs:
def deps do [ {:html_to_markdown, "~> 3.8"} ]endThen fetch:
mix deps.getVerify:
{:ok, result} = HtmlToMarkdown.convert("<h1>Hello</h1>")IO.puts(result.content)# # HelloRequires Elixir 1.14+. Uses Rustler NIFs — precompiled NIF binaries are fetched automatically via RustlerPrecompiled. Set RUSTLER_PRECOMPILED_GLOBAL_CACHE_PATH to control cache location.
install.packages("htmltomarkdown", repos = "https://xberg-io.r-universe.dev")Verify:
library(htmltomarkdown)result <- htmltomarkdown::convert("<h1>Hello</h1>")cat(result$content)# # HelloRequires R 4.2+. Available on CRAN for Linux (x86_64), macOS (arm64, x86_64), and Windows.
Download a prebuilt release archive for your platform from the GitHub Releases page. Each archive contains:
libhtml_to_markdown.so/.dylib/.dll— shared librarylibhtml_to_markdown.a— static libraryhtml_to_markdown.h— C header
Build from source (requires Rust toolchain):
git clone https://github.com/xberg-io/html-to-markdown.gitcd html-to-markdowncargo build --release -p html-to-markdown-ffi# output: target/release/libhtml_to_markdown.{so,dylib,dll}Link and verify:
#include "html_to_markdown.h"#include <stdio.h>
int main(void) { HTMConversionResult *result = htm_convert("<h1>Hello</h1>", NULL); if (result == NULL) { fprintf(stderr, "convert failed: %s\n", htm_last_error_context()); return 1; } char *content = htm_conversion_result_content(result); if (content != NULL) { printf("%s\n", content); htm_free_string(content); } htm_conversion_result_free(result); return 0;}Compile with:
gcc main.c -lhtml_to_markdown -L./target/release -o mainEvery heap-allocated string returned across the FFI must be released with htm_free_string, and every result/options handle must be released with the matching htm_*_free function. The memory belongs to the Rust allocator — do not call free() directly.
npm install @xberg-io/html-to-markdown-wasmVerify:
import init, { convert } from '@xberg-io/html-to-markdown-wasm';
await init(); // load and instantiate the .wasm file — call once
const result = convert('<h1>Hello</h1>');console.log(result.content);// # Helloinit() must complete before any convert() call. After that, convert is synchronous. The WASM build exposes inline image extraction when built with inline-images; generated native bindings may omit the Rust-only image payload. Works in browsers, Cloudflare Workers, Deno, and Bun.
Add the package URL in SwiftPM:
https://github.com/xberg-io/html-to-markdownVerify:
import HtmlToMarkdown
let result = try convert("<h1>Hello</h1>", nil)print(result.content()?.toString() ?? "")Requires Swift 6.0+. The package currently targets macOS 13+ and iOS 16+.
dart pub add h2mVerify:
import 'package:h2m/h2m.dart';import 'package:h2m/src/html_to_markdown_rs_bridge_generated/frb_generated.dart' show RustLib;
await RustLib.init();final result = await H2mBridge.convert('<h1>Hello</h1>');print(result.content);Requires Dart 3.11+. The generated package is pure Dart from the caller’s point of view and uses flutter_rust_bridge under the hood.
Add the Android artifact:
implementation("io.xberg:html-to-markdown-android:3.6.8")Requires Android minSdk 21. This is an Android AAR with bundled JNI libraries; Kotlin/JVM users should use the Java artifact (io.xberg:html-to-markdown) directly.
Use the Zig package html_to_markdown_rs from the release artifacts or the repository package metadata.
const html_to_markdown = @import("html_to_markdown");Requires Zig 0.16+. The package wraps the generated C FFI library.
Troubleshooting on Windows
Section titled “Troubleshooting on Windows”If pip install html-to-markdown fails on Windows 11 with Python 3.14 or later, try these steps:
-
Force the prebuilt wheel:
Terminal window pip install --only-binary=:all: html-to-markdownThis prevents fallback to source build. If this fails, a wheel resolution issue exists — try updating
piporuv. -
Enable MSVC compiler (if sdist build is required): Install Microsoft Visual Studio Build Tools with the “Desktop development with C++” workload. Then ensure MSVC’s
link.exeprecedes any GNU variants inPATH. Check withwhere link— the first result should be a path underVC\Tools\MSVC. -
Update pip or uv: Python 3.14 wheel tags are recent. Run
pip install --upgrade piporuv self updateto ensure correct wheel matching.
Install via Cargo:
cargo install html-to-markdown-cliOr via Homebrew:
Homebrew 6.0+ requires explicit trust for third-party taps. Trust once, then install:
brew trust xberg-io/tapbrew install xberg-io/tap/html-to-markdownVerify:
echo "<h1>Hello</h1>" | html-to-markdown# # HelloSee CLI reference for all flags and options.
Found a bug or mistake on this page?
If something here is wrong or out of date, open an issue on GitHub or contribute a fix via pull request.