Skip to content

Language Binding Guides

Every binding wraps the same Rust core. The option names and return shapes are identical across languages; only the syntax differs. This page covers per-language install notes and naming conventions.

Package: html-to-markdown-rs on crates.io

html-to-markdown-rs = "3.6"

Option structs follow Rust naming conventions (snake_case). Use the builder API via ConversionOptions::builder() or construct ConversionOptions directly.

See Installation: Feature Flags for the five Cargo features.

Package: html-to-markdown on PyPI Requires: Python ≥ 3.10

Terminal window
pip install html-to-markdown
from html_to_markdown import convert, ConversionOptions
result = convert("<h1>Title</h1>", ConversionOptions(heading_style="atx"))
print(result.content)

Option keys match the Rust field names (snake_case). ConversionOptions accepts keyword arguments. ConversionResult is a class with attributes — access fields as result.content, result.metadata, result.tables, result.images, result.document, result.warnings.

Package: @xberg-io/html-to-markdown on npm Requires: Node.js ≥ 18

Terminal window
npm install @xberg-io/html-to-markdown
import { convert, HeadingStyle } from "@xberg-io/html-to-markdown";
const result = convert("<h1>Title</h1>", { headingStyle: HeadingStyle.Atx });
console.log(result.content);

Option keys are camelCase (headingStyle, linkStyle, outputFormat). The package ships both ESM and CJS outputs. TypeScript types are bundled.

Module: github.com/xberg-io/html-to-markdown/packages/go/v3 Requires: Go ≥ 1.26

Terminal window
go get github.com/xberg-io/html-to-markdown/packages/go/v3
import (
"fmt"
"log"
htmltomarkdown "github.com/xberg-io/html-to-markdown/packages/go/v3"
)
result, err := htmltomarkdown.Convert("<h1>Title</h1>", nil)
if err != nil {
log.Fatal(err)
}
fmt.Println(*result.Content)

Options use Go struct field names (PascalCase). Convert returns (*ConversionResult, error). Errors are standard Go errors. Use errors.Is/errors.As to inspect them.

Gem: html-to-markdown on RubyGems Requires: Ruby ≥ 3.2

Terminal window
gem install html-to-markdown
require 'html_to_markdown'
result = HtmlToMarkdown.convert('<h1>Title</h1>', heading_style: :atx)
puts result.content

Options are keyword arguments with snake_case symbols. result is a ConversionResult object exposing accessor methods (content, metadata, tables, …), not a hash. Errors raise HtmlToMarkdown::ConversionError.

Package: xberg-io/html-to-markdown (native ext-php-rs extension) Requires: PHP ≥ 8.2

Install with PIE — not composer require, which cannot load a native extension:

Terminal window
pie install xberg-io/html-to-markdown
use HtmlToMarkdown\HtmlToMarkdownApi;
use HtmlToMarkdown\ConversionOptions;
$options = ConversionOptions::from_json(json_encode(['headingStyle' => 'Atx']));
$result = HtmlToMarkdownApi::convert('<h1>Title</h1>', $options);
echo $result->content;

Classes live in the flat HtmlToMarkdown\ namespace. HtmlToMarkdownApi::convert returns a ConversionResult object: $result->content is a public property, while $result->getMetadata() and $result->getTables() are accessor methods. Conversion failures throw HtmlToMarkdown\HtmlToMarkdownException.

Maven: io.xberg:html-to-markdown Requires: Java ≥ 25

<dependency>
<groupId>io.xberg</groupId>
<artifactId>html-to-markdown</artifactId>
<version>3.6.8</version>
</dependency>
import io.xberg.htmltomarkdown.HtmlToMarkdown;
import io.xberg.htmltomarkdown.ConversionOptions;
import io.xberg.htmltomarkdown.ConversionResult;
import io.xberg.htmltomarkdown.HeadingStyle;
import io.xberg.htmltomarkdown.HtmlToMarkdownRsException;
public class Main {
public static void main(String[] args) throws HtmlToMarkdownRsException {
ConversionOptions options = ConversionOptions.builder()
.withHeadingStyle(HeadingStyle.Atx)
.build();
ConversionResult result = HtmlToMarkdown.convert("<h1>Title</h1>", options);
System.out.println(result.content());
}
}

Uses a builder for options. Conversion failures throw io.xberg.htmltomarkdown.HtmlToMarkdownRsException and its subtypes (ParseErrorException, ConfigErrorException, InvalidInputException, PanicException, OtherException). Native binaries ship in the JAR for Linux x86_64, macOS arm64/x86_64, and Windows x86_64.

NuGet: XbergIo.HtmlToMarkdown Requires: .NET 10

Terminal window
dotnet add package XbergIo.HtmlToMarkdown
using HtmlToMarkdown;
var options = new ConversionOptions { HeadingStyle = HeadingStyle.Atx };
var result = HtmlToMarkdownConverter.Convert("<h1>Title</h1>", options);
Console.WriteLine(result.Content);

Classes live in the HtmlToMarkdown namespace (the XbergIo.HtmlToMarkdown prefix is only the NuGet package id). Properties are PascalCase. Errors throw HtmlToMarkdownRsException and subtypes.

Hex: html_to_markdown Requires: Elixir ≥ 1.14

{:html_to_markdown, "~> 3.8"}
case HtmlToMarkdown.convert("<h1>Title</h1>", %{heading_style: :atx}) do
{:ok, result} -> IO.puts(result.content)
{:error, _kind, reason} -> IO.warn("failed: #{reason}")
end

convert/2 returns {:ok, result} or {:error, kind, reason}. Options are a map or a %HtmlToMarkdown.ConversionOptions{} struct. The struct fields match the Rust names (snake_case).

CRAN: htmltomarkdown Requires: R ≥ 4.2

install.packages("htmltomarkdown", repos = "https://xberg-io.r-universe.dev")
library(htmltomarkdown)
result <- htmltomarkdown::convert("<h1>Title</h1>", heading_style = "atx")
cat(result$content)

Options are named function arguments. The returned list matches the ConversionResult shape with snake_case names. Errors stop execution with a message; wrap in tryCatch if you need to handle them.

Link against: libhtml_to_markdown Header: html_to_markdown.h (HTM*H, all symbols prefixed htm*_/HTM_)

Download a pre-built release archive for your platform from the GitHub releases page, or build from source with cargo build --release -p html-to-markdown-ffi.

#include "html_to_markdown.h"
HTMAlefHandle result = htm_convert("<h1>Title</h1>", 0);
if (result != 0) {
char *content = htm_conversion_result_content(result);
if (content != NULL) {
printf("%s\n", content);
htm_free_string(content);
}
htm_conversion_result_free(result);
}

Every heap-allocated string must be released with htm_free_string and every handle with the matching htm_*_free function. The C API is a thin synchronous FFI layer. No async mode, no thread-local state. Conversion errors return 0 and set the thread-local error accessible via htm_last_error_code / htm_last_error_context.

npm: @xberg-io/html-to-markdown-wasm

Terminal window
npm install @xberg-io/html-to-markdown-wasm
import { convert, WasmConversionOptions, WasmHeadingStyle } from "@xberg-io/html-to-markdown-wasm";
const options = WasmConversionOptions.default();
options.headingStyle = WasmHeadingStyle.Atx;
const result = convert("<h1>Title</h1>", options);
console.log(result.content);

The package’s default (Node.js) entry point loads the .wasm module synchronously — no init() call needed. Browser and bundler consumers import the web/bundler build instead, which exports an async init() function that must complete before the first convert() call. convert() takes a WasmConversionOptions instance built via WasmConversionOptions.default(), not a plain object literal — its fields use camelCase and have the same shape as the TypeScript binding. The WASM build exposes inline image extraction when built with inline-images; generated native bindings may omit the Rust-only image payload.

Package: HtmlToMarkdown via SwiftPM Requires: Swift ≥ 6.0

Add the package from https://github.com/xberg-io/html-to-markdown and import HtmlToMarkdown.

Package: h2m on pub.dev Requires: Dart ≥ 3.11

Terminal window
dart pub add h2m

The package is pure Dart from the caller’s point of view and uses the generated flutter_rust_bridge runtime.

Package: io.xberg:html-to-markdown-android Requires: Android minSdk 21

Kotlin Android is an AAR with bundled JNI libraries. Kotlin/JVM users should use the Java package (io.xberg:html-to-markdown) directly.

Package: html_to_markdown_rs Requires: Zig ≥ 0.16

The Zig package wraps the C FFI surface and links to the generated native library.

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.