URL to Markdown
URL to Markdown API
Send a URL and get the page back as Markdown: headings, lists, tables, code blocks and links, with the site's navigation, header, footer, forms and consent banners removed. The output goes straight into a prompt, an embedding job or a retrieval index.
One request
Add return_page_markdown=true to any fetch. The response is
text/markdown; charset=utf-8.
Request
curl "https://api.webfetch.io/v1/\
?url=https%3A%2F%2Fdeveloper.mozilla.org%2Fen-US%2Fdocs%2FWeb%2FHTTP%2FOverview\
&return_page_markdown=true\
&render_js=false" \
-H "Authorization: Bearer $WEBFETCH_KEY"This page is 228,645 bytes of HTML. The Markdown is 18,847 bytes, 8.2% of the original, for 1 credit as a plain HTTP fetch.
Response, first lines
# Overview of HTTP
**HTTP** is a [protocol](https://developer.mozilla.org/en-US/docs/Glossary/Protocol) for fetching resources such as HTML documents. It is the foundation of any data exchange on the Web and it is a client-server protocol, which means requests are initiated by the recipient, usually the Web browser. A complete document is typically constructed from resources such as text content, layout instructions, images, videos, scripts, and more.

Clients and servers communicate by exchanging individual messages (as opposed to a stream of data). The messages sent by the client are called *requests* and the messages sent by the server as an answer are called *responses*.Excerpt of the response from October 20, 2026, from MDN (CC-BY-SA 2.5).
Size on real pages
Across these 8 pages, 1,301,564 bytes of HTML became 198,276 bytes of Markdown, 15.2% of the original. A model reads the same content in fewer tokens, and an index stores no markup.
| Page | HTML bytes | Markdown bytes | Share |
|---|---|---|---|
| WordPress News wordpress.org/news/ |
155,679 | 2,666 | 1.7% |
| Kubernetes: Overview kubernetes.io/docs/concepts/overview/ |
506,514 | 10,896 | 2.2% |
| MDN: Overview of HTTP developer.mozilla.org/en-US/docs/Web/HTTP/Overview |
228,645 | 18,847 | 8.2% |
| Python blog blog.python.org/ |
31,740 | 2,663 | 8.4% |
| python.org: About www.python.org/about/ |
41,299 | 4,239 | 10.3% |
| Rust: Learn www.rust-lang.org/learn |
17,594 | 3,161 | 18.0% |
| Python docs: Coroutines and tasks docs.python.org/3/library/asyncio-task.html |
177,177 | 53,453 | 30.2% |
| Effective Go go.dev/doc/effective_go |
142,916 | 102,351 | 71.6% |
Measured October 20, 2026 through the API without JavaScript rendering. Each row is one URL
fetched twice, once as HTML and once with return_page_markdown=true. Index and
landing pages shrink the most because most of their bytes are markup. Long documentation
keeps more because most of its bytes are text.
How the conversion works
Deterministic
The converter is code that maps HTML elements to Markdown. Every sentence in the output comes from the page, nothing is summarized or reworded, and the same HTML always produces the same Markdown.
Navigation and banners removed
Scripts, styles, navigation, the site header and footer, sidebars, forms, buttons, iframes, dialogs, hidden elements and the common cookie consent banners go first. When the page marks its content with main or article, only that element is converted.
Structure kept
Heading levels, paragraphs, nested lists, tables, blockquotes, emphasis, inline code, and code blocks tagged with their language when the page names it. A splitter that chunks on headings works on the output as it is.
Links that still resolve
Links and images are made absolute against the final URL after redirects. Same-page anchors become plain text, heading permalink markers are dropped, and inline base64 images are left out.
Rendered or plain
By default the page is loaded in a browser and the Markdown is made from what it
rendered, for 5 credits. wait_for holds the capture until a
selector appears, and js_scenario can click a "Load more" button or open a
section first. When the content is already in the HTML, render_js=false
fetches it over plain HTTP for 1 credit.
When a site refuses the request, mode=auto retries on progressively more
capable routes and bills only the one that worked, up to max_cost.
country_code fetches the page from a chosen country. robots.txt is honored
on every request.
curl "https://api.webfetch.io/v1/\
?url=https%3A%2F%2Fexample.com%2Fapp\
&return_page_markdown=true\
&wait_for=main%20article" \
-H "Authorization: Bearer $WEBFETCH_KEY"Other output shapes
| Parameter | Returns |
|---|---|
return_page_markdown=true | The page content as Markdown |
return_page_text=true | The same content as plain text, without Markdown syntax |
json_response=true | JSON with markdown, resolved-url, initial-status-code, cost and metadata (the page's JSON-LD and microdata), for citing the source |
add_html=true | With json_response, the raw HTML in body as well |
extract_rules | With "output": "markdown_relevant", Markdown of one part of the page, picked with a CSS or XPath selector |
From code and from agents
The JavaScript, Python and PHP SDKs each have a
markdown() method. The MCP server's
fetch_page tool returns Markdown by default, so a connected agent reads
pages as Markdown with no extra settings.
JavaScript
import { WebfetchClient } from '@tuxxin/webfetch';
const client = new WebfetchClient(process.env.WEBFETCH_KEY);
const md = await client.markdown('https://example.com/post');Python
import os
from webfetch import WebfetchClient
client = WebfetchClient(os.environ["WEBFETCH_KEY"])
md = client.markdown("https://example.com/post", render_js=False)PHP
use Tuxxin\Webfetch\WebfetchClient;
$client = new WebfetchClient(getenv('WEBFETCH_KEY'));
$md = $client->markdown('https://example.com/post');MCP client configuration
{
"mcpServers": {
"webfetch": {
"url": "https://webfetch.io/mcp",
"headers": { "Authorization": "Bearer wfk_your_key" }
}
}
}
fetch_page takes url, render_js and
return_format (markdown, text or
html).
Pricing
-
5 credits a page rendered, 1 with render_js=false.
The same as fetching the HTML. Proxies and auto mode are priced as on any request. -
A failed fetch costs nothing.
Billing happens on success only, so a timeout or a block is never charged. -
Free to start.
The free account starts with 1,000 credits and adds 250 every month. Starter is 75,000 credits for $11.99 a month. All plans.
Questions
Does a language model write the Markdown?
No. The conversion is deterministic code that maps HTML elements to Markdown. Every sentence in the output appears on the source page, and the same HTML always gives the same Markdown.
What is removed from the page?
Scripts, styles, navigation, the site header and footer, sidebars, forms, buttons, iframes, dialogs, hidden elements and the banners of the common cookie consent platforms. When the page marks its content with main, article or role="main", only that element is converted.
What happens to links and images?
Both are made absolute against the page's final URL after redirects, so they still resolve once the text is stored somewhere else. Images keep their alt text. Same-page anchors become plain text, and inline base64 images are dropped.
Can it convert pages that build their content with JavaScript?
Yes. Pages are rendered in a browser by default (render_js=true) before they are converted, for 5 credits. wait_for and js_scenario control when the page is captured. When the content is already in the HTML, render_js=false fetches it over plain HTTP for 1 credit.
How is it billed?
5 credits a page with JavaScript rendering, the default, and 1 with render_js=false, the same as fetching the HTML. The conversion adds no cost, and a failed fetch is not billed.
Can I get the source URL and page metadata with the Markdown?
Add json_response=true. The JSON response carries markdown, resolved-url (the final URL after redirects), initial-status-code and metadata with the page's JSON-LD and microdata.
Does it follow robots.txt?
Yes, on every request. A path that robots.txt disallows for WebfetchBot returns a 403 with the code robots_disallowed and is not billed. Paid plans can opt out per key after accepting the acceptable use policy.
How large a page can it convert?
Up to 25 MB transferred, or 5 MB through the stealth pool.
Convert your first page
An email address is the whole signup, and the key works on the first request. The API reference lists every parameter, and the comparison with Firecrawl and Jina Reader covers price and billing.
Get a free key