How to Use the `@firecrawl/pdf-inspector` Node.js Bindings: Complete Guide
The @firecrawl/pdf-inspector package provides native Node.js bindings that expose the full Rust PDF engine through TypeScript/JavaScript, with both synchronous APIs for quick operations and asynchronous APIs for CPU-intensive PDF processing.
This guide walks through the practical use of pdf-inspector Node.js bindings built with napi-rs. The binding layer in napi/src/lib.rs generates automatic TypeScript definitions from annotated Rust code, giving you type-safe access to PDF classification, OCR, and region-based extraction without managing a Rust toolchain.
Installation and Setup
Pre-built binaries are distributed for every major platform through optionalDependencies in napi/package.json. A standard npm install pulls the correct binary automatically.
npm install @firecrawl/pdf-inspector
No additional build tools required. The package exports all public symbols from index.js with full type definitions in index.d.ts.
Core API Patterns
The pdf-inspector Node.js bindings follow two execution patterns defined in napi/src/lib.rs:
- Synchronous functions — Run on the Node event loop, ideal for lightweight operations like PDF classification
- Asynchronous functions — Execute on the libuv thread pool via
Taskstructs, keeping the event loop responsive during heavy OCR or multi-page processing
Synchronous vs. Asynchronous Methods
| Pattern | Functions | Use Case |
|---|---|---|
| Sync | classifyPdf, extractTextInRegions, extractTablesInRegions |
Quick checks, small PDFs |
| Async | processPdfAsync, classifyPdfAsync |
Large files, GPU OCR, production servers |
PDF Classification (Synchronous)
The classifyPdf function inspects a PDF buffer and returns type metadata without full processing. This is implemented in napi/src/lib.rs as a thin #[napi] wrapper around classify_pdf_impl.
import { classifyPdf } from '@firecrawl/pdf-inspector';
import { readFileSync } from 'fs';
const pdf = readFileSync('document.pdf');
// Synchronous classification — runs on event loop
const classification = classifyPdf(pdf);
console.log(classification.pdfType);
// "TextBased" | "Scanned" | "Mixed" | "ImageBased"
console.log(classification.pagesNeedingOcr);
// number[] — 0-based page indices requiring OCR
Full PDF Processing with OCR (Asynchronous)
For complete PDF-to-Markdown conversion with selective OCR, use processPdfAsync. This creates a ProcessPdfTask struct that copies the Buffer into Vec<u8> and executes on the thread pool.
import { processPdfAsync, OcrMode, type PdfResult } from '@firecrawl/pdf-inspector';
async function convertPdf(pdfBuffer: Buffer) {
const result: PdfResult = await processPdfAsync(pdfBuffer, {
mode: OcrMode.Selective, // Only OCR pages that need it
dpi: 300, // Render resolution for OCR
pageNumbers: [0, 1, 2], // Optional subset of pages
offline: true, // Skip model downloads
});
console.log('Markdown length:', result.markdown?.length ?? 0);
console.log('Pages with tables:', result.pagesWithTables);
console.log('OCR provenance:', result.ocrPages);
// Array of OcrPageProvenance with per-page OCR flags
}
The OcrOptions struct converts to internal pdf_inspector::vision::OcrPdfOptions via to_core_ocr_options in the binding layer.
Region-Based Text and Table Extraction
For targeted extraction from specific page regions — useful in hybrid OCR pipelines — pass arrays of PageRegions. The helper parse_page_regions in napi/src/lib.rs converts these to the Rust representation used by extract_text_in_regions_mem.
import { extractTextInRegions, type PageRegions } from '@firecrawl/pdf-inspector';
const regions: PageRegions[] = [
{
page: 0, // 0-based page index
regions: [
[0, 0, 300, 400], // bbox: [left, top, right, bottom] in PDF points
[300, 0, 612, 400], // second region on same page
],
},
{
page: 2,
regions: [[0, 0, 612, 792]], // Full page 2
},
];
const regionResults = extractTextInRegions(pdfBuffer, regions);
regionResults.forEach((pageResult) => {
pageResult.regions.forEach((region) => {
if (region.needsOcr) {
// Fall back to GPU OCR only when necessary
console.log(`Page ${pageResult.page} region needs OCR: ${region.ocrReason}`);
} else {
console.log(`Extracted: ${region.text}`);
}
});
});
Each region returns a needsOcr flag with an ocrReason string for pipeline decision-making.
Type Definitions and Editor Support
All TypeScript definitions are auto-generated from #[napi(...)] annotations in napi/src/lib.rs. Key exported types include:
// Enums
OcrMode: 'Selective' | 'Forced' | 'Disabled'
// Result types
PdfResult: {
markdown?: string;
pagesWithTables: number[];
ocrPages: OcrPageProvenance[];
}
// Region types
PageRegions: {
page: number;
regions: Array<[number, number, number, number]>;
}
RegionResult: {
bbox: [number, number, number, number];
text: string;
needsOcr: boolean;
ocrReason?: string;
}
Architecture Reference
Understanding the source structure helps with debugging and advanced usage:
| Path | Purpose |
|---|---|
napi/src/lib.rs |
NAPI binding layer — enums, structs, sync/async functions, conversion helpers |
src/lib.rs |
Core Rust PDF processing, classification, OCR routing |
src/vision/* |
PDFium rendering, ONNX Runtime OCR, model downloads |
src/extractor/* |
Text extraction, position handling, structure-tree utilities |
All NAPI functions delegate to implementations in the src/ directory. Async variants wrap these in Task structs for thread pool execution.
Summary
- Install with
npm install @firecrawl/pdf-inspector— pre-built binaries require no Rust toolchain - Use synchronous APIs (
classifyPdf,extractTextInRegions) for quick, lightweight operations - Use asynchronous APIs (
processPdfAsync) to keep the event loop responsive during OCR - Control OCR behavior through
OcrOptionswithmode,pageNumbers,dpi, andofflineparameters - Extract from specific regions with
PageRegionsarrays and checkneedsOcrflags for hybrid pipelines - Type definitions are auto-generated from
napi/src/lib.rsand fully supported inindex.d.ts
Frequently Asked Questions
What Node.js versions are supported?
The napi-rs build in napi/src/lib.rs targets N-API version guarantees. Pre-built binaries cover Node.js 16, 18, 20, and 22 across Windows, macOS, and Linux (x64 and ARM64). Check napi/package.json for the specific napi version used in your installed release.
Can I use this with Bun or Deno?
The package exports standard CommonJS and ESM modules from index.js. Bun compatibility has been tested; Deno requires Node.js compatibility mode. The napi-rs native addon loads through standard Node-API interfaces that alternative runtimes increasingly support.
How do I handle PDFs that fail classification?
classifyPdf returns PdfType classification and an array of pages needing OCR. For edge cases, fall back to processPdfAsync with OcrMode.Forced to bypass classification heuristics and run OCR on all pages, or inspect pagesNeedingOcr and process those pages individually through region-based extraction.
Why does my async function hang?
Ensure you're await-ing processPdfAsync or handling the returned Promise. The Task implementation in napi/src/lib.rs moves the PDF buffer to a thread pool worker—if the main thread blocks waiting for completion without proper async handling, the event loop stalls. Always use await or .then() in async contexts.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →