Webpage Text Extractor — URL to Clean Text & Markdown avatar

Webpage Text Extractor — URL to Clean Text & Markdown

Pricing

from $24.00 / 1,000 text extractions

Go to Apify Store
Webpage Text Extractor — URL to Clean Text & Markdown

Webpage Text Extractor — URL to Clean Text & Markdown

Get the readable text off a web page. Pass article or page URLs and get the clean main text back as Markdown or plain text, one result per URL, with ads, navigation and boilerplate stripped. $0.03 per page. Built for RAG and AI agents.

Pricing

from $24.00 / 1,000 text extractions

Rating

0.0

(0)

Developer

Broke to Built

Broke to Built

Maintained by Community

Actor stats

0

Bookmarked

3

Total users

2

Monthly active users

4 days ago

Last modified

Share

Webpage Text Extractor - URL to clean article text and Markdown

Give it an article URL, get back the readable main content as portable Markdown and as plain text, with nav, ads, sidebars, cookie banners and footers stripped out. One record per URL, with the title, byline, publish date, language, word count, reading time and a readability score attached. No API key, no headless browser, no crawl configuration.

This is the "reader" step in front of an LLM: raw HTML is mostly boilerplate, and boilerplate is tokens you pay for and quality you lose. $0.03 per page extracted, flat, no start fee.


What you get, per URL

FieldTypeWhat it is
markdownstringGitHub-flavored Markdown of the main content. Links and images are rewritten to absolute URLs so the document works outside the page.
textstringThe same content as plain text, whitespace normalized.
titlestringog:title, else <title>, else the first <h1>.
bylinestring | nullmeta[name=author], meta[property=article:author], or a [rel=author] element. null when the page declares none.
publishedAtstring | nullarticle:published_time, else the first <time datetime>.
langstring | nullThe lang attribute on <html>.
excerptstringMeta description if present, else the first 280 characters of the text.
wordCountnumberWords in the extracted content.
readingTimeMinnumberwordCount / 225, rounded up, minimum 1.
fleschReadingEasenumber | nullFlesch Reading Ease of the extracted content (English-calibrated).
url, finalUrl, statusCodeWhat you asked for, where it landed after redirects, and the HTTP status.

Set outputFormat to markdown, text, or both (default) to control which of the two big fields are returned.

How the extraction works

  1. Noise elements are removed outright: script, style, nav, header, footer, aside, form, iframe, plus common ad / share / comment / newsletter / cookie / breadcrumb classes and ARIA landmark roles.
  2. A semantic container is preferred - article, main, [role=main], #content, .post-content, .entry-content, .article-body, and similar - as long as it holds real text.
  3. If none qualifies, every div / section / td is scored by text length, paragraph count and link density, and the winner is used. That last term is what keeps a link-farm sidebar from beating the article.
  4. Links and images inside the winner are resolved against the final (post-redirect) URL, then the block is converted to Markdown.

No headless browser is involved, which is why it is fast and cheap - and also why a page that renders its article client-side has nothing for it to read. See the honest limits below.


Input

Single URL:

{ "url": "https://en.wikipedia.org/wiki/Web_scraping", "outputFormat": "both" }

Bulk - one record and one charge per URL:

{
"urls": ["https://a.com/post", "https://b.com/post"],
"maxUrls": 25,
"outputFormat": "markdown"
}
FieldTypeDefaultNotes
urlstring-One URL. A bare domain gets https:// prepended.
urlsarray of strings-Bulk list; takes precedence over url.
maxUrlsinteger25Hard cap on pages processed, and therefore on spend.
outputFormatstringbothboth, markdown, or text.

Output - two real records

Verbatim from a live run on 2026-08-15 (the long fields are truncated here with ...; the real records carry them in full).

A normal article

{
"url": "https://en.wikipedia.org/wiki/Web_scraping",
"finalUrl": "https://en.wikipedia.org/wiki/Web_scraping",
"statusCode": 200,
"title": "Web scraping - Wikipedia",
"byline": null,
"publishedAt": null,
"lang": "en",
"excerpt": "From Wikipedia, the free encyclopediaMethod of extracting data from websites For broader coverage of this topic, see Data scraping...",
"text": "From Wikipedia, the free encyclopedia\nMethod of extracting data from websites\nFor broader coverage of this topic, see Data scraping...",
"markdown": "From Wikipedia, the free encyclopedia\n\nMethod of extracting data from websites\n\nFor broader coverage of this topic, see [Data scraping](https://en.wikipedia.org/wiki/Data_scraping \"Data scraping\")...",
"wordCount": 4233,
"readingTimeMin": 19,
"fleschReadingEase": 50.5
}

Note the link in markdown: the page wrote /wiki/Data_scraping, and the output carries the absolute URL. That is the difference between a Markdown file you can hand to a model or a repo and one whose links only work in the original tab.

An HTTP error page - and what it costs you

{
"url": "https://apify.com/nonexistent-page-xyz-404",
"finalUrl": "https://apify.com/nonexistent-page-xyz-404",
"statusCode": 404,
"title": "Page not found - Apify",
"byline": null,
"publishedAt": null,
"lang": null,
"excerpt": "",
"text": "",
"markdown": "",
"wordCount": 0,
"readingTimeMin": 1,
"fleschReadingEase": null
}

Read this one carefully. A server that answers a 404 with an HTML error page has served a page, so it is extracted and it is charged. statusCode and wordCount tell you exactly what happened - always check statusCode === 200 before trusting the text. Only two outcomes are never charged: the fetch failing outright (DNS, timeout, connection refused), and a response that is not HTML at all. Both return a record with an error field instead.


Call it from code or an agent

curl -X POST "https://api.apify.com/v2/acts/EliAI~webpage-text-extractor/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
-H "content-type: application/json" \
-d '{"url":"https://example.com/some-article","outputFormat":"markdown"}'

Agents can call it as a tool over Apify MCP. The contract an LLM needs:

  • Capability: fetch one or many URLs and return the readable main content as Markdown and text
  • Required input: url (string) or urls (array)
  • Returns: one JSON record per URL; markdown / text plus title, byline, date, counts
  • Bounded: maxUrls caps the run and the spend; no crawling, no link following
  • Side effects: none - one GET per URL, nothing is stored externally

Pricing

$0.03 per page extracted - one page-extracted event per URL that returned an HTML response. No actor-start fee, so a single URL costs exactly $0.03 and 25 URLs cost exactly $0.75. maxUrls is your budget cap.

Honest comparison, measured on the store 2026-08-15. Most content extractors on Apify price per dataset item with a tiny start fee, and at volume they are far cheaper than this:

ActorPrice shape1 page100 pages
eliai/webpage-text-extractor (this one)$0.03/page, no start fee$0.03$3.00
lukaskrivka/article-extractor-smart$0.00005 start + $0.00001/item~$0.0001~$0.001
sync-network/website-main-content-extractor$0.00005 start + $0.0005/item~$0.0006~$0.05
hichemdev/website-content-crawler$0.005 start + $0.001/item$0.006$0.105
easyapi/article-content-extractor$0.09 start + $0.00299/item$0.093$0.389

So: if you are extracting hundreds or thousands of pages, one of those is the right tool and you should use it. What you get here instead is a flat, predictable per-URL price with no start fee to amortize and no crawl to configure - which is what suits a handful of URLs you already have, called synchronously from an agent or a workflow step, where the answer is one record per URL and nothing else runs.

When NOT to use this

  • Bulk crawling a whole site. There is no link following, no depth, no sitemap seeding. Use Sitemap URL Extractor to enumerate the URLs, or a per-item crawler from the table above for the extraction itself.
  • JavaScript-rendered articles. The served HTML is parsed as-is. A page whose article is assembled client-side returns a low wordCount honestly rather than failing - you need a browser-based scraper for those.
  • PDFs, images, JSON, or feeds. Non-HTML responses are reported as error: "not an HTML page" and not charged. For PDFs use PDF Text Extractor.
  • Content behind a login, a paywall, or aggressive bot protection. It fetches anonymously with a plain HTTP client - no cookies, no session, no proxy rotation.
  • Non-English readability scoring. fleschReadingEase uses English syllable heuristics; the text extraction works on any language, but that one number does not.
  • You already hold the HTML or the text. Then you are paying for a fetch you do not need - run your own Markdown converter over what you have.

FAQ

How do I convert a webpage URL to Markdown? Pass the URL with outputFormat: "markdown" (or "both"). The markdown field is GitHub-flavored Markdown of just the main content, with links and images resolved to absolute URLs so the document is portable. No install, no library.

How do I get clean article text for RAG or an LLM prompt? Use outputFormat: "text" and feed text straight into your chunker. Raw HTML for a typical article is several times the size of its readable content, and every byte of that nav-and-footer boilerplate is a token you pay for and a distraction the model has to ignore.

Does it work on JavaScript-rendered pages? It parses the HTML the server sends, without a browser. Most articles, blogs, docs and news sites ship their content in that HTML and work fine. A single-page app that renders the article client-side will come back with a low wordCount - that is the honest signal to use a browser-based scraper for that domain.

What metadata comes back with the text? title, byline, publishedAt, lang and excerpt, plus wordCount, readingTimeMin and fleschReadingEase. Fields the page does not declare come back null rather than guessed.

Can I extract many articles in one run? Yes - pass an array in urls, capped by maxUrls (default 25). One record and one $0.03 charge per page, and one bad URL never stops the others.

Am I charged if the page 404s or is empty? Yes, if the server returned an HTML error page - it was fetched and parsed, and you get the record with statusCode: 404 and wordCount: 0. You are not charged when the fetch fails outright (DNS, timeout, refused) or when the response is not HTML. Check statusCode in your pipeline.

How is this different from a website content crawler? A crawler discovers URLs by following links and bills per item it discovers. This does not discover anything - you give it the exact URLs, it returns exactly that many records. Different job, different price shape; see the comparison table above.

Does it respect robots.txt or send a custom user agent? It identifies itself as TextExtractorBot/1.0 and fetches only the URLs you pass. It does not crawl, so there is nothing to discover or spider; you are responsible for having the right to fetch the pages you submit.


Same account, each doing one job well:

Built by Broke to Built.

For AI agents

This Actor is built to be called by software, not just by people.

  • Mount it directly as an MCP tool — no Store search, no ranking, just this one tool: https://mcp.apify.com/?actors=eliai/webpage-text-extractor
  • Or call it over HTTP and get the results in the same request: POST https://api.apify.com/v2/acts/eliai~webpage-text-extractor/run-sync-get-dataset-items
  • Pay with x402, without an Apify account. This Actor is whitelisted for agentic payments, so an agent holding USDC on Base can buy a prepaid token and spend it here. The minimum purchase is $1, the token balance is an absolute spending cap, and it expires 14 days after purchase.
  • Costs are predictable before you call. Pricing is pay-per-event (see Pricing above), so an agent can budget a run in advance instead of discovering the bill afterwards.
  • Send only the field you mean. If you pass the bulk field, it is used on its own; the single-value field is a fallback, never merged into your request. You are charged for the items you sent and nothing else.