You’ve probably seen the phrase before, sitting under a file picker somewhere: “runs entirely in your browser” or “your file never leaves your device.” It reads as a privacy pitch, and it usually gets a shrug — sure, okay, that sounds nice. But how does a program that removes a password from a PDF, or OCRs a scanned document, or rebuilds a corrupted file, actually run without a server involved? PDF processing isn’t trivial. Parsing the format, rewriting internal structures, running text recognition — this is real computation. Where is it actually happening?

The honest answer is: on the computer or phone in front of you, inside the browser tab you already have open, using the same kind of code that’s always powered desktop PDF software — just compiled to run somewhere new.

The mechanism: WebAssembly

For a long time, “runs in the browser” meant JavaScript, and JavaScript alone wasn’t fast or capable enough to do the heavy lifting that serious PDF processing needs — parsing complex binary structures, running an OCR model, rewriting a file’s internal object graph. That work lived on servers, written in C, C++, or Rust, because those languages compile down to fast native code.

WebAssembly (WASM) changes what “compiles down to” means. It’s a low-level binary format that browsers can execute directly, at speeds close to native code — not a scripting language, a compilation target, the same role machine code plays for a regular desktop app. Point a C or Rust compiler at WASM instead of at your operating system, and the exact same source code that would normally produce a Windows .exe or a macOS binary produces a .wasm file the browser can load and run instead.

That distinction matters here specifically. This site’s PDF repair tool doesn’t reimplement a lightweight, browser-friendly version of PDF recovery — it runs qpdf, a mature, open-source PDF engine written in C++ that real desktop and server PDF software has relied on for years, compiled to WebAssembly. Same parser, same logic for reconstructing a broken cross-reference table, same code path a command-line qpdf install on a Linux server would run. It’s just executing inside a browser tab instead of a terminal. The OCR tool on this site works the same way: it runs Tesseract, a long-established open-source OCR engine, compiled to WASM via Tesseract.js — the actual recognition model, not a stripped-down substitute. Alongside that, plenty of the simpler operations — merging, splitting, adding page numbers — don’t need WASM at all; they run as ordinary JavaScript, using a library called pdf-lib that builds and edits PDF structure directly. Different mechanism, same principle: the code executes on your device.

The compiled engine keeps its original limits, too

Compiling qpdf to WebAssembly is a faithful port, not a rewrite — same source, same logic, just a different compile target. That cuts both ways: it doesn’t gain capabilities the original C++ program never had, either.

Unlock PDF on this site is the clearest example. It runs qpdf’s --decrypt command against your file, and that command has always meant “remove password protection, given the correct password” — never “recover or guess a password you don’t have.” Ask it to decrypt a file with the wrong password (or no password at all) and it fails, exactly the way the command-line qpdf you could install yourself would fail, because it’s running the same check. Compiling to WebAssembly changed where that check runs. It didn’t change what the check does. If you’re looking for a way to crack a forgotten password rather than remove one you already know, this tool — and honestly, any browser-based tool built the same way — isn’t it, and no amount of “runs in your browser” framing changes that; it’s a property of the underlying engine, not the compile target.

Why the tab sometimes pauses, and why OCR doesn’t

One thing genuinely worth knowing before you run a large file through one of these tools: not everything here is shielded from the browser’s own UI thread the same way.

Most of the tools on this site — repairing, merging, splitting, protecting, adding page numbers — call into qpdf or pdf-lib directly from the same JavaScript thread that’s also responsible for redrawing the page. The qpdf build this site uses is deliberately a single-threaded one, chosen specifically because it doesn’t need SharedArrayBuffer or the cross-origin-isolation response headers (Cross-Origin-Opener-Policy / Cross-Origin-Embedder-Policy) that a multi-threaded WASM build would require the whole site to send on every page. That’s a real tradeoff, not a free upgrade: it means a big, slow operation can make the tab visibly stop responding — no spinner animating, no scroll, nothing — for however long that operation takes, before handing control back. For most files that’s a fraction of a second and you’d never notice. For an unusually large or damaged PDF going through repair, it can be long enough to wonder if the tab crashed. It didn’t; the same thread that would redraw the page is busy running your file through qpdf first.

OCR PDF is the one tool here that doesn’t work that way, because it’s the slowest operation on the site by a wide margin — Tesseract’s own createWorker spins up a dedicated background thread for the recognition work, so a multi-page scan can grind on for a while without freezing the tab around it. That’s not a different privacy architecture — your file still never leaves your device either way — it’s a different answer to a UI question: does the page stay responsive while it works. Worth being clear that this is orthogonal to the “does your file leave your device” question this whole post is about; a tool can be perfectly private and still make you wait with a frozen scroll bar, and those are two separate things to check, not one.

What actually happens when you use one of these tools

Walk through the sequence concretely, because it’s simpler than it sounds:

  1. You pick a file. The browser’s File API hands the page a File object — essentially a reference to the bytes on your disk, held in memory, available to any JavaScript running on that page.
  2. The bytes go straight to a library, not a network request. That File object gets read (usually via file.arrayBuffer()) and passed directly as a function argument to pdf-lib, or written into qpdf’s in-memory virtual filesystem, or fed to Tesseract’s recognizer. This is a function call, not an HTTP request — no URL, no server, nothing your file’s contents get attached to and sent anywhere.
  3. The processing runs on your CPU. The WASM module (or the JS library) does its work — reconstructing a broken index, stamping page numbers, running OCR — using your device’s own processor and memory, the same way any other program running on your machine would.
  4. Output bytes come back, still local. The result is a new set of bytes, held in the browser’s memory, that gets offered back to you as a download via a Blob URL — a reference the browser generates locally, pointing at data it already has, not a file being fetched from anywhere.

At no point in that sequence does a network request carrying your file’s content get made. Not because the tool promises not to — because there’s structurally nothing in the code path that does it. The processing function takes bytes in, returns bytes out, and never touches fetch, XMLHttpRequest, or any other API that talks to a server.

What a typical server-side “online” tool does instead

It’s worth being fair about the alternative, because the code doing the actual PDF work is often conceptually similar — a comparable library, just running somewhere else. A server-based version of the same repair tool would look roughly like this instead:

  1. You pick a file in your browser.
  2. The browser uploads it — a POST request carrying your file’s bytes travels over the network to a server.
  3. The server runs its own PDF library — quite possibly qpdf again, or something equivalent — against the uploaded copy.
  4. The result gets sent back down to your browser, and the server discards (or, depending on how the service is built, retains) its copy of your file.

The library and the logic can be nearly identical. What’s different is structural: in that version, your file’s actual contents physically leave your device and pass through infrastructure you don’t control, even briefly. That’s not a claim that server-side tools are poorly built or reckless — plenty are well-run, with sensible deletion policies. It’s a different architecture with a different exposure profile, and the difference is worth understanding rather than taking on faith either way.

How to verify it yourself

You don’t have to trust a claim like this — it’s checkable in about thirty seconds, on any site that makes it:

  1. Open your browser’s developer tools (F12, or right-click → Inspect) and switch to the Network tab.
  2. Clear it, then use the tool on a real file — pick a file, run whatever operation, download the result.
  3. Watch what shows up. A page doing genuine client-side processing will show no request of meaningful size going out during that operation — maybe a small logging or analytics ping, but nothing carrying megabytes of PDF data. A page uploading your file will show exactly that: a POST request whose payload size roughly matches your file’s size, sent to some processing endpoint, followed later by a response coming back down.

This works on this site’s tools and it works on anyone else’s — it’s a genuinely neutral way to check the claim rather than take a badge or a sentence of copy at face value.

A second, independent check: the Content-Security-Policy header

The Network tab check above catches what actually happens during one use of one tool. There’s a second, structural check that doesn’t depend on catching anything in the act, because it isn’t enforced by this site’s own code at all — it’s enforced by your browser.

This site sends a Content-Security-Policy (CSP) response header on every page. A CSP is an allowlist: it tells the browser exactly which destinations a page is permitted to load resources from or send requests to. If a page’s own JavaScript tried to send data anywhere not on that list — say, a POST request carrying a file’s bytes to some collection endpoint — the browser blocks it outright and logs a CSP violation in the console, regardless of what the code intended. That’s the part worth noticing: it isn’t a promise inside the same code you’d otherwise have to trust, it’s a restriction the browser applies from outside that code.

The specific part of the policy that governs every outgoing network request a page on this site is allowed to make — the connect-src directive — currently reads (wrapped here for readability; it’s sent as one line):

connect-src 'self'
  https://www.google-analytics.com
  https://analytics.google.com
  https://www.googletagmanager.com
  https://*.google.com
  https://www.google.co.in
  https://*.doubleclick.net
  https://www.clarity.ms
  https://*.clarity.ms
  https://api.mixpanel.com
  https://api-js.mixpanel.com
  https://static.cloudflareinsights.com
  https://cloudflareinsights.com

Every domain on that list is analytics infrastructure: Google Analytics/Tag Manager, Microsoft Clarity (session recording), Mixpanel (product analytics), and Cloudflare’s own request-insights beacon. None of them is a file-processing or storage endpoint — there’s nothing on the list a PDF’s contents could be sent to, even if some future change to this site tried.

How to check this yourself, independent of anything written here:

  1. Open DevTools → the Network tab, and load any page on this site.
  2. Click the first request in the list — the HTML document itself.
  3. Open its Headers panel and look under “Response Headers” for content-security-policy.

What you’ll see there is the live, currently-enforced policy — the actual header, not a summary of it. For a third-party read on the same header, a site like securityheaders.com will fetch and grade it independently.

The honest limits — this isn’t a free lunch

None of this makes client-side processing strictly better in every dimension. It’s a different tradeoff, optimized specifically around never sending file contents anywhere, and that tradeoff has real costs:

  • Memory ceilings. Your device’s RAM is the RAM available for processing — there’s no elastic server behind it. A 300-page scanned PDF that a beefy server wouldn’t blink at can genuinely strain an older laptop or a phone, especially for operations like OCR or image-heavy compression that hold rendered pages in memory. A server with 64 GB of RAM simply has more headroom than the phone in your pocket.
  • First-load download size. The WASM modules and JS libraries doing the work have to reach your browser before they can run. This site lazy-loads them — nothing downloads until you actually use a tool — but the size varies a lot by tool. qpdf’s compiled WASM module, used by Repair PDF and a few others, is a little over 1MB. Tesseract’s OCR engine is bigger on its own, and each language it recognizes adds its own trained-data file on top — English alone is close to 3MB compressed — so opening OCR PDF for the first time pulls down noticeably more than opening Repair PDF does. Either way, it’s a one-time cost per tool per browser: it’s cached after the first use, and you can watch the actual numbers yourself in the Network tab, the same way described above.
  • Some tasks are genuinely better suited to servers. Batch-processing thousands of files, running workloads too heavy for consumer hardware, or coordinating work across a team all lean naturally toward server-side infrastructure. Client-side processing isn’t a universal upgrade — it’s the right fit specifically when the goal is keeping a file’s contents off the network.

The honest summary: “runs in your browser” is a specific, verifiable architectural claim about where computation happens and what does — and doesn’t — leave your device, not a vague assurance that everything about the approach is automatically superior. For most everyday PDF edits, the tradeoff leans clearly in favor of not uploading a file at all. For a handful of edge cases — a genuinely enormous scanned archive, say — it’s worth knowing where the ceiling is, and that’s a limit of the device doing the work, not a limit of the idea itself.

If you want to see the mechanics from the other side — what actually breaks inside a PDF and how a WASM-compiled engine like qpdf fixes it — Repair PDF is a concrete, verifiable example of exactly this architecture in action.