Security &
Privacy
Technical documentation for security teams evaluating Compressa for enterprise use. Every claim on this page is independently verifiable.
No APIs, no uploads, no external calls. Your PDFs never leave the browser.
Static HTML/JS/CSS export. No Node.js, no backend, no database.
Open source. Inspect the network tab yourself to verify.
Architecture Overview
Compressa is built with Next.js using output: "export" — this produces a fully static site. The build output is plain HTML, JavaScript, and CSS files. There is no server-side code, no API routes, no database, and no runtime environment.
PDF compression runs entirely in a Web Worker — a separate browser thread that handles PDF parsing, image analysis, recompression, and file rebuilding. The Web Worker communicates with the main thread exclusively through postMessage with transferable ArrayBuffers.
The deployed application consists of:
- ●Static HTML, JS bundles, and CSS
- ●A PDF.js worker script (
pdf.worker.min.mjs, served from same origin) - ●Font files loaded from Google Fonts (DM Sans, Instrument Serif)
No environment variables are used. No secrets or API keys exist anywhere in the codebase.
Data Flow
File selection
User selects a PDF via drag-drop or file picker. The file is read into an ArrayBuffer in browser memory using the FileReader API.
Worker transfer
The ArrayBuffer is transferred (zero-copy) to a dedicated Web Worker thread via postMessage with Transferable semantics. The main thread releases ownership of the data.
PDF parsing
The Web Worker uses pdf-lib to parse the PDF structure, enumerating all pages, image XObjects, fonts, and metadata. This is pure JavaScript — no native code or server calls.
Image compression
Each embedded image is decoded, optionally downsampled to the target DPI, and re-encoded as JPEG using the browser’s OffscreenCanvas API. Duplicate images are detected and deduplicated. All processing happens in-memory within the Worker thread.
PDF rebuild
The Worker rebuilds the PDF with compressed images, optionally stripped metadata, and object stream compression. The final PDF bytes are produced entirely in memory.
Download
The compressed PDF ArrayBuffer is transferred back to the main thread. A download is triggered via URL.createObjectURL. The object URL is immediately revoked and all references released for garbage collection.
At no point in this flow does data leave the browser's memory boundary. There is no network transmission of file content.
Network Activity
What you will see in the Network tab
On page load: HTML document, JS bundles, CSS, and font files (DM Sans and Instrument Serif from Google Fonts).
On first compression: pdf.worker.min.mjs loaded from same origin (~1 MB). This is the PDF.js rendering worker, a static file bundled with the application.
On subsequent files: Nothing. The worker script is cached by the browser.
What you will NOT see
✕XHR/fetch to external domains
✕WebSocket connections
✕File uploads or POST requests
✕Tracking pixels or beacons
✕Google Analytics or any analytics
✕Sentry, Bugsnag, or error reporting
✕CDN calls for PDF processing
✕Any outbound data transmission
What Compressa Won't Do
Technical Evidence
Static export configuration
// next.config.ts
const nextConfig = {
output: "export", // ← Fully static, no server
webpack: (config) => {
config.resolve.fallback = {
fs: false, // No filesystem access
path: false, // No path module
crypto: false, // No crypto module
canvas: false, // No native canvas
// ... all Node.js modules disabled
};
return config;
},
};No API routes
The src/app/ directory contains only page routes and layout files. There is no api/ subdirectory. No server-side request handlers exist anywhere in the codebase.
Worker isolation
The Web Worker runs in a separate thread within the same browser security context. PDF data is transferred via postMessage using Transferable ArrayBuffers (zero-copy, single-owner semantics). The worker is terminated after each compression completes, and a fresh worker is created for the next file.
In-browser image processing
Image re-encoding uses the browser's native OffscreenCanvas and convertToBlob APIs — no external image processing services. Zlib compression uses the browser's built-in CompressionStream API.
Dependency Audit
| Package | Purpose | Network |
|---|---|---|
| next | Static site generation framework | None |
| react / react-dom | UI rendering | None |
| pdf-lib | PDF parsing, modification, and rebuilding | None |
| pdfjs-dist | PDF.js worker for page rendering (thumbnails) | None |
Every runtime dependency operates exclusively on in-memory data. None make network requests, transmit telemetry, or access external resources. Build-time dependencies (tailwindcss, typescript, eslint) are not present in the deployed application.
Deployment Options
Hosted
Deploy as static files on any CDN or static hosting platform (Vercel, Netlify, S3 + CloudFront, GitHub Pages).
Self-hosted
Run npm run build and deploy the out/ directory to any internal static file server. Full control over infrastructure.
Air-gapped
Build once, copy the output to an isolated network. No internet connection required after the initial build. All assets including the PDF.js worker are bundled.
Note: The app loads DM Sans and Instrument Serif from Google Fonts on page load. For air-gapped or fully isolated deployments, these fonts can be self-hosted by downloading them and serving from the same origin.
Verification Steps
Every claim on this page can be independently verified. Here's how:
Open browser DevTools → Network tab
Clear the log, then compress a PDF. You will see only same-origin requests for static assets. Zero external domain requests during compression.
Inspect next.config.ts
Confirm output: "export" is set. This guarantees static-only output with no server runtime.
Check the src/app/ directory
Confirm there is no api/ subdirectory. No server-side request handlers exist.
Review package.json
Confirm no analytics, telemetry, or tracking dependencies are listed.
Search for fetch() calls
The codebase contains no fetch() calls to external services. All data processing uses in-memory ArrayBuffers passed between the main thread and Web Worker.
For maximum assurance
Clone the repository, build locally, and deploy on an air-gapped network. Compress a PDF and observe: zero network traffic beyond the initial static asset load.