<!-- BusyBot node reference — https://busybot.net/tools/read-pdf/ -->

> Node: Read PDF (`read_pdf`) · Action (binary) · v1
> Category: Core Nodes · Credentials: none
> Updated: 2026-08-16

# Read PDF

> Extract text and metadata from PDF files

## Overview

The Read PDF tool reads a PDF binary from an input item, extracts all text content page by page, and outputs document metadata (page count, info dictionary, XMP metadata) along with the extracted text. Supports password-protected/encrypted PDFs. The original binary is forwarded on the output item so downstream nodes can still access the PDF file. Uses pdfjs-dist (Mozilla PDF.js) for parsing.

**Category:** Core Nodes  
**Tool Name:** `read_pdf`  
**Version:** 1

**Appearance:** Icon: `lucide-FileText` | Color: `#003355`

## Node Type

**Action (Binary)** — handles file/binary data operations

## Input / Output

| Direction | Port(s) |
|-----------|--------|
| Input | `Input` |
| Output | `Output`, `Error` |

## Credentials

This tool does not require any credentials.

### Parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| Binary Property | `string` | Yes | `data` | Name of the binary property containing the PDF file to extract text from. Names are case-sensitive — see the upstream node's Binary Data panel for the exact names to use. |
| Password | `string` | No | — | Password to decrypt the PDF if it is encrypted/password-protected. Leave empty for non-encrypted PDFs. |
| Max Pages | `number` | No | `0` | Maximum number of pages to extract text from. Set to 0 to extract all pages. |
| Join Pages | `boolean` | No | `true` | Whether to join text from all pages into a single string separated by double newlines (true), or return an array of per-page text strings (false). |
| Keep Source | `options` | No | `both` | What data from the input item to keep on the output. "json" merges input JSON with extracted data, "binary" forwards binary, "both" does both. |
| | | | | Options: `json`, `binary`, `both` |
| Max Concurrency | `number` | No | `10` | Maximum number of items to process concurrently. |

## Output Data

One output item per input item. The extracted data is merged into the item JSON at the top level:

```json
{
  "numpages": 12,
  "numrender": 12,
  "info": {
    "Title": "Quarterly Report",
    "Author": "Dana Whitfield",
    "CreationDate": "D:20260731094500Z"
  },
  "metadata": {
    "dc:title": "Quarterly Report"
  },
  "text": "Page one text…\n\nPage two text…",
  "version": "4.2.67"
}
```

- `numpages` — the total number of pages in the document.
- `numrender` — how many pages were actually read. Lower than `numpages` when Max Pages limited the run or the text cap was reached.
- `info` — the PDF info dictionary (title, author, producer, creation date and so on), or `null` when the document has none.
- `metadata` — the document's XMP metadata as a flat object, when present.
- `text` — the extracted text. A single string with pages separated by blank lines when **Join Pages** is on, or an array with one string per page when it is off.
- `version` — the version of the PDF engine that parsed the file.
- `isScanned` — added and set to `true` when the document has pages but yielded no text at all, which means the PDF is image-only and needs OCR.
- `_warning` — added when the result is partial or empty: either the extracted text hit its size cap, or nothing could be extracted.

**Keep Source** decides what survives from the input item:

| Value | Output JSON | Output binary |
|-------|-------------|---------------|
| `both` | Input item JSON merged with the extracted fields | The item's binary is forwarded unchanged, including the PDF |
| `json` | Input item JSON merged with the extracted fields | The source PDF property is removed; any other binary properties are kept |
| `binary` | Only the extracted fields — the input JSON is dropped | The item's binary is forwarded unchanged |

Where a name collides, the extracted field wins over the input field.

Reference the text downstream by expression, e.g. `{{ $json.text }}`.

## Usage Examples

- Extract all text from a PDF document
- Read a password-protected PDF
- Extract text from the first 5 pages of a large PDF
- Get PDF metadata like author, title, and page count
- Parse uploaded PDF and get per-page text as an array

## Example Configuration

Extract everything from a PDF attached as `data`:

```json
{
  "type": "read_pdf",
  "parameters": {
    "binaryPropertyName": "data",
    "maxPages": 0,
    "joinPages": true,
    "keepSource": "both"
  }
}
```

Read only the first five pages, one string per page:

```json
{
  "type": "read_pdf",
  "parameters": {
    "binaryPropertyName": "data",
    "maxPages": 5,
    "joinPages": false,
    "keepSource": "json"
  }
}
```

Open an encrypted PDF:

```json
{
  "type": "read_pdf",
  "parameters": {
    "binaryPropertyName": "invoice",
    "password": "letmein",
    "keepSource": "both",
    "maxConcurrency": 4
  }
}
```

### Error Handling

| Mode | Behavior |
|------|----------|
| **stop** | Halts workflow on first error |
| **continue** | Skips failed items, passes successful ones through |
| **errorPort** | Routes failed items to Error output port |

## Tips

Extract text and metadata from PDF binary data — supports encrypted PDFs, page limiting, and per-page text output.

### Behavior notes

- **Scanned PDFs return no text.** A document made of page images produces empty `text`, `isScanned: true` and a warning. Run it through an OCR tool instead of retrying here.
- **Password errors are explicit.** An encrypted PDF with no Password fails with "PDF is password-protected"; a wrong one fails with "PDF password is incorrect". Neither is retried.
- **Max Pages `0` is not unlimited.** With no limit set, extraction stops after 1,000 pages; documents over 10,000 pages are refused outright. Set Max Pages when you only need the front matter — it is much faster on long documents.
- **There are size caps.** Files over 100 MB are rejected before parsing, and extraction stops once the collected text passes 50 MB, returning a partial result with `_warning` set.
- **The PDF stays attached** unless you set Keep Source to `json`, so you can extract text and still upload or archive the original file later in the workflow.