True PDF
redaction.
scrubzero removes text operators from the page content stream before drawing the visual bar. No hidden layers. No recoverable text. Built for server-side use in Node.js and AWS Lambda.
Upload a PDF, enter a search pattern (plain text or /regex/flags), download the redacted result.
A scan is an image — a bar drawn over it removes nothing. This tool OCRs the pages, burns opaque boxes into the pixels, and rebuilds the PDF from the flattened images, so the original content is destroyed. It runs entirely in your browser — the file never leaves your device.
Runs entirely in your browser. The scan is rendered, read, and rebuilt on this device — it is never uploaded. The redacted pages are flattened images, so the original pixels are destroyed, not just covered.
01 — Upload a scanned PDF
02 — What to redact
pdfjs-dist extracts text items with positions. For each match, scrubzero locates the BT/ET block in the raw content stream bytes, finds the text-drawing operators, and blanks their string arguments. The glyph data is gone before the bar is drawn.
After scrubbing, pdf-lib draws a filled rectangle over the region using the specified color (default black). The bar is a genuine visual layer on top of now-empty space — there is no text underneath to recover.
DocInfo fields (Title, Author, Subject, Keywords, Producer, Creator) are wiped and timestamps reset. The XMP metadata stream is removed from the document catalog. Enabled by default, disable with sanitizeMetadata: false.
When generateManifest: true, each redaction entry is recorded with page number, bounding box, timestamp, optional redactor ID, basis code, and SHA-256 hashes of both the input and output PDF for chain-of-custody compliance.
Redaction works on the text layer. A scanned or image-only page has no text to remove, so a bar there only covers the pixels — it does not delete them. scrubzero detects this and returns a warning instead of a false all-clear, then the Scanned PDFs tool above OCRs the page, burns the boxes into the pixels, and rebuilds the file from flattened images — all in your browser, so the scan never leaves your device.
Search and redact by text pattern
import { searchAndRedact } from '@liiift-studio/pdf-redact'
import { readFile, writeFile } from 'node:fs/promises'
const pdf = await readFile('document.pdf')
const result = await searchAndRedact(pdf.buffer, [
{ pattern: /John Smith/g, label: 'REDACTED' },
{ pattern: /\d{3}-\d{2}-\d{4}/g, label: 'SSN' },
])
await writeFile('redacted.pdf', result.pdf)
console.log(`${result.redactedCount} regions redacted`)Redact specific regions by coordinate
import { redact } from '@liiift-studio/pdf-redact'
const result = await redact(pdf.buffer, [
{ page: 1, x: 72, y: 140, width: 200, height: 18 },
{ page: 2, x: 72, y: 200, width: 150, height: 18 },
])Entity patterns — SSN, phone, email, credit card, and more
import { redactEntities } from '@liiift-studio/pdf-redact'
const result = await redactEntities(pdf.buffer, [
'ssn', 'phone', 'email', 'credit-card',
])Audit manifest with FOIA exemption codes
const result = await redact(pdf.buffer, regions, {
generateManifest: true,
redactorId: 'agent-smith',
basisCode: 'b6', // FOIA Exemption 6
addRedactionMarkers: true, // print exemption code in bar
})CLI
npx @liiift-studio/pdf-redact search document.pdf "John Smith" --output redacted.pdf
npx @liiift-studio/pdf-redact search document.pdf "/\d{3}-\d{2}-\d{4}/g" --color #1a1a1a
npx @liiift-studio/pdf-redact entities document.pdf --types ssn,phone,email
npx @liiift-studio/pdf-redact verify redacted.pdfRedactOptions
| Option | Default | Description |
|---|---|---|
| sanitizeMetadata | true | Wipe DocInfo fields and remove XMP metadata stream |
| flattenAnnotations | true | Flatten annotation layers before redacting |
| addRedactionMarkers | false | Render label or exemption code inside the bar |
| generateManifest | false | Attach a JSON audit manifest with SHA-256 hashes |
| redactorId | undefined | Operator ID recorded in the manifest |
| basisCode | undefined | FOIA basis code (e.g. 'b6') rendered in the bar when markers are on |