The open-source alternative to Adobe Acrobat, Smallpdf and iLovePDF — your documents never leave your machine. openpdfedit.com
A fast, local-first PDF editor with a Rust core. One engine, one interface, six ways to run it: in a browser, as a desktop app, as a browser extension, on iOS, from a shell, or over MCP. Documents are rendered, edited, and saved entirely on your machine; nothing is uploaded.
The interface speaks eight languages: English, 简体中文, 繁體中文, 日本語, 한국어, Deutsch, Español and Português. Pick one from the globe in the toolbar; the choice is remembered.
Features: view (tiled rendering, zoom/scroll) · annotate (highlight, underline, strikeout, notes, ink, shapes) with comment threads · undo/redo · incremental save (original bytes preserved; existing digital signatures survive annotation edits) · AcroForm fill and field creation · page organization (rotate, delete, reorder, crop, extract, merge) · redaction (true content removal) · signature list/placement · text-run and image editing · watermark (tiled text/logo stamps, 0°/45°, opacity, band or full-page) · document compare (text + pixel diff) · OCR (tesseract.js, in the page, twelve languages) · optional OpenApps account panel.
Two of those are paid. Watermark and OCR are the Supporter tools: 1,000 credits once, for both together, and that is the only charge anywhere in the product. Signing in is needed for those two and for nothing else — everything else on the list is free, with no account.
What crosses the network. Nothing you open does, with or without an account: every page is rendered, edited and saved on your machine. The one exception is the OCR engine itself. In the web app it is fetched on first use of OCR — the WebAssembly core and the one language you asked for, a few megabytes, from openpdfedit.com, the same origin that served the app — and recognition is offline from then on. The desktop and iOS builds carry those files inside the bundle and fetch nothing at all, and the extension ships without OCR.
Open openpdfedit.com/app. That is the whole of it — same engine, same interface, nothing installed.
| Where | How to get it | State |
|---|---|---|
| Web | openpdfedit.com/app | Live, and always the newest build — nothing to install or update |
| macOS | OpenPdfEdit_<version>_aarch64.dmg |
Apple Silicon. Ad-hoc signed; see below for the first-run warning |
| Windows | OpenPdfEdit_<version>_x64-setup.exe |
x64 installer |
| Windows (Store) | — | An MSIX is built by msix.yml, with a separate product identity from the .exe so the two install side by side. Not submitted to the Microsoft Store yet |
| Browser extension | openpdfedit-dist.zip, loaded unpacked |
Chrome 103+, Edge and other Chromium browsers. Not on a store yet: publish-edge.yml can only replace the package of a product that already exists, and the first submission has to be made by hand. Not Firefox: MV3 differs enough to need its own build |
| iOS | — | Built and runnable from Xcode; not yet on the App Store |
| CLI | apps/cli |
Headless batch operations, no browser and no PDFium |
| MCP | apps/mcp |
Exposes the engine to an MCP client |
The web app is the one to reach for first. It is the same Svelte interface on the same WebAssembly engine as the extension, it needs no install, and it cannot fall behind — which the desktop app can, and does, if nobody downloads a new build.
What the desktop app adds over the web app: native file dialogs, and saving over the original — with a recents list that survives a relaunch — always, where the web app can only do either in the Chromium browsers that implement the File System Access API.
OCR is no longer one of those differences. It used to shell out to a
tesseract binary found on the customer's PATH, so it ran only for
people who had installed one themselves and could never run inside the
Mac App Store's sandbox. Both now recognise with tesseract.js in the
page, so OCR works everywhere, and everything after recognition was
always the same Rust. What changed is the engine and where it runs, not
what it costs: OCR is still a Supporter tool, with watermark.
Artifacts are attached to each
GitHub Release,
built by release.yml on every v*
tag; the newest is always at
/releases/latest.
A tag with a hyphen in it (v1.0.1-rc1) is a release candidate — the
same artifacts, marked pre-release. Nothing reaches a store from a tag
either way: both store workflows are workflow_dispatch only, so
publishing is always a deliberate act.
Releases from v0.1.11-rc2 update themselves. The macOS and Windows
builds check for a new version on launch and offer to install it, which
is what the latest.json and .sig assets in a release are for — a
release without them cannot be offered as an update. v0.1.10 and
earlier have to be downloaded by hand, and so does rc1.
The .dmg carries an ad-hoc signature — a real signature, but not one
tied to an Apple Developer ID, and not notarized. Both of those need a
paid Apple Developer account. The ad-hoc signature is what stops macOS
calling the download "damaged"; what it can't stop is the weaker
warning, "Apple could not verify OpenPdfEdit is free of malware." To
get past that once:
System Settings → Privacy & Security → scroll to the message about OpenPdfEdit → Open Anyway. Or, from a terminal:
xattr -dr com.apple.quarantine /Applications/OpenPdfEdit.appTo remove the warning entirely, set APPLE_CERTIFICATE,
APPLE_CERTIFICATE_PASSWORD, APPLE_SIGNING_IDENTITY, APPLE_ID,
APPLE_PASSWORD and APPLE_TEAM_ID as repository secrets — the release
workflow already picks them up and notarizes when they're all present,
and falls back to ad-hoc signing when they aren't.
If you instead see "OpenPdfEdit is damaged and can't be opened", you have v0.1.2 or earlier. That build shipped with a broken signature — the app bundle was never sealed — and macOS reports a broken signature as "damaged". The command above clears it, and releases after v0.1.2 are fixed properly.
A ready-to-load build is committed at
apps/extension/openpdfedit-dist.zip:
- Unzip it somewhere.
chrome://extensions(oredge://extensions) → enable Developer mode → Load unpacked → pick the unzipped folder.- Click the OpenPdfEdit icon and open a PDF.
Requires Chrome 103+ or any Chromium browser of that vintage — Edge and
Brave included. Rebuilding it yourself: see
apps/extension/README.md (needs Rust with
the wasm32-unknown-unknown target and wasm-bindgen-cli pinned to the
version in Cargo.toml; npm run package reproduces the zip).
Prerequisites: Rust (stable), Node 20+, and the platform's Tauri prerequisites (https://tauri.app/start/prerequisites/).
scripts/fetch-pdfium.sh # downloads the PDFium binary for your OS
cd apps/desktop
npm install
npm run tauri dev # run itInstallers: scripts/build-dmg.sh (macOS .dmg),
scripts/build-installer.ps1 (Windows).
cd apps/webapp && npm run build # -> apps/webapp/distIt is the desktop Svelte app built with BASE_PATH=/app and the
WebAssembly backend, which is why there is no separate source tree for
it. scripts/deploy-webapp.sh ships that dist and then checks what
the origin is actually serving, rather than trusting that rsync exited
zero.
cargo test --workspace # Rust suites (uses .vendor/pdfium)
cd apps/extension && npm run e2e # Playwright against the packaged buildapps/desktop/vendor/openapps/holds prebuilt copies of@openapps/sdkand@openapps/ui(the OpenApps account/credits components), vendored so this repository installs standalone. They live underapps/desktopdeliberately: Vite resolves their bare imports (lit) by walking up from the real file path, and only there does the walk-up reachapps/desktop/node_modules. Their source lives in the OpenApps monorepo.- The marketing site is not in this repository. It lives in
openpdfedit-website, which is private: this repo is the app, and the website — the page, the privacy policy, the SEO metadata, the deploy scripts — is not part of the open-source product. The app still builds from here into/app/, andscripts/deploy-webapp.shships it. docs/carries the design/research notes and implementation plans the project was built against;PLAN.mdis the live milestone log.
AGPL-3.0-or-later. Read it, run it, change it, share it. The one condition that matters: if you build on this code and hand the result to anyone — as a download or as a website people use over a network — that version has to be open too, under the same licence. Using it yourself, inside a company or for research, obliges you nothing.
Two parts of the tree are not under it, and say so themselves:
apps/mcp is LicenseRef-Proprietary, and the vendored OpenApps
packages under apps/desktop/vendor/openapps stay MIT OR Apache-2.0,
which is their own licence and is compatible with this one.
Releases up to and including 1.0.1 were published under MIT OR Apache-2.0, and that grant cannot be withdrawn: any copy of those commits stays permissively licensed for whoever holds it, forever. The change applies from the next version onward. It brings this repository in line with OpenCapture and OpenTabs, which have been AGPL from the start.