SafePaper is built so your PDFs are processed in your browser, not on SafePaper servers. The sections below explain this in plain language.
Hosting & delivery
- The site is a Next.js (App Router) application. Production is static HTML, JavaScript bundles, CSS, and assets—served like any modern front-end (e.g. on Vercel).
- There is no Route Handler, no
pages/api, and no server action that accepts your PDF for processing. We do not operate an upload endpoint for document bodies.
Runtime (your machine)
- UI is React 19 + TypeScript, styled with Tailwind CSS, with motion via Framer Motion where noted in the interface.
- Dropped files are read with the browser File API into
ArrayBuffer / Uint8Array and kept in client-side React state (a shared provider across tool pages in one visit). The visible queue is also mirrored to sessionStorage when it fits browser limits so a refresh in the same tab can restore filenames and bytes without contacting a server. - Heavy merge, split, organize, compress, crop (CropBox and multi-region PDF exports), and redact PDF output runs in a dedicated Web Worker (
pdf-operations.worker.ts, compress-pdf.worker.ts, bookmarks-outline.worker.ts, extract-embedded-images.worker.ts, crop-pdf.worker.ts) so the main UI thread stays responsive. Buffers are passed with postMessage + Transferable where supported to avoid extra copies. - Organize's optional duplicate-page scan runs in
pdf-duplicate-pages.worker.ts with pdf.js + OffscreenCanvas—still only on your device.
Security Vault
- Security Vault (
/security) runs JWT decode, hashing, AES file encrypt, key generation, TOTP, bcrypt, and Shamir sharing with Web Crypto and jose in your tab only. - Optional site analytics and the consent banner are disabled on Security Vault routes even if you opted in elsewhere—so secrets pasted here are not on pages that load Vercel Analytics.
Share Desk (peer-to-peer)
- Share Desk (
/share) transfers files with WebRTC data channels directly between two browsers. SafePaper does not store or process file bytes on our infrastructure. - A separate WebSocket signaling service (configured via
NEXT_PUBLIC_SIGNALING_URL) relays SDP offers/answers and ICE candidates so peers can find each other. That relay carries connection metadata only—not your file contents. - Large receives stream into OPFS via
opfs-writer.worker.ts so the main UI thread stays responsive. Senders read files in 64KB slices with data-channel backpressure. - Peers may use Google's public STUN (
stun:stun.l.google.com:19302) to discover network paths. Optional TURN env vars (NEXT_PUBLIC_TURN_URL, etc.) can relay traffic on restrictive networks—that is separate third-party network traffic, not a SafePaper file upload.
PDF stack
- Structural PDF work (merge order, page extraction, rotation, removal) runs in the worker path described above.
- Optional password protection applies AES-256 encryption on the main thread after the worker returns bytes, using the browser's Web Crypto API. Your open password is not sent to any server.
- Previews and raster export (PNG images and plain-text extraction) use a canvas-based PDF renderer in a separate worker. The preview worker script is served as static
/pdf.worker.mjs from this site. CMaps, standard font metrics, ICC profiles, and WASM helpers for pdf.js live under /pdfjs/ (copied from pdfjs-dist on npm install) so workers can fetch glyph data from the same origin. - That preview worker is separate from the merge/split/organize worker; both use Web Workers and stay entirely on your device.
Network & storage
- Over the wire you should see requests for the app shell, JS chunks, CSS, fonts (next/font self-hosted subsets), icons, the PDF preview worker script, and (after
npm install) same-origin OCR assets under /tesseract/—not outbound uploads of your document to SafePaper for processing. - Downloads use normal browser mechanisms (
Blob / URL.createObjectURL) initiated by you. - We do not persist your PDFs to SafePaper storage; lifetime is in-memory for that tab session (and the shared client state resets when you leave the tool area for the home page).
Tool-by-tool: where work runs
| Tool / area | PDF bytes | Extra network |
|---|
| Merge, split, organize, protect | Browser + workers | App shell only |
| Compress, redact, clean | Browser + workers | App shell only |
| Export (PNG / JPEG / text) | Browser (pdf.js canvas) | App shell only |
| Forms, watermark, page #, insert | Browser (pdf-lib) | App shell only |
| OCR | Browser (pdf.js + Tesseract) | Same-origin WASM/worker/lang after postinstall (no third-party OCR CDN) |
| Duplicate scan (Organize) | Browser worker (pdf.js) | App shell only |
| Share Desk (P2P) | Browser WebRTC + OPFS worker | Signaling WebSocket + STUN (optional TURN) — no file bytes to SafePaper |
“App shell only” means HTML/JS/CSS/fonts and static assets from your host—no SafePaper API that accepts PDF bodies. A production service worker precaches the home page, PDF preview worker, and vendored OCR files for calmer offline reloads after the first visit.
Offline & limits
- After the app has loaded once, cached bundles mean the core tools can keep working offline for files already held in memory—subject to browser cache eviction.
- Practical limits are those of the device: available RAM, CPU, and browser tab limits. Malicious PDFs are still a local execution concern the same way opening a file in any desktop viewer is; we do not add a separate server-side malware scan because files never leave your machine for our processing.
Design rule
Zero server uploads for PDF work. New tools are expected to follow the same model: browser-first, worker offload where needed, and no silent exfiltration of document bytes to SafePaper infrastructure.