Skip to main content

Confirm

Are you sure?

URL to Markdown API

Any URL in, clean Markdown out

The page's content as Markdown, ready for a prompt, a chunker or a vector store — from a real browser, with numbers on how clean it is.

By · Last updated: September 2026

TL;DR

POST a URL to /markdown and get the page's main content back as Markdown — headings, lists, tables, fenced code and absolute links, with navigation, sidebars and cookie banners left out. The page is rendered in real Chrome first, so JavaScript sites come back complete, and the conversion is a deterministic walk of the DOM: no model, 1 credit a page.

Free plan, no credit card. 1,000 credits a month.

Try it now — no signup

Try it on a page

Try your own URL

Free · no signup · 2 runs every 10 minutes

Paste up to 10 URLs

Each URL counts as one of your free runs; the ones past the limit are listed with a free API key to run them.

Your result will appear here.

Pick one of the pages above to get started.

The request

One POST, one bearer token

POST /markdown
curl -X POST https://urlpipe.dev/markdown \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"url": "https://developer.mozilla.org/en-US/docs/Web/HTTP/Guides/Caching", "sync": true, "page_options": {"block_cookie_banners":true}}'
Response (text/plain, first lines)
# HTTP caching

The HTTP cache stores a response associated with a request and reuses the stored response for subsequent requests.

There are several advantages to reusability. First, since there is no need to deliver the request to the origin server, then the closer the client and cache are, the faster the response will be. …

## [Types of caches](#types_of_caches)

In the [HTTP Caching](https://httpwg.org/specs/rfc9111.html) spec, there are two main types of caches: **private caches** and **shared caches**.

Choosing

How should I choose a URL-to-Markdown API for RAG?

Judge it on four things, in this order: whether it renders JavaScript, how much of the visible text it keeps, how much text it adds that no visitor ever saw, and whether the same page always gives the same Markdown. Price per page matters less than any of these — a bad chunk costs you on every query that retrieves it.

  1. 1
    It renders the page. A client-rendered site sends an empty <div id="root"> to anything that doesn't run its scripts. An API that fetches with plain HTTP returns that shell as a successful, near-empty document — and your pipeline embeds it. URLpipe loads every page in headless Chrome and converts the rendered DOM.
  2. 2
    It keeps what a reader sees. Coverage of the visible text: an article that loses its second half to an over-eager boilerplate filter answers half the questions.
  3. 3
    It doesn't add what a reader never saw. Collapsed menus, off-screen drawers, "skip to content" links, cookie-policy text: all of it is in the HTML, none of it is the page. In a vector store it becomes chunks that match queries they have no business matching. This is the number most tools never publish.
  4. 4
    It is deterministic. The same page gives the same Markdown on every call, so a content hash tells you when a page actually changed, and you re-embed only then. A model-based conversion rewrites the output on every run.
  5. 5
    Links survive. Relative links are resolved to absolute URLs, so a chunk can cite its source and an agent can follow a link without the page it came from.
  6. 6
    The bill matches the work. Check whether re-fetching an unchanged page, or a page that failed, is charged. On URLpipe neither is: cache hits and failed requests cost nothing.

Measured

What the conversion strategies measure

33 real pages, the same fetched DOM for every strategy, two numbers per strategy.

We measured the strategy /markdown ships against the strategies other tools use, on 33 pages: 14 well-known sites and 19 taken from real production requests. Coverage is the share of the text a visitor sees that made it into the Markdown. Text the reader never sees is the share of the Markdown that was not visible on the page — lower is better.

StrategyCoverage of visible textText the reader never seesCost / pageTime / page
URLpipe /markdown (DOM walk)87.2%11.0%$0~20 ms
Readability (what Jina Reader runs)88.2%21.3%——
Firecrawl's selector blocklist85.8%17.0%——
LLM conversion (URLpipe's earlier pipeline)79.0%22.0%$0.002539 s

What this is — and isn't

These are the strategies, reimplemented and run on the same rendered DOM — not the vendors' live APIs, which add their own fetching, rendering and post-processing. Readability keeps slightly more of the visible text (88.2% against 87.2%) and roughly doubles the hidden text that comes with it. Treat the table as a comparison of approaches, and test any API on your own pages before you pick it.

The LLM row is the pipeline /markdown replaced. It scored worse on both numbers, cost money and took seconds per page, which is why the conversion uses no model at all.

Tokens

How many tokens does Markdown save?

A page's HTML is mostly markup, inline scripts and styles, so the same content as Markdown is several times smaller. Measured on 24 September 2026 with the o200k_base tokenizer, converting each page's HTML with the converter /markdown runs:

PageHTML tokensMarkdown tokensSmaller by
Wikipedia — Markdown99,98710,9389.1×
MDN — HTTP caching70,1329,2027.6×
RFC 9110 (HTTP Semantics)372,330150,3952.5×

The ratio depends on the page, not on the converter: the RFC is almost all prose, so there is little markup to remove. The pages above are rendered on the server; on a client-rendered app the raw HTML is smaller than the Markdown of the rendered page, because the content isn't in it at all. That is the case where rendering first is the difference between an answer and nothing.

Page options

Cookie banners, ads and your own clutter

page_options clean the page before it is read. What they take out is removed from the document, not hidden, so it is gone from the Markdown too:

POST /markdown
{
  "url": "https://example.com/blog/launch",
  "page_options": {
    "block_cookie_banners": true,
    "block_ads": true,
    "remove_selectors": [".newsletter-signup", "#related-posts"],
    "wait_for_selector": "article"
  }
}
  • block_cookie_banners removes the banners of the major consent-management providers, and the cookie-policy text their panels inject. Nothing is clicked, so no consent is given for you.
  • block_ads blocks the major ad networks' requests and removes the slots they would fill.
  • remove_selectors takes out up to 50 elements of your choosing.
  • wait_for_selector (up to 10 seconds) and delay hold the capture for content that arrives late. An element that never appears fails the request, and costs nothing.

Limits

What it does not do

  • It doesn't read CSS. The conversion walks the DOM, so text hidden only by a stylesheet can leak into the output. That is most of the 11.0% above. Elements marked hidden or aria-hidden are dropped.
  • It doesn't crawl. One URL in, one document out. There is no link discovery, sitemap walking or whole-site job — send the URLs you already have.
  • It doesn't convert PDFs. A URL that serves a PDF, an image or a download is refused as not a web page, and costs nothing.
  • It doesn't extract to a schema. You get Markdown, not typed fields. For the page's title, author and date, use /meta.
  • It has a size ceiling of 10 MB of HTML per page.

At scale

Built for batches

Requests are async by default: you get a token at once, and the Markdown arrives at your webhook, signed with HMAC-SHA256 and retried if your endpoint is down, or at GET /result/:token for 30 days. Send sync: true to wait for it instead. Results are stored and reused for 7 days by default (max_age sets it, up to 30), and a reused result is free. labels tag each request with your own ids — a tenant, a collection — and come back on the result.

Need the title and date alongside the text? /scrape returns markdown and meta from one page visit, each billed as usual. The HTML to Markdown for LLMs guide covers chunking what comes back.

Pricing

What it costs

CallCreditsFree (calls/mo)Starter (calls/mo)Pro (calls/mo)Scale (calls/mo)
/markdown1 credit1,00020,00055,000175,000

Cache hits and failed requests cost nothing. Paid plans are never cut off: past the allowance, extra credits are $1.50 per 1,000 credits. See every plan.

FAQ

Frequently asked questions

Does the URL to Markdown API use an LLM?
No. The conversion is a deterministic walk over the rendered DOM, so the same page always gives the same Markdown and no model sees your pages. It costs 1 credit per page, the same as the rendered HTML.
Does it work on JavaScript-heavy sites and single-page apps?
Yes. Every page is loaded in headless Chrome and its scripts run before the conversion. For content that arrives after load, page_options.wait_for_selector holds the capture until an element you name exists.
Can it convert a PDF, or crawl a whole site?
No to both. It converts one web page per request; a PDF URL is refused as not a web page and costs nothing. For whole-site crawling, a crawling service is the better fit.
How do I remove cookie banners and ads from the Markdown?
Send page_options with block_cookie_banners and block_ads set to true, and remove_selectors for anything else. The elements are removed from the page before conversion, so they are absent from the output.
Is re-fetching the same page charged again?
Not while the stored result is fresher than max_age, which defaults to 7 days. A reused result costs nothing, and a duplicate request that arrives while the first is still running waits for it, also free.
Is the Markdown the same on every call?
For the same page, yes — the conversion has no randomness. That makes a hash of the output a reliable signal that the page changed, so you can re-embed only what did.

Make your first request in five minutes.

Free plan, no card. Confirm your email and your API key is live — you'll be making real requests in minutes.