Skip to content
Markdown API · Use case

Get clean Markdown from a URL, without navigation or boilerplate

Clean Markdown from a URL starts with converting the right element, not with cleaning up afterwards. Whole-page Markdown carries the menu, the footer, the cookie notice and three related-post widgets, and every one of them costs tokens and confuses retrieval. The Markdown API lets a RAG pipeline, a read-it-later app or a docs importer convert exactly the element that holds the content, so only the article body turns into Markdown.

The problem

Navigation and boilerplate end up in your Markdown

On a typical article page the readable text is a minority of the markup. Navigation, sidebars, comment forms and legal footers repeat on every URL of the site, so an index built from whole pages is dominated by identical noise. Ask it a question and the closest match is often a menu.

Cleaning after the conversion means heuristics: a readability API or library, regular expressions over Markdown, per-site blocklists of phrases. They work until a layout changes, and they fail silently, either by leaving the newsletter form in or by cutting the last paragraph of the article out.

Microlink’s conversion already drops scripts, styles and navigation chrome, and adblock removes third-party ads, trackers and consent services at the network level before the page renders. For everything else, a selector scopes the conversion to main or article, and a small injected script removes site-specific widgets inside that scope before the conversion runs.

How it works

How to get clean Markdown from a URL with a selector

A selector does most of the work. selectorAll returns one Markdown string per match when the content is a list, and modules removes leftovers inside the scope. The URL to Markdown guide shows the same scoping with the raw API.

1 · Convert only the article
import createClient from 'microlink.io'

const microlink = createClient({
  apiKey: process.env.MICROLINK_API_KEY
})

const markdown = await microlink.markdown('https://example.com/blog/post', {
  selector: 'article'
})

The conversion is limited to the first element matching the selector, so the header, the sidebar and the footer never enter the Markdown. The call resolves to a string.

2 · One string per item
import createClient from 'microlink.io'

const microlink = createClient({
  apiKey: process.env.MICROLINK_API_KEY
})

const comments = await microlink.markdown('https://example.com/thread', {
  selectorAll: '.comment'
})

console.log(comments.length)

selectorAll resolves to an array with one Markdown string per matching element, which suits threads, listings and search results where each item should become its own document.

3 · Remove leftovers, as a URL
curl 'https://api.microlink.io/?url=https%3A%2F%2Fexample.com%2Fblog%2Fpost&data.markdown.selector=main&data.markdown.attr=markdown&meta=false&embed=markdown&modules=document.querySelectorAll%28%27.share%2C+.newsletter%2C+.related%27%29.forEach%28node+%3D%3E+node.remove%28%29%29'

modules runs JavaScript in the page before the conversion, so the removed nodes never reach the Markdown, and embed=markdown returns the result directly as text/markdown. The page preparation guide covers click, scroll and styles for pages that need more.

Parameters used
  • selector Scope the conversion to the first element matching a CSS selector.
  • selectorAll Convert every matching element and get an array with one Markdown string each.
  • adblock Blocks third-party ad, tracker and cookie consent requests. On by default.
  • modules Inject inline JavaScript or a module URL to remove site-specific widgets before the conversion runs.
  • meta false skips metadata detection when you only want the body. Default true.

Start with main or article, since most publishing platforms wrap the content in one of them, and fall back to a site-specific selector only when they do not. Paste a URL into the URL to Markdown tool to see the unscoped output you are starting from.

Why it works

Why scoping at the source gives cleaner Markdown

Cleaning Markdown after the fact needs heuristics. Scoping the conversion needs a selector.

01 · Tokens you do not pay for
Boilerplate never reaches the model.
A conversion scoped to the article body is a fraction of the whole page. Fewer tokens per document means cheaper embeddings, cheaper prompts and more documents per context window.

The Markdown API page puts the saving at up to 80% fewer tokens than raw HTML, and scoping compounds it.

02 · Better retrieval
Chunks contain content, not menus.
When every page in an index shares the same navigation text, similarity search surfaces the navigation. Scoped conversions keep each chunk about its own subject, which is what makes answers cite the right page.

For a whole site, run the scoped request over every URL with bulk Markdown conversion, and convert list items with selectorAll so each item becomes its own document.

03 · Deterministic
The same selector yields the same body every run.
Readability heuristics change their mind when a layout changes. A selector either matches or resolves to null, a failure you can detect and alert on instead of indexing the wrong text.

When not to: if you convert thousands of unrelated sites and cannot maintain selectors, start with main and article and accept some noise. A per-site selector map is a later optimization, not a prerequisite.

FAQ

Which selector gives the cleanest Markdown for an article?

Try main or article first, because most platforms wrap the content in one of them. Otherwise inspect the page and pick the container that holds the text, such as .post-content. Any CSS selector that document.querySelector accepts works.

What happens if the Markdown selector matches nothing?

The value resolves to null, so your code can detect it and fall back to a broader selector or to the whole page. To declare the fallback in the request, write the rule with extract and pass an array of selectors: the first one that yields a value wins.

How do I get clean Markdown from a URL without the navigation?

Scope the conversion with selector so only the content container is converted. Navigation, sidebars and footers live outside that element, so they are never part of the output and there is nothing to strip afterwards.

Does adblock change the Markdown output?

Yes, for the better. It blocks third-party ads, trackers and cookie consent services before the page renders, so their text never enters the conversion. It is on by default on every plan, the same behavior that produces clean PDFs without ads.

Can I remove elements inside the scoped Markdown content?

Yes. Inject a small script with modules that removes the nodes, for example share buttons or newsletter forms, before the conversion runs. If the content itself is rendered by JavaScript, combine it with the waits described in Markdown from JavaScript-rendered pages.
Related use cases

Solve the next problem with the same API

Markdown with metadata frontmatter

Get each page as Markdown with a YAML frontmatter block: title, author, date, word count and reading time.

Markdown from JavaScript-rendered pages

Render single-page apps in a real browser, wait for the content, then convert the finished DOM to Markdown.

LLM context from any URL

Compose Markdown, links, emails, metadata and tech stack from one URL into a context object for your agent.

Bulk Markdown conversion with caching

Convert thousands of URLs in parallel, cached per URL and refreshed in the background for cheap re-indexing.

Clean PDFs without ads or banners

Get a document, not a browser tab: ads and consent popups blocked by default, sticky chrome removed with one CSS rule.

Screenshots without cookie banners or ads

Ads, trackers and consent popups are blocked before the page renders, and one option dismisses first-party banners.

Ready for content-only Markdown?

One selector removes the noise at the source. Start on the free tier and convert your first article body today.