API Quick Reference - Five Bindings Compared
API Reference
anydoc's core API is just three things, identical across all five bindings:
| API | What it does | Returns |
|---|---|---|
toMarkdown(path) | Path-based conversion | String |
toMarkdownBytes(bytes) | Bytes-based conversion | String |
toDocument(bytes) | Stop at the document model | Structured Document (with embedded asset bytes) |
"From a path or from bytes" — and if you need embedded assets (images, etc.), stop at toDocument.
The five bindings
Rust
use anydoc::ConvertError;
// From a path
let markdown = anydoc::to_markdown("report.docx")?;
// From bytes
let bytes = std::fs::read("slides.pptx")?;
let markdown = anydoc::to_markdown_bytes(&bytes, None)?;
// Document model (keeps embedded assets)
let document = anydoc::to_document(&bytes, None)?;Install: cargo add anydoc
Node.js
import { toMarkdown, toMarkdownBytes, toDocument } from '@firecrawl/anydoc'
const markdown = await toMarkdown('report.docx')
const fromBytes = await toMarkdownBytes(bytes)
const document = await toDocument(bytes)
// Error codes: error.code ('unsupported' | 'malformed' | 'encrypted' | ...)Install: npm install @firecrawl/anydoc. Conversion runs on the libuv thread pool without blocking the event loop.
Python
import anydoc
markdown = anydoc.to_markdown("report.docx")
markdown = anydoc.to_markdown_bytes(data)
document = anydoc.to_document(data)
# Errors: exception subclasses, e.g. anydoc.UnsupportedErrorInstall: pip install firecrawl-anydoc. The GIL is released during conversion, so it plays well with asyncio and threads.
WebAssembly (browser)
import init, { toMarkdownBytes, toDocument } from '@firecrawl/anydoc-wasm'
await init() // load the wasm once
const markdown = toMarkdownBytes(bytes)
const document = toDocument(bytes)Install: npm install @firecrawl/anydoc-wasm. Conversion happens entirely in the browser — files never leave the device. The converter on this site is exactly this package.
CLI
npx @firecrawl/anydoc report.docx # print to stdout
npx @firecrawl/anydoc slides.pptx -o slides.md # write to a file
npx @firecrawl/anydoc - --format csv < data.csv # read from stdinAgent Skill
npx skills add firecrawl/anydocOnce installed, skills-protocol agents (Claude Code, Codex, Cursor, etc.) can read office documents in your project directly.
Error handling
All languages share the same ConvertError semantics:
| Variant | Meaning | What to check |
|---|---|---|
unsupported | Unknown format / scanned PDF | Verify the real format; scanned PDFs need OCR (e.g. Firecrawl Parse) |
malformed | Corrupt or structurally unusable | Re-save with the original application |
encrypted | Password-protected | Remove the password first |
resourceLimit | Crossed a safety limit (size/depth/nodes) | Split the file; confirm it isn't a zip bomb |
missingPart | Required part absent from the package | The file is incomplete — re-export |
io | Underlying I/O error (native only) | Check path, permissions, file locks |
Node.js exposes it via error.code, Python via exception subclasses, Rust by matching the ConvertError enum. (The WASM build has no io — there's no filesystem.)
Working with embedded assets
let document = anydoc::to_document(&bytes, None)?;
// Raw bytes and media types of images/objects are on the document model
// In Markdown, those positions render as alt textNeed the images on disk? Walk the model's asset nodes and write each one by its media type. This is the standard companion step in any docx-to-md pipeline.
Things to keep in mind
- Headers, footers, page numbers, and date/time placeholders are excluded in all formats — by design, not a bug
- Speaker notes are always kept — PPT speaker notes appear in the Markdown output
- External URL images become regular Markdown images; embedded images render as alt text plus model assets
- Version: the official README wins; this page tracks v0.1.8
Go deeper per language: Node.js · Python · Rust · WebAssembly · Agent Skill. Hit an error? See Error Handling & Limits.