# URL to Markdown – HTML to Markdown Converter for LLM & RAG (`chris_elder/html-to-markdown`) Actor

Convert web page URLs or raw HTML into clean GitHub-flavoured Markdown for LLM prompts, RAG ingestion and content migration: headings, links, lists, tables, code and images, main content first. No browser, no API key. $1 per 1,000 pages; failed pages are free.

- **URL**: https://apify.com/chris_elder/html-to-markdown.md
- **Developed by:** [Chris Elder](https://apify.com/chris_elder) (community)
- **Categories:** AI, Developer tools, Automation
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 page converteds

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?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## URL to Markdown – HTML to Markdown Converter for LLM & RAG

**Convert web page URLs or raw HTML into clean, GitHub-flavoured Markdown** for LLM prompts, RAG / vector-database ingestion, docs migration and content audits. Give it a list of page URLs (or paste HTML) and get one dataset row per page with the `markdown`, page title, meta description and character count.

✅ Pay per result: **$1 per 1,000 pages** · 🆓 Failed pages are never charged · 🔑 No API key · ⚡ No headless browser, so it is fast and cheap

[▶ Try it with one click](#how-to-use-it) · [📄 Real example](#real-example-output) · [💲 Pricing](#pricing-pay-per-event) · [🔌 API & integrations](#integrations-api-ai-agents-make-zapier-n8n) · [❓ FAQ](#faq)

### What does URL to Markdown do?

- **Bulk URL to Markdown**: fetch many web pages in parallel and convert each one
- **Raw HTML to Markdown**: paste HTML you already have (from a scraper, CMS export or email)
- **Keeps structure**: H1–H6, paragraphs, links, bold/italic, ordered and unordered lists, tables, fenced code blocks and images
- **Main content first**: uses `<article>` or `<main>` when the page has one; drops scripts, styles, forms, nav, header and footer elements
- **Optional metadata**: page title, meta description and source URL at the top of each Markdown document
- **Per-page timeout and size cap** so one slow page never blocks the run

### Who is it for?

- **LLM and RAG builders** – turn documentation, help centres and blog posts into Markdown before chunking and embedding
- **AI agent developers** – give an agent a "read this web page as Markdown" step through the Apify API or MCP
- **Content and SEO teams** – export existing pages to Markdown for rewrites, audits or migration to a static site
- **Scraper users** – chain it after a crawler or [Sitemap URL Extractor](https://apify.com/chris_elder/sitemap-url-extractor) to turn a URL list into readable text

### How to use it

1. Click **Try for free**. The prefill converts `example.com` and a gov.uk help page (well under one cent).
2. Paste your own URLs into **Page URLs** (one per line), or put HTML in **Raw HTML**.
3. Download the dataset as JSON, CSV or Excel, or read it through the API. Each row has a `markdown` field.

#### Input example

```json
{
  "urls": [
    "https://docs.python.org/3/tutorial/introduction.html",
    "https://en.wikipedia.org/wiki/Markdown"
  ],
  "includeMetadata": true,
  "maxConcurrency": 5,
  "timeoutSecs": 20
}
```

### Real example output

From a public run on 20 Oct 2026 (run `8sDFOdc6Ujc3T6ge5`): 3 URLs in, 2 pages converted and charged, 1 unreachable domain recorded as an error and **not charged**. The `markdown` value is shortened here.

```json
{
  "url": "https://docs.python.org/3/tutorial/introduction.html",
  "ok": true,
  "charged": true,
  "statusCode": 200,
  "title": "3. An Informal Introduction to Python — Python 3.15.0 documentation",
  "description": "In the following examples, input and output are distinguished by the presence or absence of prompts (>>> and …) …",
  "markdown": "# 3. An Informal Introduction to Python — Python 3.15.0 documentation\n\n…\n\nSource: https://docs.python.org/3/tutorial/introduction.html\n\n# 3. An Informal Introduction to Python …",
  "markdownChars": 20659
}
```

```json
{
  "url": "https://this-domain-does-not-exist-xyz123.com",
  "ok": false,
  "charged": false,
  "error": "fetch failed"
}
```

The Wikipedia "Markdown" article in the same run produced 47,782 characters of Markdown.

### Output fields

| Field | Meaning |
|---|---|
| `url`, `finalUrl` | Requested URL and the URL after redirects |
| `ok`, `charged` | Whether the page converted, and whether it was billed |
| `statusCode`, `contentType` | HTTP response details |
| `title`, `description` | Page title and meta description |
| `markdown` | The converted Markdown document |
| `markdownChars` | Length of the Markdown, handy for estimating tokens |
| `error` | Why a page failed (timeout, HTTP 4xx/5xx, DNS) |

### Pricing (pay per event)

| Event | Price |
|---|---|
| Actor start | $0.00005 (once per run) |
| Page converted | **$0.001** ($1 / 1,000) on Free/Bronze; lower on higher Apify plans |
| Failed page | **Free** |

Example: 2,000 documentation pages, 40 of which time out → 1,960 × $0.001 ≈ **$1.96** plus the start fee.

### Integrations (API, AI agents, Make, Zapier, n8n)

Run it through the Apify API or client libraries, on a schedule, or as a step after another Actor. Typical chain: [Sitemap URL Extractor](https://apify.com/chris_elder/sitemap-url-extractor) → URL to Markdown → your vector database. Send results to a spreadsheet with [Google Sheets Sync](https://apify.com/chris_elder/google-sheets-sync).

### Limits and good to know

- It reads the HTML the server returns. Pages that only render content with JavaScript (single-page apps) may come back nearly empty; use a browser-based crawler for those.
- Pages without `<article>` or `<main>` can include some navigation text, as in the Python docs example above.
- Relative image and link paths are kept as written in the page.
- Only convert pages you have the right to use.

### FAQ

**Does it run a headless browser?** No. It fetches HTML over HTTP and converts it, which keeps it fast and cheap.

**Is the output good for LLMs and RAG?** It produces plain Markdown with headings kept, which is easy to split by heading for chunking. It does not call any LLM or summarise content.

**Can I convert PDFs?** Not with this Actor. For PDFs use [PDF to Markdown](https://apify.com/chris_elder/pdf-to-markdown).

**Am I charged for 404s or timeouts?** No. Only pages that convert successfully are charged.

### Support

Open an Issue on this Actor. Built by GPT Shop Ltd with AI-assisted development; every release is reviewed and tested.

# Actor input Schema

## `urls` (type: `array`):

Pages to fetch and convert. Domains without https:// are accepted. Duplicates are removed. Leave empty if you only pass rawHtml.

## `rawHtml` (type: `string`):

Paste HTML to convert without fetching. Combined with urls when both are set. Failed raw parses are free.

## `includeMetadata` (type: `boolean`):

Prepend page title and meta description as Markdown front matter style headings.

## `maxConcurrency` (type: `integer`):

Pages fetched in parallel.

## `timeoutSecs` (type: `integer`):

Timeout per page fetch.

## `maxHtmlBytes` (type: `integer`):

Truncates huge pages before conversion.

## Actor input object example

```json
{
  "urls": [
    "https://example.com",
    "https://www.gov.uk/help"
  ],
  "includeMetadata": true,
  "maxConcurrency": 5,
  "timeoutSecs": 20,
  "maxHtmlBytes": 2000000
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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 = {
    "urls": [
        "https://example.com",
        "https://www.gov.uk/help"
    ],
    "rawHtml": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("chris_elder/html-to-markdown").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 = {
    "urls": [
        "https://example.com",
        "https://www.gov.uk/help",
    ],
    "rawHtml": "",
}

# Run the Actor and wait for it to finish
run = client.actor("chris_elder/html-to-markdown").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 '{
  "urls": [
    "https://example.com",
    "https://www.gov.uk/help"
  ],
  "rawHtml": ""
}' |
apify call chris_elder/html-to-markdown --silent --output-dataset

```

## MCP server setup

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

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/s5dOo0ba5G0JiEm2Y/builds/CcBpZ8bbZIrgzxKtz/openapi.json
