# HTML Readability to Markdown Converter (`automation-lab/html-readability-markdown-converter`) Actor

Convert raw HTML or one anonymous public webpage into clean Markdown with headings, links, source metadata, and a content hash for RAG ingestion or archives.

- **URL**: https://apify.com/automation-lab/html-readability-markdown-converter.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.44 / 1,000 item extracteds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## HTML Readability to Markdown Converter

Convert supplied raw HTML or one anonymous public page URL into clean Markdown for RAG ingestion, documentation archives, content migration, and knowledge-base pipelines.

The Actor removes common navigation and boilerplate with Mozilla Readability, preserves useful headings and links, and returns source metadata plus a deterministic SHA-256 content hash.

### What does HTML Readability to Markdown Converter do?

The Actor accepts exactly one of two sources:

- a public HTTP(S) page URL; or
- a raw HTML string supplied directly in the run input.

It produces one typed dataset record containing:

- clean Markdown;
- document title and description;
- ordered headings;
- unique absolute links;
- canonical URL and language when declared;
- word and character counts;
- a content hash for deduplication or change detection; and
- source and conversion timestamps.

For URL input, the Actor follows a bounded number of public redirects, rejects private-network destinations, retries temporary failures, and accepts HTML responses only.

### Who is this HTML to Markdown converter for?

#### RAG and AI engineers

Normalize public documentation or supplied HTML before chunking, embedding, retrieval, or model evaluation.

#### Documentation teams

Archive important web documents in a portable text format while retaining headings, links, title, and canonical source information.

#### Data engineers

Feed stable dataset records into Apify integrations, webhooks, Make, Zapier, cloud storage, or custom ETL jobs.

#### Content migration teams

Turn legacy HTML fragments into readable Markdown without copying navigation, forms, scripts, or styling markup.

#### Researchers and compliance teams

Capture public policies, standards, or reference pages with a content hash that helps identify later changes.

### Why use this Actor?

A generic HTML downloader returns markup that is noisy for language models and archives.

A basic tag replacer often retains menus, cookie notices, sidebars, and repeated site chrome.

This Actor combines:

1. safe direct HTML retrieval for one public page;
2. Readability-based main-content extraction;
3. optional CSS-selector targeting for structured documentation;
4. normalized absolute links;
5. Markdown conversion with ATX headings and fenced code blocks; and
6. typed source metadata for downstream automation.

It is intentionally focused.

It does not crawl a site, execute JavaScript, bypass login walls, or take screenshots.

### Input parameters

| Field | Type | Required | Description |
|---|---:|---:|---|
| `url` | string | One source required | Anonymous public HTTP(S) page to fetch and convert. |
| `html` | string | One source required | Raw HTML to convert without fetching a page. |
| `baseUrl` | string | No | Public URL used to resolve relative links in raw HTML. |
| `contentSelector` | string | No | CSS selector such as `main` or `article`; overrides automatic Readability selection. |
| `requestTimeoutSecs` | integer | No | URL request timeout from 5 to 120 seconds. Default: 30. |
| `maxRequestRetries` | integer | No | Retries for temporary failures from 0 to 5. Default: 2. |
| `maxContentBytes` | integer | No | Maximum raw or fetched HTML size from 10,000 to 5,000,000 bytes. |

Provide exactly one of `url` or `html`.

`baseUrl` is valid only with `html`.

### Getting started

1. Open the Actor in Apify Console.
2. Enter a public page in **Public page URL**, or clear it and paste **Raw HTML**.
3. Optionally set `contentSelector` when you know the page's main-content selector.
4. Click **Start**.
5. Open the **Dataset** tab after the run succeeds.
6. Copy `markdown`, or download the record as JSON, JSONL, CSV, XML, Excel, or RSS through Apify's dataset tools.
7. Use `contentHash` to detect duplicate or changed converted content in recurring workflows.

The prefilled Wikipedia URL is a working small example.

### URL input example

```json
{
  "url": "https://developer.mozilla.org/en-US/docs/Web/HTML",
  "contentSelector": "main"
}
```

This fetches the public MDN page, selects its `main` element, converts relative links to absolute links, and emits one Markdown document.

### Raw HTML input example

```json
{
  "html": "<!doctype html><html><head><title>HTTP archive note</title></head><body><nav>Menu</nav><main><h1>HTTP Semantics</h1><p>Read the <a href='/rfc/rfc9110.html'>complete specification</a>.</p></main></body></html>",
  "baseUrl": "https://www.rfc-editor.org/"
}
```

For your own input, replace the sample host with the real public base URL represented by the supplied HTML.

Relative links such as `/guide` become absolute when `baseUrl` is present.

### Output fields

| Field | Meaning |
|---|---|
| `sourceType` | `url` or `raw_html`. |
| `sourceUrl` | Normalized requested URL or raw-HTML base URL; nullable. |
| `finalUrl` | Final fetched URL after redirects; null for raw HTML. |
| `statusCode` | HTTP status for URL input; null for raw HTML. |
| `title` | Readability title or HTML document title. |
| `description` | HTML meta description when present. |
| `canonicalUrl` | Absolute canonical URL when declared. |
| `language` | Language declared on the root HTML element. |
| `byline` | Readability byline when detected. |
| `excerpt` | Readability excerpt when detected. |
| `markdown` | Clean converted Markdown. |
| `headings` | Ordered objects with `level` and `text`. |
| `links` | Unique objects with visible `text` and absolute `url`. |
| `wordCount` | Approximate words in selected readable content. |
| `characterCount` | Characters in the Markdown output. |
| `contentHash` | SHA-256 hash of the Markdown. |
| `convertedAt` | UTC ISO timestamp of conversion. |

Nullable metadata remains `null` rather than being invented.

### Output example

The current implementation produces records shaped like this:

```json
{
  "sourceType": "url",
  "sourceUrl": "https://developer.mozilla.org/en-US/docs/Web/HTML",
  "finalUrl": "https://developer.mozilla.org/en-US/docs/Web/HTML",
  "statusCode": 200,
  "title": "HTML: HyperText Markup Language | MDN",
  "description": "HTML is the most basic building block of the Web.",
  "canonicalUrl": "https://developer.mozilla.org/en-US/docs/Web/HTML",
  "language": "en-US",
  "byline": null,
  "excerpt": null,
  "markdown": "# HTML: HyperText Markup Language\n\n**HTML** defines the meaning and structure of web content...",
  "headings": [
    { "level": 1, "text": "HTML: HyperText Markup Language" },
    { "level": 2, "text": "Key resources" }
  ],
  "links": [
    { "text": "HTML element reference", "url": "https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements" }
  ],
  "wordCount": 1089,
  "characterCount": 13434,
  "contentHash": "9d20a7f6d837c05663c9e65cf6714d698d5a9da9ab3fe09284a0835736cefd4e",
  "convertedAt": "2026-08-29T14:05:00.000Z"
}
```

Page content and counts can change when the source changes.

### How much does it cost to convert HTML to Markdown?

The Actor uses pay-per-event pricing:

- **$0.005** once when a run starts; and
- the applicable tiered price for each converted Markdown document.

At the BRONZE tier, the current document price is **$0.0024 per document**.

Because this Actor returns one document per run, a successful BRONZE URL or raw-HTML conversion costs **$0.0074** before any Apify subscription credits.

Higher subscription tiers receive lower per-document event prices.

Failed validation, failed retrieval, or empty conversion can still incur the one-time start event, but does not emit or charge a document event.

Always check the live pricing panel for the tier that applies to your account.

### Readability and CSS selector behavior

When `contentSelector` is absent, Mozilla Readability identifies the main article-like content.

If the page is short or does not look like an article, the Actor falls back to a `main`, `article`, or document-body element.

When `contentSelector` is present:

- it must be valid CSS;
- it must match at least one element; and
- the first matching element becomes the conversion source.

Selector mode is useful for API documentation, standards, and known templates.

It can be less portable if the source site changes its markup.

### RAG ingestion workflow

A recurring RAG pipeline can:

1. run the Actor for a public documentation page;
2. read the single default-dataset record;
3. compare `contentHash` with the previously stored hash;
4. skip unchanged documents;
5. chunk `markdown` by the objects in `headings`;
6. retain `sourceUrl` and `canonicalUrl` as citation metadata; and
7. embed only new or changed chunks.

The Actor does not create embeddings or choose a vector database.

This keeps conversion reusable across AI stacks.

### Document archiving workflow

For repeatable archives:

1. schedule one task per source page;
2. export the dataset record to cloud storage;
3. name the archive object with the date and `contentHash`;
4. retain `convertedAt`, `finalUrl`, and `statusCode`; and
5. alert in your own workflow when the hash differs.

Apify schedules can start tasks hourly, daily, weekly, or with a custom cron expression.

This Actor does not itself send alerts or retain history outside normal Apify run storage.

### API usage with cURL

Start a run and wait for completion:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~html-readability-markdown-converter/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"url":"https://en.wikipedia.org/wiki/Markdown"}'
```

Keep your Apify token in a secret or environment variable.

Do not commit it to source control.

### API usage with JavaScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const input = {
  url: 'https://developer.mozilla.org/en-US/docs/Web/HTML',
  contentSelector: 'main',
};

const run = await client
  .actor('automation-lab/html-readability-markdown-converter')
  .call(input);

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0].markdown);
```

### API usage with Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor(
    "automation-lab/html-readability-markdown-converter"
).call(run_input={
    "url": "https://nodejs.org/api/http.html",
    "maxContentBytes": 5_000_000,
})

items = client.dataset(run["defaultDatasetId"]).list_items().items
print(items[0]["title"])
print(items[0]["markdown"][:500])
```

### Use with Apify MCP

Add this Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/html-readability-markdown-converter"
```

#### Claude Desktop

Use this remote MCP server configuration in Claude Desktop:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/html-readability-markdown-converter"
    }
  }
}
```

#### Cursor

Add the same `mcpServers.apify.url` value in Cursor's MCP settings.

#### VS Code

Add the same remote Apify MCP URL in your VS Code MCP configuration, then enable the `automation-lab/html-readability-markdown-converter` tool.

Example prompts:

- "Convert this public documentation URL to Markdown and summarize its headings."
- "Run the HTML Readability to Markdown Converter for this page and return its canonical URL and content hash."
- "Convert this raw HTML to Markdown using the supplied public base URL."

### Integrations

The default dataset works with:

- Apify webhooks;
- Make;
- Zapier;
- Google Drive;
- Google Sheets;
- Slack;
- GitHub Actions;
- AWS S3; and
- custom applications through the Apify API.

Large Markdown strings are generally best consumed as JSON or JSONL rather than spreadsheet cells.

### Reliability and retry behavior

URL mode retries only temporary failures such as timeouts, HTTP 429, and selected HTTP 5xx responses.

Retries use bounded exponential backoff.

The Actor does not blindly retry:

- malformed URLs;
- private-network URLs;
- permanent HTTP errors;
- non-HTML content; or
- anti-bot challenge pages.

Redirect destinations are validated again before fetching.

Raw HTML mode performs no network request except DNS validation when a `baseUrl` is supplied.

### Legality and responsible use

Only process pages and HTML you are authorized to access.

Respect website terms, robots guidance, copyright, privacy, and applicable data-protection law.

Do not use the Actor to access internal services or private infrastructure.

The Actor rejects localhost, credentials in URLs, private IP ranges, link-local destinations, and unsafe redirect destinations.

Output may still contain personal or copyrighted information present in the supplied public content.

You are responsible for retention and downstream use.

### Limitations

- One raw HTML document or one public page URL is accepted per run.
- URL mode performs direct HTTP retrieval and does not execute JavaScript.
- Login-required, CAPTCHA-protected, and strongly bot-defended pages can fail.
- The maximum HTML input or response size is 5 MB.
- Readability is heuristic and can omit content on unusual layouts.
- A custom selector uses only its first match.
- Images are represented as Markdown references; image files are not downloaded.
- Tables are converted using Turndown's standard behavior and may need downstream cleanup for complex layouts.
- Content hashes change whenever the resulting Markdown changes.
- The Actor is a converter, not a multi-page crawler or monitoring service.

### Troubleshooting

#### The run says to provide exactly one input source

Clear either `url` or `html`.

The Actor deliberately rejects runs containing both or neither.

#### The selector did not match

Inspect the current page markup and update `contentSelector`, or remove it to use automatic Readability extraction.

#### The page returned HTTP 403 or an anti-bot challenge

The source does not permit this direct anonymous retrieval path.

Use supplied raw HTML when you can lawfully obtain it, or choose an Actor designed for browser rendering.

#### The page is JavaScript-rendered and Markdown is empty

This Actor does not render JavaScript.

Use the related Public Webpage HTML Downloader in rendered mode, then pass lawfully obtained HTML into this Actor.

#### Relative links are missing for raw HTML

Set `baseUrl` to the real public source URL represented by the HTML.

Without a base URL, only already-absolute HTTP(S) links can be retained.

#### The HTML is too large

Reduce the supplied HTML to the useful content, or use `contentSelector` with URL input.

The 5 MB ceiling is intentional for bounded memory and predictable runs.

### Related Automation Lab Actors

- [Public Webpage HTML Downloader](https://apify.com/automation-lab/public-webpage-html-downloader) stores raw or browser-rendered HTML when you need page rendering or the original markup.
- [Multi-Site Article Content Extractor](https://apify.com/automation-lab/multi-site-article-content-extractor) extracts article metadata, clean text, and HTML from batches of article URLs.
- [PDF to Structured Markdown Converter](https://apify.com/automation-lab/pdf-to-structured-markdown-converter) handles supplied PDFs and anonymous public PDF URLs.

Choose this Actor when the primary output you need is one clean Markdown document with headings, links, and source metadata.

### FAQ

#### Can I convert multiple URLs in one run?

No.

The accepted product scope is one source document per run.

Create multiple Apify tasks or call the Actor once per document from your orchestrator.

#### Does it preserve links?

Yes.

HTTP(S) links retained in the selected content are normalized to absolute URLs when a source or base URL is available.

#### Does it preserve headings?

Yes.

The Markdown contains ATX headings, and the `headings` array exposes their level and text separately.

#### Can I use raw HTML without a URL?

Yes.

Leave `url` empty and provide `html`.

Add `baseUrl` only when relative links need resolution.

#### Does it render client-side JavaScript?

No.

It converts the HTML returned by direct HTTP or the raw HTML supplied in input.

#### Can I detect document changes?

Yes.

Compare `contentHash` values from successful runs for the same source and settings.

#### Does the Actor store a Markdown file?

The Markdown is stored in the default dataset record.

Use the API or an integration to write it to a `.md` file or external archive.

#### What happens when conversion fails?

The run exits with a failure status and a concise reason.

It does not emit or charge a document record for failed conversion.

# Actor input Schema

## `url` (type: `string`):

One anonymous public HTTP(S) page to fetch and convert. Provide this or Raw HTML, not both.

## `html` (type: `string`):

Raw HTML to convert without fetching a page. Provide this or Public page URL, not both.

## `baseUrl` (type: `string`):

Optional public HTTP(S) URL used to resolve relative links in supplied raw HTML.

## `contentSelector` (type: `string`):

Optional CSS selector such as main or article. When omitted, Readability removes navigation and boilerplate automatically.

## `requestTimeoutSecs` (type: `integer`):

Maximum seconds to wait for a URL response.

## `maxRequestRetries` (type: `integer`):

Retries for temporary network, rate-limit, or server failures.

## `maxContentBytes` (type: `integer`):

Maximum accepted HTML response or raw input size in bytes.

## Actor input object example

```json
{
  "url": "https://en.wikipedia.org/wiki/Markdown",
  "requestTimeoutSecs": 30,
  "maxRequestRetries": 2,
  "maxContentBytes": 3000000
}
```

# Actor output Schema

## `dataset` (type: `string`):

Dataset containing the converted Markdown record.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "url": "https://en.wikipedia.org/wiki/Markdown"
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/html-readability-markdown-converter").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "url": "https://en.wikipedia.org/wiki/Markdown" }

# Run the Actor and wait for it to finish
run = client.actor("automation-lab/html-readability-markdown-converter").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "url": "https://en.wikipedia.org/wiki/Markdown"
}' |
apify call automation-lab/html-readability-markdown-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,automation-lab/html-readability-markdown-converter"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/FBclqAzNWv9S0mmnl/builds/bgYtTt9fq57iz6KQG/openapi.json
