Building a Client-Side
PDF Engine
How ILikePdf processes 150 MB+ documents entirely in your browser — zero server uploads, zero privacy exposure — using WebAssembly, intelligent memory management, and device-adaptive processing.
01 — The Challenge
Processing PDFs in the browser is notoriously difficult. Traditional web apps upload files to servers, process them remotely, and return results. This approach has critical flaws for privacy-sensitive documents: contracts, medical records, financial statements.
The core problem — PDFs are complex binary formats requiring significant RAM. A 50 MB PDF with images needs 200–300 MB to process. Multiply across concurrent users and server costs skyrocket. More importantly, sensitive documents shouldn't leave your device at all.
✕ Server-Side
- Privacy risk — files travel over the network
- Upload/download bandwidth waste
- Server costs and scaling problems
- Network latency on every operation
- Single point of failure for breaches
✓ Client-Side
- Complete privacy — bytes never leave device
- Instant — no network round-trip
- Zero infrastructure cost
- Works fully offline after first load
- No server = no server breach possible
02 — Technical Architecture
Core Libraries
Two WebAssembly-powered engines handle all processing. Both run entirely inside the browser tab — no native installation, no server dependency.
pdf-lib — v1.17.1
PDF manipulation engine. Merges, splits, adds pages, edits metadata. Works at the PDF structure level — copies pages without re-rendering, making merges instant.
Handles PDF internals: form fields, annotations, encryption.
pdf.js — v3.11.174
Mozilla's PDF rendering engine — the same one Firefox uses natively. Converts pages to Canvas for pixel-perfect previews and high-DPI image export.
Worker architecture offloads heavy parsing to a separate thread.
No artificial limit. Processing capacity depends only on your device's available memory. Desktop browsers typically handle files up to 500 MB.
Never. ILikePdf does not add watermarks to any output file, free or otherwise.
Yes. The tool works in any modern mobile browser (Chrome, Safari, Firefox) on Android and iPhone with no app installation.
Storage Strategy
Three-tier storage solves different problems. The key rule: keep data as ArrayBuffer as long as possible — converting to strings increases memory 3–5×.
const dbSet = async (key, val) => {
const db = await initDB();
const tx = db.transaction('ILikePdf-store', 'readwrite');
tx.objectStore('ILikePdf-store').put(val, key);
return new Promise((res, rej) => { tx.oncomplete = () => res(); tx.onerror = () => rej(tx.error); });
};
// Tier 2: localStorage — metadata only (no file bytes)
localStorage.setItem('ILikePdf_history', JSON.stringify(history));
// Tier 3: RAM — active processing (volatile)
const pdfDoc = await PDFDocument.load(arrayBuffer);
03 — Memory Management
The app dynamically adjusts limits based on device type and available memory. A 4 GB RAM phone typically has 1–1.5 GB available for browser tabs. A single 100 MB PDF can consume 300–400 MB during processing.
const isMobile = /Android|iPhone/i.test(navigator.userAgent);
const deviceMem = navigator.deviceMemory || 4;
if (isMobile && screen.width < 768) {
return { maxFileSize: 50 * 1024 * 1024, maxDPI: 300, maxPagesPerBatch: 10 };
}
if (deviceMem < 4) {
return { maxFileSize: 100 * 1024 * 1024, maxDPI: 450, maxPagesPerBatch: 30 };
}
return { maxFileSize: 150 * 1024 * 1024, maxDPI: 600, maxPagesPerBatch: 50 };
};
| Device | Max File | Max DPI | Batch Size |
|---|---|---|---|
| Smartphone | 50 MB | 300 | 10 pages |
| Tablet | 75 MB | 450 | 25 pages |
| Desktop | 150 MB | 600 | 50 pages |
const estimateMemoryUsage = (fileSize, pageCount, scale, format) => {
const basePerPage = 5 * 1024 * 1024;
const scaleFactor = Math.pow(scale, 2);
const fmtMultiplier = format === 'png' ? 1.5 : 1.0;
return { estimated: pageCount * basePerPage * scaleFactor * fmtMultiplier };
};
04 — Security & Privacy
ILikePdf operates on a simple principle: we can't leak what we never see. Files never touch our servers, third-party APIs, or external services. All processing happens in the browser's sandboxed environment.
FileReader.readAsArrayBuffer(file)
→ PDFDocument.load(arrayBuffer)
→ pdfDoc.save()
→ new Blob([bytes])
→ URL.createObjectURL(blob)
→ anchor.click()
// No network request anywhere in this chain
Offline-First via Service Worker
After the first page load, all tools function without any internet connection. Enable airplane mode and process PDFs normally — the WebAssembly libraries are cached locally.
self.addEventListener('install', (e) => {
e.waitUntil(caches.open('ILikePdf-v1').then(c => c.addAll(['/', ...ASSETS])));
});
self.addEventListener('fetch', (e) => {
e.respondWith(caches.match(e.request).then(cached => cached || fetch(e.request)));
});
ILikePdf — Engineering: Performance · Privacy · Accessibility