Fast HTML main-content extractor for Node.js / Bun. Native Rust performance via napi-rs.
Pulls the article body out of a raw HTML page and renders it as clean markdown — stripping nav, footers, related-stories rails, ads, and other site chrome. Page-type aware (article, forum, product, listing, documentation, etc.), with a per-extraction confidence score and harvested metadata (JSON-LD, OpenGraph, microformats).
Built by Firecrawl. Source: github.com/firecrawl/html-extractor.
Install
npm install @firecrawl/html-extractor
bun add @firecrawl/html-extractor
Prebuilt binaries included for linux-x64, macOS ARM64, and windows-x64. No Rust toolchain needed.
Quick start
import { extract } from '@firecrawl/html-extractor'
const html = await fetch('https://example.com/article').then(r => r.text())
const result = await extract(html, { url: 'https://example.com/article' })
console.log(result.markdown)
console.log(result.pageType)
console.log(result.extractionQuality)
console.log(result.metadata?.title)
API
Asynchronous extraction. CPU work runs on a libuv worker thread, so the Node event loop isn't blocked for large pages. Prefer this for production use.
Synchronous variant. Convenient for scripts and short HTML, but blocks the event loop while running. Don't use in request handlers.
version(): string
Returns the library version.
Options
interface ExtractOptions {
url?: string
favorPrecision?: boolean
favorRecall?: boolean
outputText?: boolean
targetLanguage?: string
pageTypeOverride?:
| 'article' | 'forum'
| 'product' | 'listing'
| 'collection'| 'documentation'
| 'service' | 'other'
includeLinks?: boolean
includeTables?: boolean
includeImages?: boolean
includeMetadata?: boolean
minExtractionLength?: number
}
Result shape
interface ExtractResult {
markdown: string
text?: string
pageType: string
extractionQuality: number
language?: string
metadata?: {
title?: string
description?: string
author?: string
publishedDate?: string
siteName?: string
imageUrl?: string
canonicalUrl?: string
language?: string
keywords: string[]
}
stats?: {
textChars: number
elementCount: number
usedFallback: boolean
pageType: string
}
errorReason?: string
}
How the algorithm works
A trafilatura-inspired five-stage pipeline:
- Pre-clean — drop
<script> / <style> / <head> / comments / hidden elements.
- Page-type classification — rules-based ladder (URL patterns, tag counts, class regexes, JSON-LD
@type) picks a scoring profile.
- Score + select — every element scored on 7 features (text density, link density, tag weight, class hints, position, parent chain); the highest-scoring subtree is the candidate main content.
- Fallback chain — if Stage 3 produced a degenerate result, fall through justext-style → readability-style → raw-text.
- Post-clean + render — strip leftover boilerplate from inside the kept subtree, render markdown, extract metadata.
See the Rust crate's README for architecture details and benchmarks.
License
Apache-2.0.