---
title: "How to convert PDF to Markdown in Python"
canonical_url: "https://www.nutrient.io/blog/how-to-convert-pdf-to-markdown-using-python/"
md_url: "https://www.nutrient.io/blog/how-to-convert-pdf-to-markdown-using-python.md"
last_updated: "2026-09-02T16:30:24.327Z"
description: "Convert a PDF to Markdown in Python with the Nutrient DWS Processor API — a tutorial covering LLM ingestion and text workflows."
---

**TL;DR**

Convert a PDF to Markdown in Python by sending the file to the Nutrient DWS Processor API `/build` endpoint with `output.type` set to `markdown`. Markdown output gives LLMs and text pipelines clean, structured text instead of the PDF format’s fixed layout. This tutorial covers the request, page selection, scanned PDFs, and when to use the Data Extraction API instead.

Markdown is the format most large language models (LLMs) and static-site tools read best: plain text with lightweight structure for headings, lists, and tables. PDFs carry that structure visually but not semantically, so feeding a raw PDF to an LLM or a search index usually loses it. Converting a PDF to Markdown restores a clean, machine-readable version of the document.

This tutorial converts a PDF to Markdown in Python using the [Nutrient DWS Processor API](https://www.nutrient.io/guides/dws-processor/tools-and-api/pdf-to-markdown-api.md). For an agentic, no-code path, the [PDF-to-Markdown skill](https://www.nutrient.io/ai/skills/pdf-to-markdown/) and the [DWS MCP Server workflow](https://www.nutrient.io/blog/teaching-llms-to-read-pdfs.md) cover the same conversion from Claude.

## Prerequisites

- Python 3.8 or higher

- The `requests` library

- A Nutrient DWS Processor API key (a [free account](https://dashboard.nutrient.io/sign_up/?product=processor) includes 50 credits per month)

## Step 1 — Get an API key

Create a [free Nutrient account](https://dashboard.nutrient.io/sign_up/?product=processor) and copy the API key from the dashboard.

## Step 2 — Install requests

Install the `requests` library:

```bash

python -m pip install requests

```

Place the source PDF in the working directory and name it `document.pdf`.

## Step 3 — Convert the PDF to Markdown

Create `convert.py` and add the following code. It posts the PDF to the `/build` endpoint, sets the output type to `markdown`, and streams the result to `result.md`:

```python

import sys

import requests
import json

response = requests.request(
  'POST',
  'https://api.nutrient.io/build',
  headers = {
    'Authorization': 'Bearer your_api_key_here'
  },
  files = {
    'file': open('document.pdf', 'rb')
  },
  data = {
    'instructions': json.dumps({
      'parts': [
        {
          'file': 'file'
        }
      ],
      'output': {
        'type': 'markdown'
      }
    })
  },
  stream = True
)

if response.ok:
  with open('result.md', 'wb') as fd:
    for chunk in response.iter_content(chunk_size=8192):
      fd.write(chunk)
else:
  print(response.text)
  sys.exit(1)

```

Replace `your_api_key_here` with the key from Step 1.

## Step 4 — Run the script

Run the script:

```bash

python convert.py

```

The API returns the Markdown, and the script writes it to `result.md` in the working directory.

For a document with a heading, a paragraph, and a cleanly structured table, `result.md` looks like this:

```markdown

# Quarterly report

Revenue grew across all regions.

| Region | Revenue |
| ------ | ------- |
| EMEA   | $1.2M   |
| AMER   | $2.4M   |

```

Headings and lists come through as Markdown structure rather than fixed visual layout. Table fidelity depends on the source document: Cleanly structured tables convert to Markdown table syntax, while simpler or loosely formatted ones may come back as plain text rows. For guaranteed table structure — typed cells, bounding boxes, schema-shaped JSON — use the [Data Extraction API](https://www.nutrient.io/api/data-extraction-api/) instead.

### How the request works

The `/build` endpoint takes a multipart request with two fields. The `file` field carries the PDF, and the `instructions` field is a JSON object describing the job: `parts` lists the input (referenced by the form field name `file`), and `output.type` set to `markdown` selects Markdown conversion. Streaming the response writes the output without holding the whole file in memory. The API allows 100 requests per minute per API key (test keys are limited to 10 per minute). Batch large jobs and add retries with exponential backoff.

## Convert only selected pages

To convert a page range instead of the whole document, add a `pages` object to the part. Page indexes are zero-based, and the `end` value is inclusive, so the following converts the first three pages:

```json

{
  "parts": [
    {
      "file": "file",
      "pages": {
        "start": 0,
        "end": 2
      }
    }
  ],
  "output": {
    "type": "markdown"
  }
}

```

## Convert scanned PDFs

PDF-to-Markdown conversion works best with born-digital PDFs that already contain selectable text. For scanned or image-only PDFs, run optical character recognition (OCR) first to produce a searchable PDF. Then convert that result to Markdown.

The first request runs OCR with an `actions` step and no Markdown output — the response is a searchable PDF. The part’s `"file"` value must match the name of the multipart field the script uploads (`'file'` in the Step 3 script):

```python

# First request: OCR the scanned PDF into a searchable PDF.

ocr_response = requests.request(
  'POST',
  'https://api.nutrient.io/build',
  headers = {
    'Authorization': 'Bearer your_api_key_here'
  },
  files = {
    'file': open('scanned.pdf', 'rb')
  },
  data = {
    'instructions': json.dumps({
      'parts': [
        {
          'file': 'file'
        }
      ],
      'actions': [
        {
          'type': 'ocr',
          'language': 'english'
        }
      ]
    })
  }
)

if ocr_response.ok:
  with open('searchable.pdf', 'wb') as fd:
    fd.write(ocr_response.content)
else:
  print(ocr_response.text)
  sys.exit(1)

```

Then run the Step 3 script against `searchable.pdf` — the second `/build` request with `output.type` set to `markdown` completes the flow. The [PDF-to-Markdown API guide](https://www.nutrient.io/guides/dws-processor/tools-and-api/pdf-to-markdown-api.md) documents the full OCR-then-convert flow.

## When to use the Data Extraction API instead

Processor API Markdown is the right tool when Markdown is simply the output format of a conversion. For retrieval-augmented generation (RAG)-grade extraction — layout-aware structure, tables and key-value pairs, bounding boxes, schema-shaped JSON, or citations and confidence scores — use the [Data Extraction API](https://www.nutrient.io/api/data-extraction-api/). The engine tradeoffs are compared in [Document AI vs. traditional OCR](https://www.nutrient.io/blog/document-ai-vs-ocr.md).

[Start a free trial](https://www.nutrient.io/try/)

[Talk to our team](https://www.nutrient.io/contact-sales/)

## FAQ

#### Why convert a PDF to Markdown for LLMs?

Markdown is plain text with lightweight structural cues, so an LLM receives clean headings, lists, and tables instead of a fixed visual layout. This reduces parsing errors and hallucinations compared with feeding a raw PDF.

#### Does the Processor API convert scanned PDFs to Markdown directly?

Conversion works best on born-digital PDFs with selectable text. For scanned or image-only PDFs, run OCR first to create a searchable PDF. Then convert that result to Markdown.

#### How is this different from the Data Extraction API?

The Processor API produces Markdown as an output format in a conversion workflow. The Data Extraction API adds layout-aware, RAG-grade extraction — typed elements, tables, bounding boxes, schema-shaped JSON, and confidence scores.

#### Can only part of a PDF be converted?

Yes. Add a zero-based `pages` range to the part. The `end` value is inclusive, so a range of 0–2 converts the first three pages.

For the no-code and agentic paths to the same conversion, refer to our blog about [teaching LLMs to read PDFs](https://www.nutrient.io/blog/teaching-llms-to-read-pdfs.md) and the [PDF-to-Markdown skill](https://www.nutrient.io/ai/skills/pdf-to-markdown/).
---

## Related pages

- [The business case for accessibility: Five ways it drives enterprise value](/blog/5-ways-accessibility-drives-enterprise-value.md)
- [Accessibility Untangled Why It Matters Guide](/blog/accessibility-untangled-why-it-matters-guide.md)
- [Advanced Techniques For React Native Ui Components](/blog/advanced-techniques-for-react-native-ui-components.md)
- [`vector_store` holds your indexed documents (see the multimodal RAG post](/blog/agentic-rag.md)
- [How to build an AI agent for contract redlining against a compliance playbook](/blog/ai-contract-redlining-compliance-playbook.md)
- [Ai Document Automation Extraction To Action](/blog/ai-document-automation-extraction-to-action.md)
- [Ai Legal Assistant Document Authoring](/blog/ai-legal-assistant-document-authoring.md)
- [Amazon Textract Alternatives](/blog/amazon-textract-alternatives.md)
- [Start (clears any prior buffer), navigate the document, then stop into a file.](/blog/android-faster-pdf-rendering.md)
- [Android Pdf Out Of Memory Handling](/blog/android-pdf-out-of-memory-handling.md)
- [Angular File Viewer Pdf Image Office Files](/blog/angular-file-viewer-pdf-image-office-files.md)
- [Auto Tagging And Document Accessibility In Dotnet Sdk](/blog/auto-tagging-and-document-accessibility-in-dotnet-sdk.md)
- [Simple PII redaction.](/blog/automated-pii-removal.md)
- [Best Ai Document Workflow Platforms](/blog/best-ai-document-workflow-platforms.md)
- [Best Document Ai Platforms](/blog/best-document-ai-platforms.md)
- [Best Document Classification Platforms](/blog/best-document-classification-platforms.md)
- [Best document parser for RAG: LlamaParse vs. Unstructured vs. Reducto vs. Nutrient](/blog/best-document-parser-llamaparse-unstructured-reducto.md)
- [Best Document Parsing Apis](/blog/best-document-parsing-apis.md)
- [Best Document Viewers](/blog/best-document-viewers.md)
- [Best Multilingual Ocr Software](/blog/best-multilingual-ocr-software.md)
- [Best Secure Document Collaboration Platforms](/blog/best-secure-document-collaboration-platforms.md)
- [Build Vs Buy Document Extraction](/blog/build-vs-buy-document-extraction.md)
- [Business Automation](/blog/business-automation.md)
- [The CEO’s AI playbook: Why decision architecture beats model selection](/blog/ceo-ai-playbook-decision-architecture.md)
- [1. Extract and chunk the PDF.](/blog/chat-with-pdf.md)
- [Complete Guide To Pdfjs](/blog/complete-guide-to-pdfjs.md)
- [Construction Document Data Extraction](/blog/construction-document-data-extraction.md)
- [Convert One Drive Files To Pdf In Sharepoint](/blog/convert-one-drive-files-to-pdf-in-sharepoint.md)
- [Create And Edit Pdfs In Flutter](/blog/create-and-edit-pdfs-in-flutter.md)
- [Create Pdfs With React](/blog/create-pdfs-with-react.md)
- [Creating A Document Scanner With Ocr In Python](/blog/creating-a-document-scanner-with-ocr-in-python.md)
- [Creating And Filling Pdf Forms Programmatically In Javascript](/blog/creating-and-filling-pdf-forms-programmatically-in-javascript.md)
- [The CTO’s AI playbook: Why accountability architecture beats orchestration](/blog/cto-ai-playbook-accountability-architecture.md)
- [Digital Signatures](/blog/digital-signatures.md)
- [Digital Workflow Automation](/blog/digital-workflow-automation.md)
- [Document Ai Vs Ocr](/blog/document-ai-vs-ocr.md)
- [Document Extraction Confidence Scores](/blog/document-extraction-confidence-scores.md)
- [Document Viewer](/blog/document-viewer.md)
- [Document Watermarking](/blog/document-watermarking.md)
- [Emerging threats: Your logging system may be an agentic threat vector](/blog/emerging-threats-your-logging-system.md)
- [Extend Alternatives](/blog/extend-alternatives.md)
- [Extract Patient Data On Premises](/blog/extract-patient-data-on-premises.md)
- [app.py](/blog/extract-text-from-pdf-using-python.md)
- [Fillable Pdf](/blog/fillable-pdf.md)
- [How To Add Digital Signature To Pdf Using React](/blog/how-to-add-digital-signature-to-pdf-using-react.md)
- [How To Build A Dotnet Maui Pdf Viewer](/blog/how-to-build-a-dotnet-maui-pdf-viewer.md)
- [How To Build A Flutter Pdf Viewer](/blog/how-to-build-a-flutter-pdf-viewer.md)
- [or](/blog/how-to-build-a-javascript-pdf-viewer-with-pdfjs.md)
- [How To Build A Javascript Pdf Viewer](/blog/how-to-build-a-javascript-pdf-viewer.md)
- [or](/blog/how-to-build-a-nextjs-pdf-viewer.md)
- [How To Build A Powerpoint Viewer Using Javascript](/blog/how-to-build-a-powerpoint-viewer-using-javascript.md)
- [Using Yarn](/blog/how-to-build-a-react-excel-viewer.md)
- [How To Build A React Native Pdf Viewer](/blog/how-to-build-a-react-native-pdf-viewer.md)
- [How To Build A React Powerpoint Viewer](/blog/how-to-build-a-react-powerpoint-viewer.md)
- [How To Build A Reactjs File Viewer](/blog/how-to-build-a-reactjs-file-viewer.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer-with-react-pdf.md)
- [or](/blog/how-to-build-a-reactjs-pdf-viewer.md)
- [How To Build A Reactjs Viewer With Pdfjs](/blog/how-to-build-a-reactjs-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer With Pdfjs](/blog/how-to-build-a-vuejs-pdf-viewer-with-pdfjs.md)
- [How To Build A Vuejs Pdf Viewer](/blog/how-to-build-a-vuejs-pdf-viewer.md)
- [How To Build An Android Pdf Viewer](/blog/how-to-build-an-android-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Ng2 Pdf Viewer](/blog/how-to-build-an-angular-pdf-viewer-with-ng2-pdf-viewer.md)
- [How To Build An Angular Pdf Viewer With Pdfjs](/blog/how-to-build-an-angular-pdf-viewer-with-pdfjs.md)
- [How To Convert Docx To Pdf Using Javascript](/blog/how-to-convert-docx-to-pdf-using-javascript.md)
- [How To Convert Docx To Pdf Using Python](/blog/how-to-convert-docx-to-pdf-using-python.md)
- [How To Convert Html To Pdf Using Html2pdf](/blog/how-to-convert-html-to-pdf-using-html2pdf.md)
- [or](/blog/how-to-convert-html-to-pdf-using-react.md)
- [How To Convert Html To Pdf Using Wkhtmltopdf And Csharp](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-csharp.md)
- [or](/blog/how-to-convert-html-to-pdf-using-wkhtmltopdf-and-python.md)
- [How To Convert Html To Pptx](/blog/how-to-convert-html-to-pptx.md)
- [How To Convert Word To Pdf In Nodejs](/blog/how-to-convert-word-to-pdf-in-nodejs.md)
- [or](/blog/how-to-create-a-react-js-signature-pad.md)
- [How To Create Pdfs With React To Pdf](/blog/how-to-create-pdfs-with-react-to-pdf.md)
- [How To Edit Pdfs Using Ios Pdf Library](/blog/how-to-edit-pdfs-using-ios-pdf-library.md)
- [How To Embed A Pdf Viewer In Your Website](/blog/how-to-embed-a-pdf-viewer-in-your-website.md)
- [How To Extract Tables From Pdf And Images](/blog/how-to-extract-tables-from-pdf-and-images.md)
- [How To Generate Pdf From Html With Nodejs](/blog/how-to-generate-pdf-from-html-with-nodejs.md)
- [base_url tells WeasyPrint where to resolve relative asset paths](/blog/how-to-generate-pdf-reports-from-html-in-python.md)
- [How To Merge Pdfs Using Javascript](/blog/how-to-merge-pdfs-using-javascript.md)
- [How To Ocr Pdfs In Linux](/blog/how-to-ocr-pdfs-in-linux.md)
- [How To Print Pdf In Csharp](/blog/how-to-print-pdf-in-csharp.md)
- [How To Programmatically Create And Fill Pdf Form In Angular](/blog/how-to-programmatically-create-and-fill-pdf-form-in-angular.md)
- [Open an image.](/blog/how-to-use-tesseract-ocr-in-python.md)
- [From an HTML string.](/blog/html-in-pdf-format.md)
- [Html To Pdf In Javascript](/blog/html-to-pdf-in-javascript.md)
- [Javascript Document Editor](/blog/javascript-document-editor.md)
- [Javascript Pdf Editors](/blog/javascript-pdf-editors.md)
- [Javascript Pdf Libraries](/blog/javascript-pdf-libraries.md)
- [Langextract Vs Llamaindex Extraction Comparison](/blog/langextract-vs-llamaindex-extraction-comparison.md)
- [Linearized Pdf](/blog/linearized-pdf.md)
- [Llamaparse Alternatives](/blog/llamaparse-alternatives.md)
- [Low Code No Code Document Integrations](/blog/low-code-no-code-document-integrations.md)
- [or](/blog/merge-pdfs.md)
- [Swift Package Manager](/blog/mobile-pdf-sdk.md)
- [`elements` come from your document parser — each has a type and content.](/blog/multimodal-rag.md)
- [Nutrient Flutter 6 Bindings Api](/blog/nutrient-flutter-6-bindings-api.md)
- [Nutrient Flutter Bindings Architecture](/blog/nutrient-flutter-bindings-architecture.md)
- [Nutrient Vs Conga Composer](/blog/nutrient-vs-conga-composer.md)
- [Online Document Viewer](/blog/online-document-viewer.md)
- [Open Pdf In Your Web App](/blog/open-pdf-in-your-web-app.md)
- [Building WCAG 2.2, Section 508, and PDF/UA-compliant PDFs with an SDK](/blog/pdf-accessibility.md)
- [Extract data from PDF files: A developer guide to structured data from PDFs and scans](/blog/pdf-data-extraction-developer-guide.md)
- [Pdf Extraction Benchmark Opendataloader Bench](/blog/pdf-extraction-benchmark-opendataloader-bench.md)
- [Pdf Extraction Document Case Studies](/blog/pdf-extraction-document-case-studies.md)
- [Pdf Page Labels](/blog/pdf-page-labels.md)
- [Pdf Sdk Compliance Security Checklist](/blog/pdf-sdk-compliance-security-checklist.md)
- [Pdf Sdk Performance Benchmark](/blog/pdf-sdk-performance-benchmark.md)
- [Pdf Ua Compliance Guide](/blog/pdf-ua-compliance-guide.md)
- [Pdfjs Accessibility Structtree Printing](/blog/pdfjs-accessibility-structtree-printing.md)
- [Pdfjs Advanced Loading Streaming Workers](/blog/pdfjs-advanced-loading-streaming-workers.md)
- [Pdfjs Annotation Editor Layer](/blog/pdfjs-annotation-editor-layer.md)
- [Pdfjs Area Annotations Canvas Capture](/blog/pdfjs-area-annotations-canvas-capture.md)
- [Pdfjs Coordinate Systems Pdf To Screen](/blog/pdfjs-coordinate-systems-pdf-to-screen.md)
- [Pdfjs Document Outline Bookmarks Metadata](/blog/pdfjs-document-outline-bookmarks-metadata.md)
- [Pdfjs Eventbus Guide](/blog/pdfjs-eventbus-guide.md)
- [macOS](/blog/pdfjs-file-format-conversion-to-pdf.md)
- [macOS](/blog/pdfjs-generating-pdf-thumbnails-pdf2pic.md)
- [Pdfjs Limitations Commercial Upgrade](/blog/pdfjs-limitations-commercial-upgrade.md)
- [Pdfjs Native Annotation Layer Forms](/blog/pdfjs-native-annotation-layer-forms.md)
- [Pdfjs Navigation Zoom Rotation](/blog/pdfjs-navigation-zoom-rotation.md)
- [Pdfjs Pdf Page Manipulation Pdf Lib](/blog/pdfjs-pdf-page-manipulation-pdf-lib.md)
- [Pdfjs React Viewer Setup](/blog/pdfjs-react-viewer-setup.md)
- [Pdfjs Rendering Overlays React Portals](/blog/pdfjs-rendering-overlays-react-portals.md)
- [Pdfjs Server Side Text Extraction](/blog/pdfjs-server-side-text-extraction.md)
- [Pdfjs Sticky Note Annotations](/blog/pdfjs-sticky-note-annotations.md)
- [Pdfjs Text Highlight Annotations](/blog/pdfjs-text-highlight-annotations.md)
- [Pdfjs Text Search Pdffindcontroller](/blog/pdfjs-text-search-pdffindcontroller.md)
- [Pdfjs Thumbnail Sidebar](/blog/pdfjs-thumbnail-sidebar.md)
- [Process Flows](/blog/process-flows.md)
- [React Native Pdf Annotation](/blog/react-native-pdf-annotation.md)
- [React Pdf Annotation Layer Forms](/blog/react-pdf-annotation-layer-forms.md)
- [Using Yarn](/blog/react-pdf-editor.md)
- [React Pdf Loading States Errors Passwords](/blog/react-pdf-loading-states-errors-passwords.md)
- [React Pdf Setup Basic Rendering](/blog/react-pdf-setup-basic-rendering.md)
- [React Pdf Text Layer Custom Renderer](/blog/react-pdf-text-layer-custom-renderer.md)
- [React Pdf Thumbnails Page Navigation](/blog/react-pdf-thumbnails-page-navigation.md)
- [Reducto Alternatives](/blog/reducto-alternatives.md)
- [Requisition System](/blog/requisition-system.md)
- [labels.py](/blog/route-documents-automatically-classify-api.md)
- [or](/blog/sample-blog-updated.md)
- [Sdk Product Updates Q2 2026](/blog/sdk-product-updates-q2-2026.md)
- [Add DWS MCP Server to your Claude Code project.](/blog/teaching-llms-to-read-pdfs.md)
- [Open an image file.](/blog/tesseract-python-guide.md)
- [Define the HTML part of the document.](/blog/top-10-ways-to-generate-pdfs-in-python.md)
- [Top 5 Javascript Pdf Viewers](/blog/top-5-javascript-pdf-viewers.md)
- [or](/blog/top-js-pdf-libraries.md)
- [Convert an HTML file to PDF.](/blog/top-ten-ways-to-convert-html-to-pdf.md)
- [Vector Pdf](/blog/vector-pdf.md)
- [Wcag2 Accessibility Requirements Documents](/blog/wcag2-accessibility-requirements-documents.md)
- [Web Sdk Is Now Headless](/blog/web-sdk-is-now-headless.md)
- [What Are Annotations](/blog/what-are-annotations.md)
- [What Is A Vpat](/blog/what-is-a-vpat.md)
- [What Is Document Processing](/blog/what-is-document-processing.md)
- [What Is Intelligent Document Processing](/blog/what-is-intelligent-document-processing.md)
- [What Is Pdf Ua](/blog/what-is-pdf-ua.md)
- [Why Pdfium Is A Trusted Platform For Pdf Rendering](/blog/why-pdfium-is-a-trusted-platform-for-pdf-rendering.md)
- [Why Your Ai Agent Hallucinates Pdf Table Data](/blog/why-your-ai-agent-hallucinates-pdf-table-data.md)

