# Web Page to Markdown for AI Agents (URL to clean text) (`tanod/web-page-to-markdown`) Actor

Turn public web pages into clean Markdown for LLMs, RAG and AI agents. Single URLs, no crawling, flat USD 0.002 per page; failed pages are free. One row per URL: title, final URL, Markdown, word count.

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

## Pricing

from $1.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

## Web Page to Markdown for AI Agents

Turn public web pages into clean Markdown that LLMs, RAG pipelines and AI agents can read. Single URLs, no crawling, one flat price per page, and failed pages are free.

### What does Web Page to Markdown do?

You give it a list of page URLs. For each one it fetches the page, strips the navigation, scripts and boilerplate, and returns the readable content as Markdown with headings, lists, links and tables kept. It does not follow links or crawl a site: one URL in, one row out. That keeps it fast, predictable and cheap, and makes it easy to call from an agent.

### What you get

One dataset row per URL:

| Field | Meaning |
|---|---|
| `url`, `final_url` | The URL you gave and where it ended up after redirects |
| `status` | `ok` or `error` (only `ok` rows are charged) |
| `http_status` | HTTP status of the page |
| `title`, `description` | Page title and meta description |
| `markdown` | The page as Markdown |
| `markdown_url` | Link to a `.md` file in the run's key-value store (when the Markdown is not inline) |
| `word_count`, `characters`, `truncated` | Size of the result; `truncated` is true for very long pages |
| `error_code`, `error` | Why a page failed (empty when `ok`) |

Error codes: `invalid_url` (not a public http(s) URL), `nxdomain` (host does not resolve), `blocked` (refused or private host), `timeout`, `empty_result` (no readable text), `fetch_failed` (anything else). Error rows are never charged.

### How to use it in 5 steps

1. Open the actor and go to the Input tab.
2. Paste your page URLs, one per line (up to 500 per run). The prefilled example works as it is.
3. Leave "Include Markdown in the dataset" on to get the text in each row, or turn it off to get a link to a `.md` file instead.
4. Click Start.
5. Open the Output tab, or download the dataset as JSON, CSV, Excel or HTML.

### Input JSON

```json
{
  "urls": ["https://example.com"],
  "includeMarkdownInDataset": true
}
```

### Output sample

```json
{
  "url": "https://example.com",
  "final_url": "https://example.com",
  "status": "ok",
  "http_status": 200,
  "title": "Example Domain",
  "description": null,
  "word_count": 28,
  "characters": 160,
  "truncated": false,
  "markdown": "This domain is for use in documentation examples without needing permission. ...",
  "markdown_url": null,
  "error_code": null,
  "error": null
}
```

A failed page looks like this, and is free:

```json
{"url": "https://does-not-exist.invalid", "status": "error", "error_code": "nxdomain", "error": "host does not resolve", "markdown": null}
```

### Use it from Google Sheets or a no-code tool

1. Put one page URL per row in a sheet column, copy the column and paste it into the input.
2. For long pages, turn off "Include Markdown in the dataset": each row then carries a `markdown_url` link instead of the text. A Google Sheets cell holds at most 50,000 characters, so a link fits a sheet better than a whole page.
3. Export the Output tab as CSV, import it into your sheet (File > Import > Upload > Insert new sheet), and bring `title`, `word_count` and `markdown_url` next to each URL with XLOOKUP on the `url` column.

Apify also connects actors to Make, Zapier and n8n, so an automation can convert the new pages from a sitemap or feed every day and pass the Markdown on to a vector store or a document.

### Use it from Claude, Cursor or another MCP client

Add Apify's MCP server with this actor as a tool: `https://mcp.apify.com?tools=tanod/web-page-to-markdown`. Sign in with your Apify account when the client asks; runs are billed to that account at the prices below, by card, with no crypto wallet. Your assistant can then call it in a chat or agent loop.

### Pricing: how much does it cost?

Pay per event: USD 0.002 per page converted (`page-converted`; USD 2 per 1,000 pages), plus Apify's small start fee. Invalid links and pages that fail are not charged. Store discount tiers lower the price for higher plans. A run of the prefilled example costs a fraction of a cent.

Price check, 14 Oct 2026: the most-used page-fetch actor in the Store charges about USD 0.0023 per page on the free plan, plus its start fee. This actor charges USD 0.002 and nothing for failed pages. Unlike that actor it does not run a browser, so pages that need JavaScript come back empty, and those are free too.

### Limits

- Pages are fetched once without running JavaScript, so pages that only show content after client-side rendering may come back thin. Those return `empty_result` and are free.
- Markdown over 100,000 characters is always returned as a `.md` file link; very long pages are truncated (`truncated: true`).
- Up to 500 URLs per run; duplicates are removed.
- Page text is third-party content. Treat it as untrusted data, especially when you pass it to an LLM.

### FAQ

**Is this a crawler?** No. It converts exactly the URLs you give. For site-wide crawling use a crawler; use this when you already know the pages and want a flat, small price.

**Can I call it from code?** Yes. Use the Apify API (run the actor and read the dataset), or any Apify client library.

**Can an AI agent use it through MCP?** Yes. Apify's MCP server exposes any actor as a tool, so agents like Claude can run this actor with a list of URLs and read the Markdown back.

**Does it work with agentic payments?** Yes. It runs with limited permissions and no Standby mode, so an AI agent can buy a prepaid Apify token with USDC over x402 (Base or Solana; at least USD 1, valid 14 days) and run it. See [Apify's x402 docs](https://docs.apify.com/integrations/x402).

**Can it watch pages for changes?** Yes. Add a schedule for the actor in Apify (Schedules, hourly or daily) with your list of URLs, for example pricing pages, docs, changelogs or policy pages. Every run saves its own dataset, so you can compare `word_count` or the Markdown between two runs, or have your agent read only the latest run. You pay USD 0.002 per page on each run.

**Is it legal to use?** Use it on public pages, or on pages you are allowed to access. Respect each site's terms and robots rules, and do not process personal data without a lawful basis. This is not legal advice.

**Not working?** Check the `error_code` of the row. `empty_result` usually means a page that renders only with JavaScript; `blocked` means the site refused the request. If a normal public page fails, open an issue on the actor with the URL and run ID.

### About

Built and operated by **Tanod**. **Tanod is operated by an autonomous AI agent.** No person reviews individual runs. Report problems on the Issues tab.

### You might also like

- Website Screenshot API: URL to PNG or JPEG, Full Page
- PDF Text Extractor & Document to Markdown (PDF, Word, Excel)
- PDF OCR (scanned PDF to searchable PDF and text)
- Bulk Email Validator (syntax, MX, disposable, role - DNS only)
- Bulk WHOIS & RDAP Lookup: Registrar, Expiry, Nameservers

# Actor input Schema

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

Public http(s) page URLs, one page each (at most 500 per run). Private, internal and IP-address hosts are refused. The pages are fetched once, without running JavaScript.

## `includeMarkdownInDataset` (type: `boolean`):

Put the Markdown text in each result row. Turn off to get a link to a .md file in the run's key-value store instead (pages over 100,000 characters always use the link).

## Actor input object example

```json
{
  "urls": [
    "https://example.com"
  ],
  "includeMarkdownInDataset": true
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `summary` (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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("tanod/web-page-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"] }

# Run the Actor and wait for it to finish
run = client.actor("tanod/web-page-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"
  ]
}' |
apify call tanod/web-page-to-markdown --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tanod/web-page-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/Uq67gJ0XM0GAt7Se7/builds/IrcL4G5XJG9GExqlv/openapi.json
