imisspdf for Developers
Build privacy-first PDF features into your own app — using the same engine that powers imisspdf.com.
@imisspdf/pdf-utils
Tiny, well-typed wrapper around pdf-lib for the 8 most common PDF operations. Works identically in the browser, Node 18+, Bun, and Deno. MIT licensed.
Install
npm install @imisspdf/pdf-utils
Why this exists
pdf-lib is excellent — but for the 5 operations 90% of apps actually need (merge, split, rotate, count pages, watermark), the code is verbose and the same boilerplate gets re-copied across projects. This package is the boring missing layer:
- Concise API —
mergePdfs([buf1, buf2])instead of 20 lines - Well-typed — full TypeScript types, JSDoc on every public function
- Universal — identical API in browser (Vite, Webpack, ESBuild) and Node 18+
- No network — not a wrapper around a SaaS — does everything locally with WebAssembly + pdf-lib
- Minimal surface — 8 functions, no DI, no plugins, no config
- MIT licensed — use in commercial products with no obligations
Quick examples
1. Merge multiple PDFs into one
import { mergePdfs } from '@imisspdf/pdf-utils';
// In the browser, from <input type="file" multiple>:
const files = Array.from(input.files!);
const buffers = await Promise.all(files.map((f) => f.arrayBuffer()));
const merged = await mergePdfs(buffers);
// merged is a Uint8Array — save it:
const blob = new Blob([merged], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
window.open(url); 2. Split a PDF by page range
import { splitPdf } from '@imisspdf/pdf-utils';
const pdf = await readFile('./report.pdf');
const subset = await splitPdf(pdf, [
{ from: 1, to: 3 },
{ from: 7, to: 10 },
]);
await writeFile('./excerpt.pdf', subset); 3. Add a text watermark
import { addTextWatermark } from '@imisspdf/pdf-utils';
const stamped = await addTextWatermark(pdf, 'CONFIDENTIAL', {
opacity: 0.2,
fontSize: 60,
angle: -30,
}); Full API surface
Eight functions covering the operations 90% of apps need. Full types in src/index.ts.
mergePdfs(buffers)— concatenate PDFs in array ordersplitPdf(buffer, ranges)— extract page rangesrotatePdf(buffer, opts)— rotate all or selected pagesgetPageCount(buffer)— count pages without renderingaddTextWatermark(buffer, text, opts?)— stamp text on every pagegetMetadata(buffer)— extract title, author, creator, datesremoveMetadata(buffer)— strip metadata for privacyisPdfEncrypted(buffer)— pre-flight check
Browser vs Node — what works where
Every function is identical in both runtimes. The library uses standard ArrayBuffer and Uint8Array types, no Node-specific or DOM-specific APIs.
- Browser (Chrome, Safari, Firefox, Edge — modern) — works via WebAssembly, ~80 KB gzipped
- Node 18+ — use
fs/promisesfor file I/O, then passArrayBuffer - Bun & Deno — tested, works
- Edge runtimes (Cloudflare Workers, Vercel Edge) — works (no Node-specific APIs)
Privacy posture
This is a client-side library. It does not make any network requests. It does not collect telemetry. It does not include analytics. The only dependency is pdf-lib, which is similarly self-contained.
If you're building a privacy-first product, your dependency tree stays clean. Audit with npm ls --all — you should see only pdf-lib.
Roadmap
Planned for 0.2.x (issues welcome with use-case votes):
compressPdf— image re-sampling and stream re-encodingflattenForms— bake interactive fields into the visible layeraddPageNumbers— with templatesaddImageWatermark— PNG/JPG stamps with positioningextractTextLayer— for indexing / search use cases
Why not a REST API?
We considered offering a hosted REST API for server-to-server PDF processing. We decided not to ship one because it would contradict the architectural promise of imisspdf.com — that your files never leave your machine. A REST API necessarily uploads files to our servers. If you want that, Adobe, PDFKit.io, and ConvertAPI already do it well. Use them when server-side processing fits your use case.
If you want privacy-by-default client-side PDF processing, @imisspdf/pdf-utils is for you.
License & contributing
MIT — use in commercial products with no obligations.
We accept PRs. The library is small and the bar is "well-typed, no network calls, no breaking the public API". Issues and feature requests welcome. We prioritise additions that real apps would use.