Bun.HTML.readability extracts the main article of an HTML document with the readability engine of Brave Speedreader. Bun.HTML.extract reads element attributes with CSS selectors, like the Brave web-discovery document extractor. Both run natively, never fetch resources and never execute scripts.
Bun.HTML.readability
const html = await Bun.file("post.html").text();
const article = Bun.HTML.readability(html, { url: "https://example.com/post" });
if (article) {
console.log(article.title); // "Reading mode in Bun"
console.log(article.byline); // "Ada Lovelace"
console.log(article.text); // article text without navigation, ads or footer
}
The input is a string, an ArrayBuffer or a TypedArray of UTF-8 bytes. The result is null when no article candidate is found, or when the text is shorter than minLength.
| Field | Type | Description |
|---|---|---|
title | string | Title from JSON-LD, <meta> tags or <title>, without the site name |
byline | string | null | Author from JSON-LD or <meta name="author"> |
excerpt | string | null | Description, or the first sentence of the article |
lang | string | null | lang attribute of <html> |
content | string | Cleaned article HTML |
text | string | Text content of the cleaned article |
length | number | Number of characters in text |
score | number | Mozilla readability score of the original document |
readable | boolean | score is above the Speedreader threshold (20) |
page | string | Speedreader reader page, only with page: true |
Options
| Option | Description |
|---|---|
url | URL of the document (default https://example.com/). An invalid URL throws |
minLength | Return null when the article text is shorter |
page | Also serialize the reader page, a complete HTML document |
theme, fontFamily, fontSize, columnWidth | data-* attributes of the reader page's <html> |
const { page } = Bun.HTML.readability(html, { url, page: true, theme: "dark" })!;
return new Response(page, { headers: { "Content-Type": "text/html; charset=utf-8" } });
Bun.HTML.extract
Each request selects elements with selector and reads one value per attribute request. The attribute "textContent" reads text. An attribute request with its own selector reads from the first matching descendant; a missing attribute or descendant gives "". Requests with an invalid selector are skipped.
const results = Bun.HTML.extract(html, [
{
selector: ".result",
attributes: [
{ key: "url", selector: "a", attribute: "href" },
{ key: "title", selector: "a", attribute: "textContent" },
],
},
]);
// [{ selector: ".result", values: { url: "https://a.example/", title: "First" } }, ...]
Implementation
The readability engine is Brave's Speedreader (MPL-2.0, derived from the MIT readability and kuchikiki crates), absorbed into Bun as the bun_readability crate. It parses with the same html5ever parser as Bun.HTML.parse; Bun.HTML.extract uses the Bun.HTML DOM and selector engine. Bun.HTML is created on first access, so neither API costs anything at startup. For streaming transformations without a DOM, use HTMLRewriter.