userland.run70Try the demo
Free tool · runs in your browser · no upload

Merge, split, compress and password-protect PDFs

Pick a folder of PDF files and run pdfcpu, an open-source PDF processor, on all of them: merge them into one document, split them into single pages, optimize them, or add and remove password protection. It runs in this tab; your documents are never uploaded.

Run it on your folder

Nothing is downloaded until you press Run. Works in current Chrome, Edge, Firefox and Safari; saving straight back into the folder needs Chrome or Edge.

loading the tool…

What you can do

Merge all PDFs into one

Combines every PDF in the folder, in alphabetical order, into a single file in out/, with a bookmark per source file. Result: one merged PDF in out/.

bash
mkdir -p out && pdfcpu merge -c disable out/merged.pdf *.pdf

Split into pages

Splits each PDF into files of N pages (one page each by default) in out/split/, named after the source: report_1.pdf, report_2.pdf, … Result: page files in out/split/.

bash
mkdir -p out/split && st=0; for f in *.pdf; do [ -e "$f" ] || continue; pdfcpu split -c disable --force "$f" out/split 1 || st=1; done; exit $st

Optimize (compress)

Rewrites each PDF without duplicate fonts, images and unused objects, using compressed object streams. Writes name-optimized.pdf into out/. Result: optimized copies in out/.

bash
mkdir -p out && st=0; for f in *.pdf; do [ -e "$f" ] || continue; pdfcpu optimize -c disable "$f" "out/${f%.pdf}-optimized.pdf" || st=1; done; exit $st

Add a password

Encrypts each PDF with AES-256; the password is needed to open it. Writes name-locked.pdf into out/. Result: encrypted copies in out/.

bash
mkdir -p out && st=0; for f in *.pdf; do [ -e "$f" ] || continue; pdfcpu encrypt -c disable --upw "$PDF_PASSWORD" --opw "$PDF_PASSWORD" "$f" "out/${f%.pdf}-locked.pdf" || st=1; done; exit $st

Remove a password

Opens each password-protected PDF with the password you know and writes an unprotected copy, name-unlocked.pdf, into out/. Result: unprotected copies in out/.

bash
mkdir -p out && st=0; for f in *.pdf; do [ -e "$f" ] || continue; pdfcpu decrypt -c disable --upw "$PDF_PASSWORD" "$f" "out/${f%.pdf}-unlocked.pdf" || st=1; done; exit $st

Show document info

Prints page count, page size, PDF version, encryption and permissions for every PDF. Changes nothing. Result: a report in the output pane.

bash
pdfcpu info -c disable *.pdf

How it works

  1. Pick a folder. Choose the folder with your PDF files. They are copied into a sandbox in this browser tab, not uploaded.
  2. Choose an operation. Merge, split, optimize, add a password, remove a password, or show document info. The matching pdfcpu command appears and can be edited.
  3. Run pdfcpu. Press Run. pdfcpu, compiled to WebAssembly, processes the files and writes the results into an out/ folder.
  4. Save the results. Save out/ back into your folder, or download it as a zip file.

Under the hood the page boots NanoVM, a Linux userland compiled to WebAssembly, in this tab. Your folder is copied into its in-memory filesystem at /work, and a BusyBox shell runs the command, which starts pdfcpu on the WebAssembly (WASI) runner. The Terminal tab opens the same folder in an interactive shell, for anything the presets don’t cover.

Your files stay on your device

Your PDFs are read by your browser and copied into an in-memory filesystem inside this tab, where pdfcpu (compiled to WebAssembly) processes them. Nothing is uploaded; there is no server that could receive them.

Passwords you type are passed to pdfcpu as an environment variable for that one run. They are not part of the command line, the share link or any request.

The only network requests are for the pdfcpu program itself: a signed, content-hashed package from the jsDelivr CDN, fetched once and cached. The counter next to the Run button lists every request that leaves this site.

Questions

In which order are PDFs merged?

Alphabetically by file name, the order the shell expands *.pdf in. To choose another order, rename the files (01-cover.pdf, 02-report.pdf) or edit the command and list the files yourself.

How much smaller does optimize make a PDF?

It depends on the file. pdfcpu removes duplicate fonts and images and unused objects and writes compressed object streams, which helps most with documents assembled from many sources. It does not downsample or re-compress images, so scans stay the same size and lose no quality.

Which encryption does it use?

AES with a 256-bit key, the strongest option in the PDF standard. The same password is set as user and owner password.

Can it remove a password I don't know?

No. Removing protection needs the password that opens the document. The tool is for files you already have access to, such as removing the password from your own bank statements.

Are my PDFs uploaded?

No. pdfcpu runs as WebAssembly inside your browser tab and reads the copy of your folder held in the tab's memory. After the tool has loaded you can go offline and it keeps working.

What is pdfcpu?

An open-source PDF processor written in Go, licensed under Apache-2.0. The tool runs the unmodified pdfcpu command-line program, built for WebAssembly (WASI).

The software

program
pdfcpu 0.16.1
license
Apache-2.0
source
github.com/pdfcpu/pdfcpu
runs on
WebAssembly (wasm32-wasip1) on the host wasm engine
delivered as
a signed, content-addressed package from the NanoVM app catalog (Ed25519 + SHA-256, verified in the browser)
this page
AGPL-3.0-only OR LicenseRef-UEL · source

Build the same thing into your page

This tool is the <nano-tool> web component from the public NanoVM SDK (@userland-run/nano-sdk/tools), with the built-in pdf definition. The same element runs on any page:

html
<script type="module">
  import { defineNanoTool } from "@userland-run/nano-sdk/tools";
  defineNanoTool();
</script>
<nano-tool tool="pdf" wasm-url="/nano.wasm" terminal url-params></nano-tool>

Or headless, with the folder bridge (@userland-run/nano-sdk/folder). Definitions are plain data — presets, form fields and quoted command templates — so you can write one for any catalog app.

javascript
import { createNano } from "@userland-run/nano-sdk";
import { mountFolder } from "@userland-run/nano-sdk/folder";
import { runTool } from "@userland-run/nano-sdk/tools";

const nano = await createNano({ image: { wasm: "/nano.wasm" }, ramMB: 512 });
const dir = await showDirectoryPicker({ mode: "readwrite" });
const folder = await mountFolder(nano, dir, { at: "/work" });
// installs pdfcpu from the signed catalog, then runs:
// mkdir -p out && pdfcpu merge -c disable out/merged.pdf *.pdf
const r = await runTool(nano, { tool: "pdf", preset: "merge", folder });
if (r.exitCode === 0) await folder.writeBack(); // new and changed files only; never deletes

More tools

← All tools