About this tool
Documents, assembled — without a server in the loop.
Collate turns a stack of photos, scans, and existing PDFs into a single, correctly ordered PDF (or a set of JPG/PNG images) in the time it takes to drag files into a window and press one button.
What it's for
Day-to-day work generates a constant trickle of paper — signed forms, inspection photos, receipts, permits — that eventually needs to become one clean PDF. That usually means a phone scanning app, some manual reordering, and often a third-party service somewhere in between. Collate removes that middle step: pictures of documents go in, an organized file comes out, and nothing is ever transmitted anywhere along the way.
How the “no upload” part actually works
Everything — reading the images, rendering PDF pages, building the merged file — happens inside the browser tab itself, using the same JavaScript engine that renders this page. There's no server component receiving files, no API endpoint accepting uploads, and no database storing anything. Close the tab, and nothing of what you processed persists anywhere except the file your browser already saved to your device.
That much is true of the architecture. But architecture is a promise, so the app also ships a Content Security Policy that makes the browser enforce it. The policy restricts outbound connections to this app's own origin, which has no endpoint capable of receiving a document. Even if a malicious PDF or a compromised dependency tried to send your files somewhere, the browser would block the request before it left the machine.
File compatibility
Images
Any format your browser can natively display — JPEG, PNG, WebP, GIF, BMP, and more — plus iPhone HEIC/HEIF photos, converted in-browser for browsers that can't read HEIC directly. EXIF rotation is honored, so portrait phone photos stay upright.
PDFs
Unpacked page-by-page, so individual pages can be reordered, rotated, merged with new photos, or combined with pages from other PDFs — not just appended whole. Encrypted files prompt for a password; signed and filled-in pages are preserved as flattened visual copies.
Output
A merged PDF — Optimized (smaller) or Uncompressed (full fidelity) — or the same pages exported as JPG/PNG, zipped automatically when there's more than one.
Technical disclosures
Things worth knowing before trusting this with something that matters.
One thing is stored locally: your theme preference
Light/dark choice is saved in this browser's local storage. That is the only thing Collate writes anywhere. Documents are held in memory for the life of the tab and are gone when it closes — there is no autosave and no recovery.
There is no analytics, telemetry, or error reporting
Nothing about your session is measured or transmitted, including when something goes wrong. Errors are logged to your own browser console only.
“Optimized” PDF output is lossy
It resizes photos to at most 2000px on the long edge and re-encodes them as JPEG, which is what keeps a batch of phone photos from producing a several-hundred-megabyte file. For archival or legal originals, choose Uncompressed. Either way, pages copied from an existing PDF are never recompressed.
Limits: 250 pages, 150 MB per file, 600 MB total
Everything is processed in this tab's memory, so an unbounded batch wouldn't slow down — it would crash the tab and lose your arrangement. Files past these limits are declined by name rather than failing silently.
Large PDFs can make the page stutter briefly
Photo processing runs on a background thread, so batches of images stay responsive. PDF rendering deliberately does not: running it in the background turned out to silently drop signature blocks and filled form fields from the output, so it was moved back. Importing or converting a long PDF may briefly stall the interface. It is working, not hung.
HEIC Live Photos use only the first frame
Live Photos and burst shots bundle several frames in one file. Collate takes the first and discards the rest. A HEIC variant the decoder can't parse is skipped with an error on its card rather than failing the whole batch.
Signed PDFs are flattened into visual copies
A digital signature — from Adobe Acrobat Sign, DocuSign, or similar — covers the exact bytes of the file it was applied to. Combining pages produces a new file, so the certificate can't survive. This is true of every tool that merges PDFs, not just this one.
Collate flattens those pages the same way “Print to PDF” would: the signature block stays visible on the page, but no certificate is attached and nothing claims to be verifiable. The result is a visual copy, and recipients can see it as one. Where the certificate itself is what matters, send the original file.
Filled forms are flattened too
A filled-in form field is stored the same way a signature is, and would be lost the same way when pages are combined. Collate flattens any page carrying form fields so the entries survive — page by page, so the rest of the document keeps its selectable text. There is also a Flatten all option for when a faithful visual copy of everything matters more than selectable text.
Flattened pages lose selectable text
Flattened pages are images: they look correct and print correctly, but their text is no longer selectable or searchable. Affected pages are named after conversion rather than downgraded silently.
Password-protected PDFs can be unlocked, but their pages become images
Collate prompts for the password and uses it in the tab only — it is never transmitted and is discarded when the tab closes. The library that assembles the output has no decryption support, so unlocked pages are rendered and embedded as images: they look correct, but their text stops being selectable and searchable.
The security policy is strong against exfiltration, weaker against injection
The connection restriction described above is strict. The script policy is not equally strict, because the app's framework requires inline scripts to start up. This is a deliberate trade: the asset worth protecting here is your documents, and it is their route off the device that is sealed.
Under the hood
Collate is a Next.js app with no API routes, no server actions, and no environment variables — there is nothing for a server to do, and no credentials or secrets exist in this codebase to expose. The excerpt below is real, trimmed only for length:
// lib/pdfEngine.ts — trimmed for readability
export async function buildOutputPdf(items, sourceDocs, options) {
const out = await PDFDocument.create();
for (const item of usable) {
if (item.kind === "image") {
// Image bytes are read straight from the File object already
// sitting in browser memory — decoded, rotated and re-encoded in
// a Web Worker, then embedded. No network call at any point.
const jpegBytes = await encodeImage(item.file, item.rotation, ...);
out.addPage(...).drawImage(await out.embedJpg(jpegBytes), ...);
continue;
}
// A page whose content lives in widget annotations — a signature
// block, a filled form field — can't be copied natively: pdf-lib
// doesn't carry the AcroForm across, so that content would vanish
// without any error. Those pages get rendered instead.
const flatten =
options.forceFlatten ||
source.isEncrypted || // pdf-lib cannot decrypt, ever
source.hasSignature ||
source.widgetPages?.includes(item.pageIndex);
if (!flatten) {
// Native copy — text and vector content stay intact, and page
// rotation is metadata rather than pixels, so it stays lossless.
const [copied] = await out.copyPages(sourceDoc, [item.pageIndex]);
out.addPage(copied);
} else {
// Rendered with intent:"print" so annotation appearances are drawn
// into the page, the same way "Print to PDF" behaves.
const raster = await rasterizePdfPageForEmbed(source, item.pageIndex, ...);
out.addPage([raster.widthPt, raster.heightPt]).drawImage(...);
}
}
return out.save(); // bytes held in memory — handed straight to a download
}Everything else follows the same pattern — pdf-lib assembles and merges PDFs, pdf.js renders thumbnails and rasterizes pages for image export, heic2any decodes iPhone photos, and jszip bundles multi-page image exports. All of it runs as ordinary JavaScript in this tab, with no network calls to anywhere but the host that served the page itself.
Dependencies are kept current for security reasons rather than novelty: the PDF rendering library in particular has a history of vulnerabilities that let a crafted PDF run code in the page, which for a tool like this would undermine the entire point. Collate runs a patched version and additionally disables the language feature those attacks relied on.