anydoc: Convert Any Office Document to Clean Markdown in Milliseconds

anydoc is a fast Rust library that converts Word, PowerPoint, Excel, PDF, and more to clean Markdown. With Node.js, Python, and WASM bindings, it's the fastest and most complete converter available.

anydoc: Convert Any Office Document to Clean Markdown in Milliseconds

If you've ever tried to feed a .docx or .pptx file into an LLM, you know the pain. Most converters are slow, produce messy output, or only support a handful of formats. Firecrawl's anydoc aims to solve this once and for all: a pure Rust library that converts Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV, and PDF into clean GitHub-Flavored Markdown (GFM) in under 5 milliseconds per document.

Built by the team behind Firecrawl, anydoc is the engine that powers Firecrawl Parse. It's now open source, with bindings for Node.js, Python, and WebAssembly, plus an Agent Skill so your AI agents can read documents natively.

Why anydoc?

The problem with existing document-to-Markdown converters is threefold:

  1. Speed: LibreOffice takes over a second per document. anydoc does it in 4.4 ms median.
  2. Format coverage: Most tools support only a few formats. anydoc handles 14 different formats out of the box.
  3. Consistency: Each converter has its own quirks. anydoc funnels everything through a single document model, so output is uniform across all formats.

In their benchmark against six other converters (LibreOffice, unstructured, markitdown, pandoc, docling, mammoth), anydoc scored highest on every format it supports and was 10x faster than the next-fastest tool.

Getting Started

CLI

The quickest way to try anydoc is via npx:

npx @firecrawl/anydoc report.docx # Markdown to stdout
npx @firecrawl/anydoc slides.pptx -o slides.md # or to a file
npx @firecrawl/anydoc - --format csv < data.csv # read stdin

For a permanent install:

npm install -g @firecrawl/anydoc

Node.js

npm install @firecrawl/anydoc
import { toDocument, toMarkdown, toMarkdownBytes } from '@firecrawl/anydoc';

// From a file path:
const markdown = await toMarkdown('report.docx');

// From bytes, with format auto-detected:
const fromBytes = await toMarkdownBytes(bytes);

// Or specify the format explicitly (needed for CSV):
const fromCsv = await toMarkdownBytes(bytes, 'csv');

// Or get the document model with embedded assets:
const document = await toDocument(bytes);

Python

pip install firecrawl-anydoc
import anydoc

markdown = anydoc.to_markdown("report.docx")
markdown = anydoc.to_markdown_bytes(data)
markdown = anydoc.to_markdown_bytes(data, "csv")
document = anydoc.to_document(data)

WebAssembly (Browser)

npm install @firecrawl/anydoc-wasm
import init, { toMarkdownBytes, toDocument } from '@firecrawl/anydoc-wasm';
await init();
const markdown = toMarkdownBytes(bytes);

Rust

cargo add anydoc
let markdown = anydoc::to_markdown("report.docx")?;
let markdown = anydoc::to_markdown_bytes(&bytes, None)?;
let markdown = anydoc::to_markdown_bytes(&bytes, anydoc::Format::Csv)?;
let document = anydoc::to_document(&bytes, None)?;

Features That Matter

Full Document Structure

anydoc preserves everything you'd expect from a rich document:

  • Headings with anchors
  • Bold, italic, strikethrough
  • Inline code and code blocks
  • Links and internal cross-references
  • Bulleted, numbered, nested, and task lists (with original numbering)
  • Tables with merged cells and header rows
  • Block quotes
  • Footnotes and endnotes
  • Speaker notes (from PowerPoint)

Embedded Assets

Images and embedded objects are rendered as alt text in Markdown, but the raw bytes are available on the document model, tagged with their media type. External images become standard Markdown images.

Content-Based Format Detection

Instead of relying on file extensions, anydoc reads the actual bytes to detect the format: PDF header, RTF open group, OLE stream names, ZIP package mimetype. This means mislabeled files still convert correctly.

PDF Support Built In

Text-based PDFs are converted locally using pdf-inspector โ€” no OCR service required. For scanned PDFs, you'd need Firecrawl's hosted API with OCR models.

Agent-Ready

anydoc ships as an Agent Skill:

npx skills add firecrawl/anydoc

This works with Claude Code, Codex, Cursor, OpenCode, and other compatible agents.

Benchmark: anydoc vs. the Rest

Here's how anydoc compares to other popular converters on 100 real-world documents across 14 formats (scores out of 100, higher is better):

Tool Formats Median ms Score Completeness Structure Formatting Cleanliness
anydoc 14/14 4.4 81 87 79 78 81
libreoffice 12/14 1129.5 40 59 42 40 24
unstructured 8/14 572.9 63 76 59 51 63
markitdown 6/14 134.8 65 78 66 60 52
pandoc 5/14 102.1 56 74 57 56 38
docling 4/14 513.6 57 60 60 57 51
mammoth 1/14 52.5 70 84 71 75 51

Per-format, anydoc wins or ties on every single format. For example, on .docx it scores 88 vs. mammoth's 70, and on .pptx it's 74 vs. markitdown's 66.

The benchmark uses an LLM judge (Claude Sonnet 5) to compare outputs blind against ground truth images of the first six pages. Each pair is judged twice to cancel position bias, totaling 482 verdicts.

How It Works

anydoc's architecture is elegant: every format parser outputs to a shared document model, which then goes through a single GFM serializer. This means fixes to one format automatically apply to all others.

document bytes
โ”‚
โ”œโ”€โ–บ format detection โ†’ content markers, not the extension
โ”‚
โ”œโ”€โ–บ format parser โ†’ one per format (doc, docx, ppt, pptx, xls,
โ”‚ xlsx, odt/ods/odp, rtf, epub, csv)
โ”‚ โ”‚
โ”‚ โ””โ”€โ–บ Document โ†’ shared model: blocks, inlines, tables,
โ”‚ footnotes, assets
โ”‚ โ”‚
โ”‚ โ””โ”€โ–บ GFM serializer โ†’ Markdown
โ”‚
โ””โ”€โ–บ PDF โ†’ pdf-inspector โ†’ Markdown directly

Error Handling

anydoc returns a ConvertError with specific variants:

  • Unsupported โ€“ Unknown format or image-only PDF
  • Malformed โ€“ Structurally unusable file
  • Encrypted โ€“ Password-protected
  • ResourceLimit โ€“ Crossed safety limits (decompression, nesting, etc.)
  • MissingPart โ€“ Required part absent
  • Io โ€“ File read error (only from to_markdown)

In Node and WASM, the variant is on error.code; in Python, there's a subclass per variant.

Development

anydoc is open source (MIT) and actively developed. You can run tests, contribute, or just explore the codebase:

cargo test
cd node && npm install && npm run build && npm test
cd python && pip install maturin && maturin develop && python -m unittest discover -s tests

The repo includes a fixture corpus with snapshot tests, mutation tests, and fuzz targets per format.

Conclusion

If you're building a pipeline that ingests office documents and needs clean, structured Markdown for LLMs, anydoc is a game-changer. It's fast, comprehensive, and consistent. Whether you use it via CLI, Node.js, Python, or in the browser, it's the best tool we've seen for this job.

Try the live demo in your browser โ€” files are processed locally via WebAssembly, so nothing leaves your machine.

Source

firecrawl/anydoc: Convert Word, PowerPoint, Excel, OpenDocument, RTF, EPUB, CSV, and PDF to clean Markdown. Built in Rust, with Node.js and Python bindings.