Most “free” PDF editors aren’t really free. You upload a file, fix a typo, hit download… and get a watermark or a paywall. Worse, your document lives on someone else’s server now.
I’m a builder and I needed a tool I could trust. So I made one: a 100% client-side PDF editor. No signup. No watermark. Your file never leaves your device. This post is the story — what we tried, what broke, and what finally worked.
The problem we kept hitting:
- Bait-and-switch UX: “Free” until the last click.
- Privacy risk: Uploading IDs/contracts to unknown servers isn’t acceptable for many people or companies.
- Latency and cost: Upload → process → download is slow, and server costs scale as you grow.
The obvious answer: don’t upload at all. Do the work in the browser.
**
What “client-side PDF editing” really means**
PDFs are a weird mix of vector graphics, text glyphs, images, annotations, and page transforms. In practice we needed to solve five things:
- Parse and render pages fast enough that mobile users don’t bounce.
- Edit text without wrecking layout.
- Place images/logos/stamps precisely.
- Capture signatures smoothly (mouse/touch) and embed them reliably.
- Export a clean PDF instantly, all offline.
We leaned on modern web APIs: WebAssembly, Canvas, OffscreenCanvas, Web Workers, and careful memory management. No servers required.
Text editing: “glyph runs” and white-out surgery
PDF text isn’t like a contenteditable div. It’s positioned glyph runs. Our approach:
- Detect text runs on the page.
- When the new text doesn’t match metrics exactly, place a subtle white-out rectangle behind the edited area to “erase” the old glyphs, then draw the new text on top (preserving alignment/flow).
- Support common font choices; fall back gracefully when fonts aren’t embeddable.
This was the most fragile part. Early versions had hilarious bugs: a single emoji could push a line 2px and every subsequent line went crooked. Fix: normalize metrics and snap to baselines.
Images & logos: pixels meet PDF space
Placing a PNG/JPG/WebP on a PDF page sounds simple until you remember that PDF has its own coordinate space with transforms. We convert CSS pixels → PDF user units, apply rotation/scale, and clamp to page bounds. For logos with transparency, PNG with alpha is ideal.
Signatures: feel matters
We capture pointer events, smooth the path (Catmull–Rom → cubic Beziers), and embed the result as a vector or high-res bitmap. The two things that made it feel “real”:
- Slight pressure simulation based on velocity (thicker when moving faster).
Immediate feedback at 60fps using a worker + offscreen canvas on supported browsers.
Performance: how we kept it snappy on a Moto GLazy page rendering: only draw the viewport + a small prefetch window.
Worker pool: parsing/rendering off the main thread to keep TBT ~0–30ms.
Chunked processing: stream large PDFs and free buffers aggressively.
No layout thrash: one write per frame; batch DOM updates; avoid sync measures.
Result: on mobile we see ~1.2s FCP and ~1.5s LCP for the landing UI, and edits feel instant.
Privacy & trust: rules we set for ourselves
- Default: no network calls. The editor runs locally.
- If you choose an optional cloud action later, it’s explicit and TLS-only.
No watermark, no usage caps, no “gotcha” step. We’d rather earn goodwill than convert via traps.
**
What we got wrong (so you don’t have to)**Font chaos: even when you think you embedded a font, subsetting can bite you. We added thorough fallbacks and test PDFs with non-Latin scripts.
Mobile Safari limits: large canvases + memory spikes = crashes. Fix: tile rendering and lower peak memory.
Pointer jitter: naive smoothing feels sluggish. Velocity-aware smoothing felt right.
Export size: we shipped a build that ballooned file size after multiple edits. The culprit: duplicate image XObjects. We now dedupe assets on export.
Open problems we’re still chewing on
- Full OCR for scanned PDFs (we’re evaluating on-device models).
- True find & replace across pages.
- Batch stamping (same logo on N pages in one step).
- PDF/A export for archival workflows.
If you’re building something similar, these patterns helped
- Workers everywhere. Even small parsing tasks benefit.
- One source of truth for coordinates. Don’t mix CSS pixels, device pixels, and PDF units across modules.
- Design for failure. Fonts missing? Fall back. Image corrupt? Render a placeholder and let the user continue.
- Keep promises user-visible. “No watermark” is a commitment — put it in the UI, not just the blog.
Want to try it (no pressure)
If a truly free, client-side editor is useful, you can try it here: pdffreeeditor.com.
No signup, no watermark; edit, sign, merge/split, and add images right in the browser.
I’d love feedback on edge cases (weird fonts, giant scans, RTL text). If you’ve solved similar problems in canvas/WebAssembly, please share your tricks — I’ll happily credit and implement.
— Maaz
Top comments (1)
I await your guy's feedback.