Skip to content
All posts
Engineering

Why we built Docverix in the browser

By Docverix Engineering7 min read

The default behaviour of every free Docverix tool is the same: your file never leaves the browser. Drop a PDF into Merge, run OCR on a scanned receipt, edit a .docx in the Word editor — every byte of file content stays in the tab. You can verify this yourself: open DevTools' Network panel and watch a tool run end-to-end. There's no upload.

That choice isn't aesthetic; it's the whole product. Every other free-PDF-tool site uploads first, processes server- side, and then deletes (eventually). We took the harder path deliberately, and this post is the architectural reasoning, the libraries that make it work, and the cases where we genuinely needed a server.

The case for client-side first

Three things made the call easy.

Verifiability.A privacy claim that depends on trusting the vendor is weaker than a privacy claim a user can confirm in 10 seconds. "We delete your files after 30 minutes" vs. "your file never reached our server at all" — the second one is a different category of promise. DevTools' Network panel is a verification tool every user already has installed.

Unit economics.Server-side processing has per-request cost (CPU, bandwidth, storage). For a free tool tier, that cost has to be subsidised somewhere — usually ads, quota walls, or a freemium trap. Client-side processing is O(0) marginal cost: your machine does the work. We can keep the free tier genuinely free without slipping into the conversion-pressure patterns that make Sejda's 3-tasks- per-hour or Smallpdf's 2-tasks-per-day exist.

Latency. An upload-process-download round-trip for a 10 MB PDF on a typical home connection adds 2–6 seconds before the tool can even begin working. Local processing starts when the file lands in the tab.

The OSS engine that made it possible

The browser became viable for serious document work only because a handful of open-source libraries decided to ship Web-platform versions of long-established native tools. We stand on top of five:

  • pdf-lib — pure-JS PDF creation and manipulation. Read PDFs, mutate them, write them back. Runs in any JavaScript runtime.
  • pdfjs-dist— Mozilla's PDF rendering engine. The library that powers Firefox's PDF viewer, packaged for browsers and Node.
  • tesseract.js— port of Google's Tesseract OCR engine to WebAssembly. Runs as a Web Worker; language packs lazy-load per script.
  • fabric.js — canvas-based interaction layer for the PDF editor (drag, resize, annotate, redact).
  • TipTap — ProseMirror-based rich-text editor we use for the Word editor, with custom extensions that round- trip to .docx via the docx and mammoth libraries.

Web Workers, not the main thread

PDF parsing, OCR recognition, and image encoding are CPU-bound. Running them on the main thread would jank the UI, freeze inputs, and worst case cause the tab to be killed for being "unresponsive". Every heavy primitive in Docverix runs in a Web Worker — a separate JavaScript thread with its own runtime.

The pattern for Tesseract looks like:

let runtime: typeof import("tesseract.js") | null = null;

async function getRuntime() {
  if (!runtime) runtime = await import("tesseract.js");
  return runtime;
}

const worker = await runtime.createWorker(language);

Two things worth noting. The await import() defers loading the Tesseract bundle (~5 MB compressed) until the moment a user actually starts OCR — page-load impact for someone who never uses OCR is zero. And createWorker() spawns a real OS-thread-level worker via the underlying Workers API, so the main thread stays responsive while a 50-page scan recognises in the background.

Where we made exceptions

Two flows currently route to a server, both opt-in and clearly flagged:

  • Word editor  ⌘K AI assist.When you select text and hit ⌘K, the selection (not the whole document) is sent to OpenAI for the chosen action: improve, shorten, translate, etc. We send only the selection because it's the minimum data needed for the prompt.
  • OCR "Use AI" toggle. Flipping the toggle in the OCR tool routes the file to a server-side vision model — handles hard scans (faded, handwritten, mixed- script) better than Tesseract. Quota-gated per IP; file deleted within 30 minutes; never logged with content.

What client-side cost us

The tradeoffs aren't free.

Bigger initial bundle. Shipping pdf-lib, pdfjs, fabric, and shared shells means a larger JS payload than a thin upload-form site. We mitigate with next/dynamic on the editor surfaces and await import() on every PDF helper, so the baseline page weight stays around React + Tailwind + Radix (~750 KB parsed), and the heavy libs load only when you visit a tool that needs them.

Memory ceilings.A 200 MB PDF that a server could process trivially will OOM the browser tab. We cap uploads at 25 MB in the free tier; bigger files route to the Docverix Platform's server-side processing pipeline.

Browser variance.Older browsers without WebAssembly SIMD, smaller heap caps on mobile, and one particularly noisy Safari + Tesseract interaction all needed handling. The result is the "Use desktop for the full editor" nudge on tiny mobile screens — not because the code can't run, but because the editor UI wants real screen space.

We'd still make the same call. The verifiability story alone is worth the bundle-size tax — and the cost asymmetry (us shipping bytes once vs. us paying for CPU every request) is what lets the free tier stay genuinely free.

What's next

Things on the bench: a desktop-app shell using Tauri for users whose IT teams ban web apps wholesale (Sejda Desktop style); bigger client-side file caps via streaming decoders (currently we load the whole file into memory); and the Docverix Platform's structured-extraction pipeline, which is where the server side genuinely earns its place.

If you've thought about building something similar, the short answer is: it's harder than it looks, the libraries are mature enough that it works, and the privacy posture you get back is differentiating in ways that compound over time.

Docverix Platform

Need workflow + audit on every doc your team handles?

Docverix Platform turns these tools into a routed, audited pipeline — validator → supervisor → approver, with a complete audit trail.