MarkItDown vs Docling vs Jina Reader vs Crawl4AI for Websites

MarkItDown, Docling, Jina Reader and Crawl4AI on 10 real URLs: headings kept, navigation leaked, tokens and time. Where each one wins and loses.

Written byAndrii
Published on
MarkItDown vs Docling vs Jina Reader vs Crawl4AI for Websites

MarkItDown vs Docling vs Jina Reader vs Crawl4AI: Which markdown converter for websites?

If the goal is a docs or help-center site feeding an AI knowledge base or support bot, I would use Crawl4AI with fit_markdown when you can run a browser, a crawl API when you cannot, and Docling only for the PDFs. The file converters (MarkItDown and Docling) are not the weak link once they have the page HTML. The weak link is everything around the conversion. They do not render JavaScript, they keep the navigation, and MarkItDown got a 403 from Wikipedia when it fetched the URL itself. Crawl4AI renders JavaScript but leaks the most boilerplate unless fit_markdown is on. Jina Reader is the cleanest and drops the most content. For PDFs, Docling is the best of the four.

That comes from one run on 10 URLs on 2026-10-30. It is the end-to-end companion to the HTML to markdown library benchmark, and step 1 of the website to markdown knowledge base pipeline. Eight of the 10 pages are shared with that benchmark. Two are new, a JavaScript-rendered page and a PDF.

I run WebCrawlerAPI, so one of the five rows below is ours. It is labeled, it ran with the same rules as the others, and it lost on some pages. The method, code and per-page numbers are linked at the end of the test section.

Short verdict

If you needUseWhy, from this run
PDFs and Office filesDocling24 of 24 headings and 4 pipe tables on the PDF, but 36 to 61 s on CPU
One URL now, no setupJina ReaderLowest leakage (3.1%), but 72.0% heading recall and a near-empty result on the JS page
Self-hosted, JS-rendered pagesCrawl4AIOnly open tool here that rendered the JS page; use fit_markdown to cut leakage from 8.5% to 4.3%
HTML already in handMarkItDown or Docling97.7% and 99.4% heading recall, 0.1 to 0.2 s per page, no navigation removal
A whole site, on a schedule, hostedA crawl API (ours: WebCrawlerAPI)4.1% leakage and no hard failures on the 9 web pages, but 51.8% word recall on the Guardian front page and the PDF returned as base64

What each tool is built for

MarkItDown

MarkItDown (0.1.9) is a Microsoft library that turns files into markdown for LLM pipelines. For HTML it wraps markdownify, which the library benchmark already measured. A plain pip install markitdown raised MissingDependencyException on the PDF. The markitdown[pdf] extra fixed it. Given a URL, it fetches the page itself with a plain HTTP client and converts what comes back.

Docling

Docling (2.145.0) is a layout-aware document parser for PDF, DOCX, HTML and more. PDFs go through machine-learning models (a 506 MB model cache and a 1.5 GB virtual environment here, with PyTorch 2.15.0). HTML does not. The HTML pages converted in under 0.8 s each, with no model load. I did not run it with a GPU, so the PDF times are CPU times on an Apple Silicon laptop.

Jina Reader

Jina Reader is a hosted service: a GET request to https://r.jina.ai/<url> returns markdown. The Jina Reader page (read 2026-10-30) says it is free and lists 20 requests per minute without a key. This run used no key, 10 requests, 4 s apart. It fetches on its own servers, so the target site sees Jina, not you.

Crawl4AI

Crawl4AI (0.9.5) is an open-source Python crawler on top of Playwright with a markdown generator and content filters. What it is and how to set it up is covered in the open-source crawler roundup and the Crawl4AI tutorial. Here it ran in the smallest configuration: default markdown generator, check_robots_txt=True, plus a PruningContentFilter so that both raw_markdown and fit_markdown came from the same crawl. The project's README now also advertises a hosted Crawl4AI service; I did not test it, so everything below is the open-source library.

How the test was run

Ten URLs, one machine (Apple Silicon, macOS 15.6.1, Python 3.11.2), one day.

TypePageNote
DocsPython tutorial, classesshared with the library benchmark
DocsRequests quickstartshared
DocsFlask quickstartshared
Table-heavyWikipedia, comparison of lightweight markup languagesshared, 23 tables
Table-heavyPython built-in functionsshared
ArticleMartin Fowler, Microservicesshared
ArticleJoel on Software, The Joel Testshared
Front pageThe Guardian, technologyshared, cookie banner, list of stories
JS-renderedquotes.toscrape.com/js/content is absent from the raw HTML (0 quote elements raw, 10 after rendering)
PDFarxiv.org/pdf/1706.0376215 pages, 2.2 MB

The JS page is a public sandbox built for scrapers, so it is not typical. It only tests whether a tool renders JavaScript.

Metrics:

  • Heading recall: share of the h1 to h4 headings in the main region found in the output. For the PDF, a hand list of 24 section titles that must match a whole output line.
  • Leakage: share of output tokens (cl100k_base) that are not words of the main region. The main region is one CSS selector per page, taken from the raw HTML (the rendered DOM for the JS page). This is a simpler rule than the hand labels in the library benchmark, so the leakage numbers of the two posts do not compare.
  • Tokens and seconds: median per page. Seconds are end to end (fetch plus convert) when a tool is given a URL.
  • Failures: an error, or under 20% of the main words in the output.

Each tool ran once per URL. Two variants cover the fairness question: MarkItDown and Docling were also fed the cached HTML (the rendered DOM for the JS page), which separates the converter from the missing fetch step. Crawl4AI reports raw_markdown and fit_markdown from one crawl.

Requests were small. robots.txt was checked before every fetch (quotes.toscrape.com has none, it returns 404), the User-Agent was WebCrawlerAPI-benchmark/1.0, and requests were spaced 2 to 4 s apart (15 s for arXiv, which asks for a 15 s crawl delay). Crawl4AI ran with check_robots_txt=True and the API with respect_robots_txt: true. Jina fetches on its side, so I only chose sites that allow it. WebCrawlerAPI got 10 calls to POST /v2/scrape with output_formats: ["markdown"] and main_content_only: true. arXiv saw one extra request because the MarkItDown PDF row was rerun after installing the PDF extra.

Terminal output of report.py: tool versions, heading recall, leakage, median tokens, seconds and failures per tool, plus the PDF rows

Limits: one labeler, 10 pages, one machine, one day, a text-match heuristic. The code, results.json and trimmed output excerpts are in the post's assets folder. Robots rules are explained in what is robots.txt.

Results

Heading recall and leakage are pooled over the 9 web pages. The Guardian front page is 66 of the 175 headings and dominates several rows, so each metric is also shown without it.

ToolHeadings, 9 pagesHeadings, excl. GuardianLeakage, 9 pagesLeakage, excl. GuardianMedian tokensMedian sWeb failuresPDF headings (of 24)
MarkItDown, given URL85.1%79.8%5.9%4.0%8,9050.26210
MarkItDown, given HTML97.7%100%6.3%4.7%8,5630.11010
Docling, given URL99.4%100%5.8%4.7%8,7570.35124
Docling, given HTML99.4%100%5.8%4.7%7,9190.17024
Jina Reader72.0%75.2%3.1%0.9%8,0270.93123
Crawl4AI, raw markdown97.7%100%8.5%7.1%10,0601.460failed
Crawl4AI, fit_markdown95.4%99.1%4.3%4.2%9,3311.460failed
WebCrawlerAPI (ours)72.6%98.2%4.1%2.8%8,2160.920base64 file, not text

The failures are: MarkItDown by URL on the Wikipedia page (403) and the JS page, Docling by URL on the JS page, Jina Reader on the JS page. Median tokens count pages with usable output only. Seconds for the "given HTML" rows exclude the fetch, so they are not comparable with the rows that fetch. Network time dominates for Jina and the API, so none of this is a speed ranking.

Bar chart of boilerplate leaked and heading recall for MarkItDown, Docling, Jina Reader, Crawl4AI and WebCrawlerAPI, with lighter bars for the HTML-fed and fit_markdown variants

Static docs pages

The leakage figure is kind to the file converters here, and it hides the navigation. On the Python docs page, MarkItDown, Docling and Crawl4AI raw leak only 7.3%, 7.4% and 14.8%, because the sidebar table of contents repeats the headings that count as main words. In the output, 50 (MarkItDown), 44 (Docling) and 45 (Crawl4AI) non-empty lines come before the first sentence of the page. The API had 15, Crawl4AI fit_markdown 8 and Jina Reader 3.

Terminal panes showing the first 17 lines of MarkItDown, Docling, Jina Reader and Crawl4AI output for the same Python docs page, with navigation lines highlighted

The strings "Previous topic" and "Report a bug" (both sidebar text) appear in MarkItDown, Docling, Crawl4AI raw and the API output. Jina Reader has neither. Crawl4AI fit_markdown has the first one. So main_content_only: true did not strip the Sphinx sidebar on this page. It targets article-style pages, and a docs page with a sidebar is a miss.

JS-heavy page

MarkItDown returned 60 tokens, Docling 25 and Jina Reader 118: the title, a login link and "Next". Jina's output carried its own warning, "This page maybe not yet fully loaded". Crawl4AI returned 412 tokens and the API 420, with the quotes. The API took 3.5 s on this page, against 0.6 to 1.3 s on the static ones.

Docling given the rendered DOM returned all of it (100% word recall). What the file converters lack here is the browser, not the conversion. See how to scrape JavaScript-heavy sites if that part is new.

Terminal panes with the first lines of each tool's output for the JavaScript page (top row) and the PDF (bottom row)

Table-heavy pages

Tables survived in nearly every tool. On the Wikipedia page (23 tables), MarkItDown (given HTML), Docling and the API wrote 23 pipe tables. Crawl4AI wrote 22 and Jina Reader 16. On the Python built-ins page, fit_markdown found only 80.95% of the table cell text against 100% for raw markdown: the content filter pruned table rows. If tables matter, fit_markdown needs a second look. MarkItDown never fetched the Wikipedia page, because it got a 403 (one of its 2 URL-mode failures).

Jina Reader keeps less than it should

Jina's leakage is the lowest (3.1%), but it gets there by dropping content. It found 12 of 25 headings on Fowler's article, and only 69.2% of that page's main words. On Wikipedia it found 10 of 22 headings. On the Guardian page it kept 76.9% of the main words, where most tools kept more than 99%. A missing section in a knowledge base is a question your support bot cannot answer, and nothing in the output says the section was ever there. The Firecrawl alternatives roundup covers hosted tools with the same trade.

The bottom row of the screenshot above shows the PDF outputs. Docling found all 24 headings and wrote 4 pipe tables. It took 61 s the first time (which includes loading the models) and 36 s on the second pass, CPU only. Jina Reader found 23 of 24 headings in 0.4 s and wrote no pipe tables. MarkItDown found 10 of 24 because words were glued together ("Providedproperattributionis..."), though it ran in 2.8 s. Crawl4AI failed with Page.goto: Download is starting: the browser tried to download the file.

The API call succeeded (HTTP 200) but its markdown field held the PDF itself, base64-encoded, 2,082,760 tokens of JVBERi0.... That is what the run returned for this one PDF. The scrape docs do not document PDF output, so I would not build on it.

Speed and setup cost

Per web page, MarkItDown and Docling took under 0.8 s (given a URL), Crawl4AI 1.1 to 1.9 s, Jina Reader 0.4 to 2.6 s and WebCrawlerAPI 0.6 to 3.5 s. Crawl4AI is slower because it launches a browser. It needs 572 MB of Chromium, and its virtual environment (867 MB) also holds MarkItDown, so that figure covers both. Docling is the heavy install: 1.5 GB of virtual environment plus the 506 MB model cache.

Where the file converters fall down on websites

They were built for files, so the missing pieces are the ones a web crawler provides. There is no readability step, which is why all of the navigation reached the output. There is no browser: the JS page gave 60 and 25 tokens. And the fetch is basic. MarkItDown sent a plain request and Wikipedia answered 403.

Given HTML, the picture flips. Docling kept 99.4% of headings and 99.3% of the main words, level with Crawl4AI raw. If your pipeline already has a fetcher that renders pages, either one works as the converter. Put a selector or a content filter in front, since neither strips the sidebar.

Firecrawl was out of scope for this test; for hosted crawlers see best Firecrawl alternatives.

MarkItDown vs Docling, and when MarkItDown is the wrong tool

On HTML, MarkItDown and Docling came out level once both had the page (97.7% and 99.4% of headings, 6.3% and 5.8% leakage). On the PDF the gap was large: 24 of 24 headings for Docling against 10 of 24 for MarkItDown, which glued words together. So the choice between them is about files, not websites. For websites, neither is the tool to start with.

MarkItDown is the wrong tool when the input is a URL (it fetched Wikipedia with a plain request and got a 403, and it cannot render JavaScript), when the PDF text must be clean, or when navigation must go. MarkItDown alternatives, by job: Docling for PDFs, Crawl4AI for JavaScript pages, a crawl API for whole sites.

Jina Reader alternative, and Jina Reader vs Crawl4AI

Jina Reader vs Crawl4AI in one line: Jina is cleaner and needs no setup but dropped sections here, Crawl4AI kept 97.7% of headings and rendered the JS page but needs a browser and a filter. As a Jina Reader alternative, Crawl4AI is the self-hosted pick, and a crawl API is the hosted pick.

Which one to use

  • PDFs and Office files: Docling. Budget minutes of CPU per batch, or a GPU. MarkItDown with the PDF extra is lighter, but only if word spacing does not matter. It mattered in this PDF: MarkItDown found 10 of 24 headings and glued words together.
  • One URL, no infrastructure, a human reading the answer: Jina Reader, and accept that it drops sections.
  • Self-hosted, JS-rendered pages, full control: Crawl4AI with fit_markdown (4.3% leakage, 95.4% headings), and a check on table-heavy pages. You pay in operations: a browser per worker, memory and retries.
  • Whole-site crawl on a schedule into an AI knowledge base, hosted: a crawl API. It has no browser fleet to run, and no hard failures on the 9 web pages here, though it dropped about half of the Guardian front page.
  • Docs site feeding a support bot: crawl the site, keep the main content, then chunk it. If the sidebar survives (it did on the Python docs page with main_content_only: true), the scrape docs list clean_selectors for removing CSS selectors from the output. I did not test that option here. With Crawl4AI, fit_markdown removed more of the sidebar than raw markdown did (8 lines before the first sentence against 45).
  • A free tool is enough when the site is small, the volume is low and you own the infrastructure. Crawl4AI plus a selector costs nothing per page.

To try it on your own pages, start with one URL in the free URL to markdown tool, then move to the crawl API for a whole site. The web scraping API covers single pages from code. For WebCrawlerAPI, one request looked like this. Pay-as-you-go pricing is $0.002 per page (pricing docs, read 2026-10-30), so the 10 calls cost $0.02.

// Node 18+: one page to markdown, main content only, robots.txt respected
const res = await fetch("https://api.webcrawlerapi.com/v2/scrape", {
  method: "POST",
  headers: {
    Authorization: "Bearer YOUR_API_KEY",
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    url: "https://docs.python.org/3/tutorial/classes.html",
    output_formats: ["markdown"],
    main_content_only: true,
    respect_robots_txt: true,
  }),
});
const { markdown } = await res.json();
console.log(markdown.slice(0, 500));

Terminal card with the scrape request and the first lines of the markdown response for the Python docs page

Where it was weak: 51.8% word recall and 20 of 66 headings on the Guardian front page (a list of stories), the Sphinx sidebar kept on the docs page, and the base64 PDF. Where it was strong: 98.2% heading recall and 2.8% leakage on the 8 other web pages. Options are described in /docs/api/scrape and cleaning.

Next steps


About the Author

Andrii Mazurian
Andrew Mazurian@andriixzvf

Founder, WebCrawlerAPI · 🇳🇱 Netherlands

Engineer with 15 years of experience in APIs, big data, and infrastructure. Founded WebCrawlerAPI in 2024 with a single goal: to build the best data API, and have been shipping it every day since.