1. Quick Start
MarkItDown is a lightweight Python utility by Microsoft that converts various file formats to Markdown, purpose-built for LLMs and text analysis pipelines. It preserves document structure including headings, lists, tables, and links while producing clean, token-efficient Markdown output.
Key features:
- Converts PDF, Word (.docx), PowerPoint (.pptx), Excel (.xlsx/.xls), HTML, CSV, JSON, XML, images, audio, EPub, Outlook messages (.msg), and ZIP archives
- Fetches and converts YouTube video transcripts and Wikipedia articles from URLs
- Supports Azure Document Intelligence for advanced document extraction
- Extensible plugin system for third-party format converters
- MCP (Model Context Protocol) server for integration with LLM applications
- LLM-powered image descriptions and OCR via optional plugins
- Reads from files, URLs, stdin, or Python streams
Prerequisites: Python 3.10 or higher
Install and run:
pip install 'markitdown[all]'
markitdown document.pdf
# Document Title
Content extracted from your PDF as clean Markdown...
Tip
For a quick one-liner that converts and saves in one step:
markitdown report.pdf -o report.md. You can also pipe from stdin:cat file.pdf | markitdown.
What to try next:
- Save output to a file — see Core Usage below
- Convert content from a URL — see the Python API section
- Use MarkItDown as a Python library — see Python API
- Set up the MCP server for LLM integration — see MCP Server
2. Installation
System Requirements
| Requirement | Minimum | Recommended |
|---|---|---|
| Python | 3.10 | 3.12 or 3.13 |
| OS | Linux, macOS, Windows | Any |
| RAM | 256 MB | 512 MB+ for large PDFs |
Install via pip
Tip
The recommended installation uses
[all]to include every optional dependency. If you only need specific format support, install individual extras to keep your environment lean.
pip install 'markitdown[all]'
Verify the installation:
markitdown --version
markitdown 0.1.6b2
Install Specific Format Support
Instead of installing all dependencies, you can choose only what you need:
pip install 'markitdown[pdf, docx, pptx]'
| Extra | Formats Enabled | Dependencies Installed |
|---|---|---|
[all] |
All formats below | Everything |
[pdf] |
PDF files | pdfminer.six, pdfplumber |
[docx] |
Word documents | mammoth, lxml |
[pptx] |
PowerPoint presentations | python-pptx |
[xlsx] |
Excel spreadsheets (.xlsx) | pandas, openpyxl |
[xls] |
Legacy Excel (.xls) | pandas, xlrd |
[outlook] |
Outlook messages (.msg) | olefile |
[audio-transcription] |
WAV, MP3 audio | pydub, SpeechRecognition |
[youtube-transcription] |
YouTube video transcripts | youtube-transcript-api |
[az-doc-intel] |
Azure Document Intelligence | azure-ai-documentintelligence, azure-identity |
Important
The extras changed between 0.0.1 and 0.1.0. If you are upgrading from an earlier version, switch to
pip install 'markitdown[all]'to get the same all-inclusive behavior as before.
Note
The core package always includes
beautifulsoup4,requests,markdownify,magika,charset-normalizer, anddefusedxml. These handle HTML, plain text, CSV, JSON, XML, RSS, and basic web content without any extras.
Install from Source
git clone git@github.com:microsoft/markitdown.git
cd markitdown
pip install -e 'packages/markitdown[all]'
Virtual Environment Setup
Standard Python
python -m venv .venv
source .venv/bin/activate
pip install 'markitdown[all]'
uv
uv venv --python=3.12 .venv
source .venv/bin/activate
uv pip install 'markitdown[all]'
Conda
conda create -n markitdown python=3.12
conda activate markitdown
pip install 'markitdown[all]'
Docker
Build and run MarkItDown in a container:
docker build -t markitdown:latest .
docker run --rm -i markitdown:latest < ~/your-file.pdf > output.md
The Docker image is based on python:3.13-slim-bullseye and includes ffmpeg and exiftool for audio and image metadata extraction.
Install Troubleshooting
Error: No module named 'pdfminer' when converting PDFs
You installed MarkItDown without the PDF extra. Install it:
pip install 'markitdown[pdf]'
Error: No module named 'pptx' when converting PowerPoint files
Install the PowerPoint extra:
pip install 'markitdown[pptx]'
Error: pip install fails with version conflicts
Use a clean virtual environment:
python -m venv .venv-markitdown
source .venv-markitdown/bin/activate
pip install 'markitdown[all]'
Error: markitdown: command not found after installation
Ensure your Python scripts directory is on your PATH. If you installed in a virtual environment, make sure it is activated.
Error: Python version too old
MarkItDown requires Python 3.10+. Check your version:
python --version
If you have multiple Python versions, use python3.12 or the full path to a supported Python installation.
Error: magika installation fails
The magika dependency requires a compatible version (~=0.6.1). If you encounter issues, try:
pip install --upgrade pip
pip install 'markitdown[all]'
3. Configuration
MarkItDown is designed to work with zero configuration. All behavior is controlled through command-line flags or Python API parameters at runtime.
Environment Variables
| Variable | Purpose | Default |
|---|---|---|
EXIFTOOL_PATH |
Path to the exiftool binary for image/audio metadata |
Auto-detected from well-known paths |
MARKITDOWN_ENABLE_PLUGINS |
Enable third-party plugins in the MCP server | false |
Note
If
exiftoolis installed in a standard location (/usr/bin,/usr/local/bin,/opt/homebrew/bin,C:\Program Files, etc.), MarkItDown finds it automatically. You only needEXIFTOOL_PATHif it is installed in a non-standard location.
For full configuration details including Azure Document Intelligence setup and LLM integration, see the Administrator & Developer Guide.
4. Core Usage
Command-Line Interface
The markitdown command converts a file and writes Markdown to stdout:
markitdown example.pdf
CLI Flags
| Flag | Description |
|---|---|
<filename> |
File to convert (optional; reads from stdin if omitted) |
-o, --output |
Write output to a file instead of stdout |
-v, --version |
Show version number and exit |
-x, --extension |
Hint about file extension (useful when reading from stdin) |
-m, --mime-type |
Hint about the file's MIME type |
-c, --charset |
Hint about the file's character encoding (e.g., UTF-8) |
-d, --use-docintel |
Use Azure Document Intelligence instead of offline conversion |
-e, --endpoint |
Azure Document Intelligence endpoint URL (required with -d) |
-p, --use-plugins |
Enable third-party plugins for conversion |
--list-plugins |
List installed third-party plugins and exit |
--keep-data-uris |
Keep base64-encoded data URIs in output (truncated by default) |
Save to File
Use -o or shell redirection:
markitdown report.pdf -o report.md
markitdown report.pdf > report.md
Read from stdin
Pipe content or redirect files:
cat document.pdf | markitdown
markitdown < document.pdf
Tip
When reading from stdin, MarkItDown uses
magikato detect the file type automatically. If detection fails, provide a hint with--extension:cat mystery-file | markitdown --extension .pdf
Converting URLs
MarkItDown can fetch and convert content directly from URLs via the Python API:
from markitdown import MarkItDown
md = MarkItDown()
result = md.convert("https://example.com/document.pdf")
print(result.markdown)
Supported URI schemes: http:, https:, file:, and data:.
Note
When fetching URLs, MarkItDown sends an
Acceptheader that prefers Markdown:text/markdown, text/html;q=0.9, text/plain;q=0.8, */*;q=0.1. Sites that support Markdown responses (like Cloudflare's markdown-for-agents) will serve Markdown directly.
Python API
Basic Conversion
from markitdown import MarkItDown
md = MarkItDown()
result = md.convert("test.xlsx")
print(result.markdown)
The convert() method accepts:
| Input Type | Example |
|---|---|
| File path (string) | md.convert("report.pdf") |
| File path (Path object) | md.convert(Path("report.pdf")) |
| URL (string) | md.convert("https://example.com/page.html") |
| Data URI (string) | md.convert("data:text/plain;base64,SGVsbG8=") |
| Binary stream | md.convert(open("file.pdf", "rb")) |
requests.Response |
md.convert(response) |
Conversion Result
The convert() method returns a DocumentConverterResult object:
result = md.convert("document.pdf")
print(result.markdown) # The converted Markdown text
print(result.title) # Optional document title (may be None)
print(str(result)) # Same as result.markdown
Note
The
text_contentproperty is a soft-deprecated alias formarkdown. New code should useresult.markdownorstr(result).
Stream Conversion
Convert binary streams directly:
from markitdown import MarkItDown, StreamInfo
md = MarkItDown()
with open("report.pdf", "rb") as f:
result = md.convert_stream(f, stream_info=StreamInfo(extension=".pdf"))
print(result.markdown)
The StreamInfo object provides hints about the stream content:
| Field | Type | Purpose |
|---|---|---|
mimetype |
str |
MIME type (e.g., application/pdf) |
extension |
str |
File extension with dot (e.g., .pdf) |
charset |
str |
Character encoding (e.g., utf-8) |
filename |
str |
Original filename |
url |
str |
Source URL |
LLM-Powered Image Descriptions
Provide an OpenAI-compatible client for AI-generated image captions:
from markitdown import MarkItDown
from openai import OpenAI
client = OpenAI()
md = MarkItDown(llm_client=client, llm_model="gpt-4o")
result = md.convert("photo.jpg")
print(result.markdown)
You can customize the prompt used for image description:
md = MarkItDown(
llm_client=client,
llm_model="gpt-4o",
llm_prompt="Describe this image in detail, focusing on any text content."
)
Important
LLM-powered descriptions require a valid OpenAI API key (or compatible API). Without an
llm_client, image conversion falls back to EXIF metadata extraction only.
Azure Document Intelligence
For high-fidelity document extraction:
from markitdown import MarkItDown
md = MarkItDown(docintel_endpoint="https://your-resource.cognitiveservices.azure.com/")
result = md.convert("complex-document.pdf")
print(result.markdown)
From the command line:
markitdown document.pdf -d -e "https://your-resource.cognitiveservices.azure.com/"
Note
Azure Document Intelligence requires an Azure subscription and a configured Document Intelligence resource. Authentication uses Azure's
DefaultAzureCredential, which checks environment variables, managed identity, and CLI login in order.
Supported Formats
| Format | Extensions | Notes |
|---|---|---|
.pdf |
Text extraction via pdfminer.six; table extraction via pdfplumber; supports form-style and borderless tables |
|
| Word | .docx |
Via mammoth; supports equations, comments, custom style maps |
| PowerPoint | .pptx |
Extracts text from slides including speaker notes |
| Excel | .xlsx |
Via pandas + openpyxl; each sheet becomes a Markdown table |
| Legacy Excel | .xls |
Via pandas + xlrd |
| CSV | .csv |
Auto-detects delimiter and encoding |
| HTML | .html, .htm |
Converts via markdownify; special handling for Wikipedia and Bing SERP pages |
| EPub | .epub |
Extracts text from e-book files |
| Images | .jpg, .jpeg, .png |
EXIF metadata extraction; optional LLM-powered descriptions |
| Audio | .mp3, .wav, .m4a |
EXIF metadata; optional speech transcription via SpeechRecognition |
| Outlook | .msg |
Extracts email content from Outlook message files |
| Jupyter | .ipynb |
Extracts code cells and outputs from notebooks |
| RSS/XML | .xml |
RSS feed content extraction |
| JSON | .json |
Rendered as formatted text |
| ZIP | .zip |
Iterates over archive contents and converts each file |
| YouTube | URL | Extracts title, description, metadata, and transcript |
| Wikipedia | URL | Special formatting for Wikipedia article pages |
Note
MarkItDown uses Google's
magikalibrary for content-type detection. Even without file extension hints, it can often identify the correct format from file content alone.
MCP Server
The markitdown-mcp package provides a Model Context Protocol server that lets LLM applications (like Claude Desktop) convert files to Markdown.
Install
pip install markitdown-mcp
Run with STDIO (default)
markitdown-mcp
Run with HTTP/SSE
markitdown-mcp --http --host 127.0.0.1 --port 3001
| Flag | Description | Default |
|---|---|---|
--http |
Use Streamable HTTP and SSE transport | STDIO |
--sse |
Deprecated alias for --http |
- |
--host |
Host to bind to (only with --http) |
127.0.0.1 |
--port |
Port to listen on (only with --http) |
3001 |
The MCP server exposes one tool: convert_to_markdown(uri) which accepts http:, https:, file:, and data: URIs.
Warning
The MCP server runs with the privileges of the user who started it. It has no built-in authentication. When using
--http, it binds to localhost by default. Do not bind to non-localhost interfaces unless you understand the security implications — any process on the network could use the server to read files accessible to that user.
Claude Desktop Integration
Build the Docker image and configure claude_desktop_config.json:
docker build -t markitdown-mcp:latest packages/markitdown-mcp/
{
"mcpServers": {
"markitdown": {
"command": "docker",
"args": ["run", "--rm", "-i", "markitdown-mcp:latest"]
}
}
}
To mount a local directory for file access:
{
"mcpServers": {
"markitdown": {
"command": "docker",
"args": [
"run", "--rm", "-i",
"-v", "/home/user/data:/workdir",
"markitdown-mcp:latest"
]
}
}
}
Enable Plugins in MCP Server
Set the MARKITDOWN_ENABLE_PLUGINS environment variable:
MARKITDOWN_ENABLE_PLUGINS=true markitdown-mcp
5. Common Tasks
Convert a PDF and Save to File
markitdown report.pdf -o report.md
Batch Convert All PDFs in a Directory
for f in *.pdf; do
markitdown "$f" -o "${f%.pdf}.md"
done
Convert a Web Page
from markitdown import MarkItDown
md = MarkItDown()
result = md.convert("https://example.com/blog-post.html")
with open("blog-post.md", "w") as f:
f.write(result.markdown)
Extract YouTube Transcript
from markitdown import MarkItDown
md = MarkItDown()
result = md.convert("https://www.youtube.com/watch?v=dQw4w9WgXcQ")
print(result.markdown)
Note
YouTube transcript extraction requires the
[youtube-transcription]extra:pip install 'markitdown[youtube-transcription]'
Convert Excel Spreadsheet to Markdown Tables
from markitdown import MarkItDown
md = MarkItDown()
result = md.convert("data.xlsx")
print(result.markdown)
Each sheet in the workbook is converted to a separate Markdown table.
Get Image Descriptions with AI
from markitdown import MarkItDown
from openai import OpenAI
client = OpenAI()
md = MarkItDown(llm_client=client, llm_model="gpt-4o")
result = md.convert("screenshot.png")
print(result.markdown)
Convert with Custom DOCX Style Mapping
from markitdown import MarkItDown
md = MarkItDown(style_map="p[style-name='Heading 1'] => h1:fresh")
result = md.convert("custom-styled.docx")
print(result.markdown)
Process All Files in a ZIP Archive
markitdown archive.zip
MarkItDown automatically iterates over ZIP contents and converts each supported file.
Convert Outlook Email to Markdown
from markitdown import MarkItDown
md = MarkItDown()
result = md.convert("message.msg")
print(result.markdown)
Use MarkItDown with OCR Plugin
from markitdown import MarkItDown
from openai import OpenAI
md = MarkItDown(
enable_plugins=True,
llm_client=OpenAI(),
llm_model="gpt-4o",
)
result = md.convert("scanned-document.pdf")
print(result.markdown)
Important
The OCR plugin (
markitdown-ocr) must be installed separately:pip install markitdown-ocr. It requires an OpenAI-compatible LLM client. Withoutllm_client, the plugin loads but OCR is silently skipped, falling back to the standard converter.
Convert from a Data URI
import base64
from markitdown import MarkItDown
md = MarkItDown()
data = base64.b64encode(b"Hello, World!").decode()
result = md.convert(f"data:text/plain;base64,{data}")
print(result.markdown)
Use MarkItDown in a Pipeline
curl -s https://example.com/document.pdf | markitdown --extension .pdf > output.md
6. Troubleshooting
Diagnostic Decision Tree
- Is MarkItDown installed? Run
markitdown --version - Is the file format supported? Check the Supported Formats table in Core Usage
- Is the required optional dependency installed? Check the extras table in Installation
- Is the file corrupted? Try opening it in its native application
Error: Could not convert stream to Markdown. No converter attempted a conversion
Cause: The file format is not supported or was not recognized.
Solution:
- Check that the file extension matches the actual format
- Provide explicit hints:
markitdown file --extension .pdf --mime-type application/pdf - Verify the format is in the supported formats list
Prevention: Always use correct file extensions. When piping from stdin, provide --extension or --mime-type hints.
Error: File conversion failed after N attempts
Cause: A converter recognized the file but failed during conversion. This wraps the underlying exceptions from individual converter attempts.
Solution:
- Check the error message for specific converter failures
- Ensure all required dependencies are installed for that format
- Try with a different file of the same type to rule out file corruption
Error: MissingDependencyException for a specific format
Cause: The optional dependency for that file format is not installed.
Solution:
pip install 'markitdown[pdf]' # Replace 'pdf' with the needed extra
The error message tells you exactly which extra to install.
Error: A one-byte document is generated with no error output
Cause: Known issue (GitHub #1784). Some files may produce minimal or empty output without raising an error.
Solution:
- Verify the file is not empty or corrupted
- Try converting with Azure Document Intelligence (
-dflag) for better extraction - Check if the file contains extractable text (scanned images in PDFs require OCR)
Warning
If you consistently get empty output for a specific file type, it may indicate a converter bug. File a GitHub issue with a sanitized sample file.
PDF Conversion Produces Poor Results
Cause: PDFs with complex layouts, scanned images, or unusual fonts may not extract well with the default converter.
Solution:
- Try Azure Document Intelligence for higher fidelity:
markitdown file.pdf -d -e "<endpoint>" - Install and use the OCR plugin for scanned documents
- For form-style PDFs, the built-in converter uses
pdfplumberfor table detection automatically
Output Contains Truncated Data URIs
Cause: By default, MarkItDown truncates base64-encoded data URIs (like embedded images) to keep output clean.
Solution: Use --keep-data-uris to preserve them:
markitdown document.html --keep-data-uris
YouTube Transcript Not Extracted
Cause: Either the youtube-transcript-api dependency is not installed, or the video has no available transcript.
Solution:
- Install the dependency:
pip install 'markitdown[youtube-transcription]' - Verify the video has captions/subtitles available
- Note that private or age-restricted videos may not expose transcripts
Warning
YouTube short URLs (
youtu.be/...) and Shorts (youtube.com/shorts/...) are not currently recognized by the YouTube converter (GitHub #1775). Use fullyoutube.com/watch?v=URLs.
Memory Issues with Large PDFs
Cause: Previously reported as a regression in version 0.1.5 (GitHub #1611, now closed/fixed). Large PDFs can consume significant memory during extraction.
Solution: The current version processes PDF pages individually and calls page.close() after each page to free memory. If you still experience issues with very large PDFs, consider splitting the PDF into smaller chunks before conversion.
7. FAQ
Q: What makes MarkItDown different from other document converters?
MarkItDown focuses on preserving document structure as Markdown specifically for consumption by LLMs and text analysis tools. Unlike high-fidelity converters designed for human readability, it prioritizes clean, token-efficient Markdown that AI systems process well.
Q: Can I convert files without installing all dependencies?
Yes. Install only the extras you need: pip install 'markitdown[pdf, docx]'. The core package handles HTML, plain text, CSV, JSON, and XML without any optional dependencies.
Q: How does file type detection work?
MarkItDown uses a multi-layered detection approach: file extension, MIME type hints, and Google's magika library for content-based detection. It generates multiple "guesses" and tries converters in priority order until one succeeds.
Q: Can I write my own converter plugin?
Yes. MarkItDown supports third-party plugins via Python's entry points system. See the packages/markitdown-sample-plugin directory for a complete example. Plugins implement the DocumentConverter interface with accepts() and convert() methods, and register via the markitdown.plugin entry point group.
Q: Does MarkItDown support Word equations?
Yes. The DOCX converter includes a math converter that handles Office MathML (OMML) and converts equations to LaTeX notation in the Markdown output.
Q: How are ZIP files handled?
MarkItDown recursively iterates over all files in a ZIP archive and attempts to convert each one. The output is the concatenation of all successfully converted files.
Q: Is there a breaking change between 0.0.1 and 0.1.0?
Yes, three important changes: (1) Dependencies are now organized into optional feature groups — use pip install 'markitdown[all]' for backward-compatible behavior. (2) convert_stream() now requires a binary file-like object (not io.StringIO). (3) The DocumentConverter class interface changed to read from streams rather than file paths, which affects plugin developers.
Q: Can I use a custom requests session for URL fetching?
Yes. Pass it to the constructor:
import requests
session = requests.Session()
session.headers.update({"Authorization": "Bearer token"})
md = MarkItDown(requests_session=session)
Q: What happens if multiple converters can handle the same file?
Converters are tried in priority order. Specific format converters (priority 0.0) are tried before generic ones like PlainText and HTML (priority 10.0). The first converter that accepts the file and successfully converts it wins.
Q: How can I debug MCP server issues?
Use the MCP Inspector tool:
npx @modelcontextprotocol/inspector
Connect to the server via STDIO, Streamable HTTP (http://127.0.0.1:3001/mcp), or SSE (http://127.0.0.1:3001/sse).