# PDF Merger & Splitter: Merge, Split, Extract Pages (`data-done-right/pdf-merger-splitter`) Actor

PDF merger and PDF splitter for URLs: merge PDF files in order, split PDF every N pages or by ranges, extract pages from PDF, rotate and reverse pages. Password-protected PDFs supported. Every result gets a direct download link, page count and size.

- **URL**: https://apify.com/data-done-right/pdf-merger-splitter.md
- **Developed by:** [Data Done Right](https://apify.com/data-done-right) (community)
- **Categories:** Automation, Developer tools
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.20 / 1,000 pdf output files

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## PDF Merger & Splitter: Merge PDF Files, Split PDF, Extract Pages

This Actor is a **PDF merger and PDF splitter** for automations and AI agents. Give it PDF links (or PDF records from an Apify key-value store) and it will **merge PDF files** into one, **split a PDF** by page count, page ranges or one file per page, **extract pages from a PDF**, **rotate** pages, or **reverse** the page order. Every result PDF is saved and returned with a **direct download link**, its page count and its size.

It works on public URLs and on your own files, handles **password-protected PDFs** when you supply the password, and never lets one bad file stop the rest of the run.

### What can it do

| Operation | What you get |
|---|---|
| **merge** | All input PDFs joined, in the order you list them, into **one** PDF. Optional page range per file, e.g. `1-3,5`. |
| **split** | Each input PDF cut into several PDFs: **every N pages**, **by page ranges** (`1-3,4-6,7-`), or **one file per page**. |
| **extract** | A new PDF with only the pages you name, per input file. The order you write is kept, so `5,1-3` also reorders pages. |
| **rotate** | Selected pages (or all) turned 90, 180 or 270 degrees clockwise. |
| **reverse** | The same PDF with its pages in reverse order. |

### How to merge PDF files

```json
{
  "operation": "merge",
  "urls": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
    "https://pdfobject.com/pdf/sample.pdf"
  ],
  "filePageRanges": ["", ""],
  "outputFileName": "bundle.pdf"
}
```

Files are merged in the order of `urls`. Use `filePageRanges` to take only some pages of a file (one entry per URL, empty = all pages). If any input cannot be downloaded or opened, **nothing is merged** and the row names the failing file, so you never get a silently incomplete PDF. Turn on `skipBadFiles` to merge the readable files instead; skipped ones are listed in `warnings`.

### How to split a PDF

```json
{ "operation": "split", "splitMode": "everyN", "splitEvery": 10,
  "urls": ["https://www.irs.gov/pub/irs-pdf/fw9.pdf"] }
```

- `splitMode: "everyN"` with `splitEvery`: a 45-page file with N=10 gives 5 PDFs.
- `splitMode: "ranges"` with `pageRanges: "1-3,4-6,7-"`: each comma-separated range becomes its own PDF (use `+` to join pages in one file, e.g. `1+9`).
- `splitMode: "eachPage"`: one PDF per page.

Output names look like `fw9_part-001.pdf`, `fw9_part-002.pdf`.

### How to extract pages from a PDF

```json
{ "operation": "extract", "pageRanges": "6,1-2", "urls": ["https://www.irs.gov/pub/irs-pdf/fw9.pdf"] }
```

Page ranges: `5` (one page), `1-3`, `4-` (page 4 to the end), `last`, `5-1` (pages 5 down to 1), combined with commas. A page outside the file gives a clear error for that file, e.g. "page 12 is outside this PDF, which has 10 pages".

### How to rotate or reverse PDF pages

`{"operation": "rotate", "rotateAngle": "90", "pageRanges": "2-4", "urls": [...]}` rotates only pages 2 to 4 (leave `pageRanges` empty for all pages). `{"operation": "reverse", "urls": [...]}` reverses the page order.

### Password-protected PDFs

Add the `password` input (stored as a secret). It is tried on every file; for a different password per file, give the URL as an object when you call the Actor by API: `{"url": "https://...", "pages": "1-2", "password": "..."}`. A missing or wrong password gives a clear error for that file only. The Actor **never tries to crack or guess passwords**. Results are saved **without** encryption.

### Use your own files (key-value store)

Set `keyValueStoreId` to one of your key-value stores and list `recordKeys` (for example PDFs saved by another Actor). They are added after the URLs, in order.

### Output

One dataset row per result PDF (and one `failed` row per input that could not be processed):

```json
{
  "fileName": "merged.pdf",
  "url": "https://api.apify.com/v2/key-value-stores/.../records/0001-merged.pdf?signature=...",
  "pages": 2,
  "bytes": 28020,
  "sourceFiles": ["https://www.w3.org/.../dummy.pdf", "https://pdfobject.com/pdf/sample.pdf"],
  "operation": "merge",
  "status": "ok",
  "error": null,
  "kvKey": "0001-merged.pdf",
  "pageRange": null,
  "warnings": null
}
```

`url` is a **signed link that downloads without an API token**. Result PDFs are stored in the run's key-value store, which Apify deletes after your plan's data-retention period; set `keyValueStoreName` to keep them in a named store. Problems are also collected in a `FAILED` record.

### How much does it cost

**$0.004 per result PDF** (pay per event `pdf-output`). A merge counts as one, a split into 5 parts counts as five. Failed inputs are free. There is no start fee and no per-page fee. `maxOutputFiles` (default 100) caps the cost of a run, and the Actor stops cleanly if your spending limit is reached. Platform usage is small: a typical job runs for a few seconds.

### Limits (honest)

- Input files are downloaded with a hard cap (`maxFileSizeMb`, default 50, max 500) and `maxPagesPerFile` (default 1000). Larger files fail with a clear message.
- The Actor changes page structure only: it does not compress, OCR, flatten forms or add watermarks. Interactive form fields, bookmarks and links that point to pages left out may not survive a split or extract. Document title and author are kept for single-file operations.
- It does not crack passwords, and it does not read pages behind a login (use a direct PDF link).
- Scanned PDFs are merged and split fine (pages are copied as they are); text is not extracted.

### FAQ

**How do I merge PDF files online without uploading them manually?**
List their public URLs (or key-value store record keys) in `urls`, run the Actor, and download the merged PDF from the `url` field.

**Can I merge only some pages of each PDF?**
Yes. Use `filePageRanges`, for example `["1-3,5", "", "2-"]` for three files.

**How do I split a PDF into single pages?**
Use `operation: "split"` with `splitMode: "eachPage"`. You get one PDF per page (and one charge per page file).

**Does it work with password-protected PDFs?**
Yes, if you provide the password. The result is saved without a password. Without the right password, that file fails with an error and the other files are still processed.

**Is there a file size limit?**
Default 50 MB per input file, up to 500 MB, set by `maxFileSizeMb`. Memory is 1 GB by default, so very large merges may need more memory.

**Can I call it from code or an AI agent?**
Yes: use the Apify API, the Apify client libraries, or the Apify MCP server. The input is plain JSON, and the output includes ready-to-use download links.

### Related tools

- **Extract Zip Files**: unzip archives and pull attachments out of emails and PDFs.
- **PDF to Text & OCR**: turn PDF pages into text, including scanned documents.
- **Bulk File Downloader**: download many files from a list of links before you merge them.

# Actor input Schema

## `operation` (type: `string`):

What to do. merge = join all files into one PDF (in the order given). split = cut each file into several PDFs (see Split mode). extract = keep only the pages in 'Page ranges' as one new PDF per file. rotate = turn pages by 90/180/270 degrees. reverse = reverse the page order.

## `urls` (type: `array`):

Direct links to PDF files, in the order they should be merged. Example: https://example.com/a.pdf. For merge, add a page range per file in 'Page range per file'. Each item may also be an object like {"url": "https://example.com/a.pdf", "pages": "1-3,5", "password": "..."} when you call the Actor by API.

## `filePageRanges` (type: `array`):

Optional. For merge: which pages to take from each file, in the same order as the URLs. One entry per file; leave an entry empty for all pages. Example: 1-3,5 takes pages 1, 2, 3 and 5; 4- takes page 4 to the end; 5-1 takes pages 5 down to 1.

## `pageRanges` (type: `string`):

Used by extract, rotate, reverse and split (by ranges). Example: 1-3,5 (pages 1 to 3 and page 5), 4- (page 4 to the end), last, 5-1 (pages 5 down to 1). Extract keeps the order you write, so 5,1-3 also reorders pages. Rotate: leave empty to rotate every page. Split by ranges: each comma-separated range becomes its own PDF (1-3,4-6,7- makes three files; join pages with +, e.g. 1+9).

## `splitMode` (type: `string`):

How 'split' cuts each file: every N pages, by page ranges, or one PDF per page.

## `splitEvery` (type: `integer`):

For split mode 'Every N pages': pages per output file. Example: 10 turns a 45-page PDF into 5 files (the last has 5 pages).

## `rotateAngle` (type: `string`):

For the rotate operation: clockwise angle added to the selected pages.

## `outputFileName` (type: `string`):

File name of the merged PDF. Example: contract-bundle.pdf

## `skipBadFiles` (type: `boolean`):

Off (default): if any input cannot be downloaded or opened, nothing is merged and the row says which file failed, so you never get a silently incomplete PDF. On: merge the readable files and list the skipped ones in 'warnings'.

## `password` (type: `string`):

Opens password-protected PDFs (the same password is tried on every file; you can also set a password per file with the object form of the URL list). Wrong or missing passwords give a clear error for that file. Passwords are never cracked or guessed. Results are saved without encryption.

## `keyValueStoreId` (type: `string`):

Optional. Read PDF records from one of your Apify key-value stores (for example the output of another Actor). Used together with 'Record keys'.

## `recordKeys` (type: `array`):

Optional. Keys of PDF records in the input key-value store, added after the URLs. Example: invoice-001.pdf

## `maxOutputFiles` (type: `integer`):

Stop after this many result PDFs. Also caps the cost (one charge per result file).

## `maxFileSizeMb` (type: `integer`):

Input files larger than this are not downloaded (reported as failed).

## `maxPagesPerFile` (type: `integer`):

Input PDFs with more pages are rejected.

## `keyValueStoreName` (type: `string`):

Optional. Keep the result PDFs in this named store (kept until you delete it) instead of the run's default store (deleted after your plan's data retention period).

## `proxyConfiguration` (type: `object`):

Only needed if the PDF host blocks datacenter IPs.

## Actor input object example

```json
{
  "operation": "merge",
  "urls": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
    "https://pdfobject.com/pdf/sample.pdf"
  ],
  "splitMode": "everyN",
  "splitEvery": 10,
  "rotateAngle": "90",
  "outputFileName": "merged.pdf",
  "skipBadFiles": false,
  "maxOutputFiles": 100,
  "maxFileSizeMb": 50,
  "maxPagesPerFile": 1000,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All result items of this run (the default dataset), as JSON, CSV, Excel and more.

## `records` (type: `string`):

Key-value store records: the run summary, notes on any problems, and any files.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "urls": [
        "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
        "https://pdfobject.com/pdf/sample.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("data-done-right/pdf-merger-splitter").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "urls": [
        "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
        "https://pdfobject.com/pdf/sample.pdf",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("data-done-right/pdf-merger-splitter").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "urls": [
    "https://www.w3.org/WAI/ER/tests/xhtml/testfiles/resources/pdf/dummy.pdf",
    "https://pdfobject.com/pdf/sample.pdf"
  ]
}' |
apify call data-done-right/pdf-merger-splitter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,data-done-right/pdf-merger-splitter"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/j8OZ4lgfK9xza6dUC/builds/hf6LhsA0dhbGLtQfw/openapi.json
