> Source: https://txtfetch.com/extract/html > Plain-text twin — every page on txtfetch.com has one. https://txtfetch.com/text --- # Any web page, fetched and reduced to clean text. Pass a URL, not a file. txtfetch fetches the page server-side and hands back clean text, with the markup, scripts, and styles gone. Deciding what's chrome (nav, ads, cookie banners) versus article is a caller-side call. See the free tool below to check yours. the-problem Turning a web page into usable text usually means standing up a scraper. You fetch the HTML yourself, strip scripts and styles, and guess at which
is the actual content versus navigation and ads. You also handle redirects and encoding along the way. That's infrastructure most teams don't want to own just to get plain text into a RAG index. one-request-solution Skip the fetch-and-strip pipeline. Pass a url parameter to txtfetch, and it retrieves the page server-side, runs it through Apache Tika's HTML parser, and returns clean plain text. No headless browser, no boilerplate code to maintain. curl ```curl curl -X POST https://api.txtfetch.com/v1/extract \ -H "Authorization: Bearer $TXTFETCH_KEY" \ -F file=@landing-page.html ``` Python ```python import os import requests with open("landing-page.html", "rb") as f: r = requests.post( "https://api.txtfetch.com/v1/extract", headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"}, files={"file": f}, ) print(r.json()["extracted_text"]) ``` JavaScript ```javascript import { readFile } from "node:fs/promises"; const file = new Blob([await readFile("landing-page.html")]); const form = new FormData(); form.append("file", file, "landing-page.html"); const res = await fetch("https://api.txtfetch.com/v1/extract", { method: "POST", headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` }, body: form, }); const { extracted_text } = await res.json(); console.log(extracted_text); ``` Go ```go package main import ( "bytes" "encoding/json" "fmt" "io" "mime/multipart" "net/http" "os" ) type extractResponse struct { Status string `json:"status"` ExtractedText string `json:"extracted_text"` } func main() { f, err := os.Open("landing-page.html") if err != nil { panic(err) } defer f.Close() var body bytes.Buffer writer := multipart.NewWriter(&body) part, err := writer.CreateFormFile("file", "landing-page.html") if err != nil { panic(err) } if _, err := io.Copy(part, f); err != nil { panic(err) } writer.Close() req, err := http.NewRequest("POST", "https://api.txtfetch.com/v1/extract", &body) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY")) req.Header.Set("Content-Type", writer.FormDataContentType()) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var result extractResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { panic(err) } fmt.Println(result.ExtractedText) } ``` Or skip the download. Pass a `url` parameter and txtfetch fetches the document server-side: curl ```curl curl -X POST "https://api.txtfetch.com/v1/extract?url=https://example.com/blog/2024-annual-report" \ -H "Authorization: Bearer $TXTFETCH_KEY" ``` Python ```python import os import requests r = requests.post( "https://api.txtfetch.com/v1/extract", headers={"Authorization": f"Bearer {os.environ['TXTFETCH_KEY']}"}, params={"url": "https://example.com/blog/2024-annual-report"}, ) print(r.json()["extracted_text"]) ``` JavaScript ```javascript const endpoint = new URL("https://api.txtfetch.com/v1/extract"); endpoint.searchParams.set("url", "https://example.com/blog/2024-annual-report"); const res = await fetch(endpoint, { method: "POST", headers: { Authorization: `Bearer ${process.env.TXTFETCH_KEY}` }, }); const { extracted_text } = await res.json(); console.log(extracted_text); ``` Go ```go package main import ( "encoding/json" "fmt" "net/http" "net/url" "os" ) type extractResponse struct { Status string `json:"status"` ExtractedText string `json:"extracted_text"` } func main() { endpoint, err := url.Parse("https://api.txtfetch.com/v1/extract") if err != nil { panic(err) } q := endpoint.Query() q.Set("url", "https://example.com/blog/2024-annual-report") endpoint.RawQuery = q.Encode() req, err := http.NewRequest("POST", endpoint.String(), nil) if err != nil { panic(err) } req.Header.Set("Authorization", "Bearer "+os.Getenv("TXTFETCH_KEY")) resp, err := http.DefaultClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close() var result extractResponse if err := json.NewDecoder(resp.Body).Decode(&result); err != nil { panic(err) } fmt.Println(result.ExtractedText) } ``` ``` { "status": "success", "extracted_text": "..." } ``` what-comes-back That is the shape. This is the text. A real .html from the benchmark corpus, word-diffed against the raw parser output. Nothing here was written for this page. Every character comes from a committed fixture. txtfetch Pricing Page (HTML) `pricing.html` · text/html · left pane read via Apache Tika, **right pane: the human-checked expected.json** raw parser output ``` Pricing Turn any document into clean plain text over a simple HTTP API. pricing tiers diagram Plans Plan Price Quota Hobby $0 500 docs/mo Developer $19 10,000 docs/mo Scale $99 100,000 docs/mo Questions? Use the contact form & skip the 'support' email. ``` the human-checked ideal ``` Pricing Turn any document into clean plain text over a simple HTTP API. pricing tiers diagram Plans Plan Price Quota Hobby $0 500 docs/mo Developer $19 10,000 docs/mo Scale $99 100,000 docs/mo Questions? Use the contact form & skip the 'support' email. ``` [See all ten documents, with the full explanation →](https://txtfetch.com/diff) formats-covered - `.html` - `.htm` - `.xhtml` faq **How do I extract text from a web page URL?**: POST to https://api.txtfetch.com/v1/extract?url= with your API key in the Authorization header. txtfetch fetches the page server-side and returns { "status": "success", "extracted_text": "..." }. **Does it strip navigation, ads, and boilerplate?**: It strips markup, not boilerplate. Tika's HTML parser removes scripts, styles, and tags. But nav, footer, and cookie-banner text is still text, so it comes back in the response like any other paragraph. Deciding what's chrome versus article is a deliberate, caller-side step. See /tools/html-to-text for a free tool that shows you exactly what your pages' chrome looks like before you index them. **Can I upload a local .html file instead of a URL?**: Yes. The same endpoint accepts a multipart file upload for local HTML files, same as any other format. go-further - [Drop an .html file, paste HTML, or paste a copied page — free, in your browser →](https://txtfetch.com/tools/html-to-text) - [Delimited data lives on the CSV side →](https://txtfetch.com/extract/csv) - [Structured/config markup lives on the XML side →](https://txtfetch.com/extract/xml) - [API quickstart →](https://txtfetch.com/docs) - [How the pipeline works →](https://txtfetch.com/how-it-works) - [Extract it from your language →](https://txtfetch.com/for) - [Get an API key →](https://app.txtfetch.com/signup) Web & data - [`.csv`](https://txtfetch.com/extract/csv) - [`.xml`](https://txtfetch.com/extract/xml) - [All formats →](https://txtfetch.com/extract) ## Send a real .html through it. One HTTP call returns the text. Read one in your browser first, for free. [Get an API key →](https://app.txtfetch.com/signup) [Open the free .html reader →](https://txtfetch.com/tools/html-to-text)