# PDF PII Redactor — Remove Personal Data, Not Just Cover It (`northbound_works/pdf-pii-redactor`) Actor

Finds emails, phone numbers, SSNs, card numbers and more in a PDF and deletes them from the file, then draws the black box. Verified after saving: if the text is still extractable, the document is not charged.

- **URL**: https://apify.com/northbound\_works/pdf-pii-redactor.md
- **Developed by:** [Austin Cooley](https://apify.com/northbound_works) (community)
- **Categories:** Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## PDF PII Redactor — actually remove personal data, not just cover it

Finds emails, phone numbers, Social Security numbers, credit card numbers, IBANs,
IP addresses and dates of birth in a PDF, **deletes them from the file**, then
draws the black box.

### The difference that matters

Most tools that call themselves redactors draw a black rectangle over the text
and save the file. The words are still there, in the content stream, underneath
the box.

Select-all and copy gets them back. So does `pdftotext`. So does any PDF parser
written in the last twenty years. Real documents have been leaked exactly this
way — including court filings, published with "redacted" names that anyone could
recover by dragging a cursor across them.

This Actor uses PyMuPDF's redaction annotations, which remove the glyphs from
the page before the box is painted.

**Then it checks.** After saving, the output is re-opened and re-parsed. If any
of the text we claimed to remove is still extractable, the document is marked
failed and **you are not charged for it**.

### What it finds

| Type | Notes |
|---|---|
| Email addresses | |
| Phone numbers | Requires separators or a country code, so bare invoice numbers survive |
| US Social Security numbers | `NNN-NN-NNNN` |
| Credit card numbers | **Luhn-checked** — real cards pass, order numbers almost never do |
| IBAN | International bank account numbers |
| IP addresses | IPv4, correctly bounded so version strings are not eaten |
| Dates of birth | `MM/DD/YYYY` |
| Anything else | Supply your own regex — employee IDs, case numbers, internal references |

The patterns are deliberately conservative. A false positive silently destroys
real content in someone's document, which is worse than a miss they can catch by
reading it.

### Pricing

Charged **per page that actually had something redacted**. A 60-page contract
with personal data on 3 pages costs 3 pages, not 60. Pages we did not touch are
free — which means the work of finding the matches happens before anything is
billable.

Nothing is charged for a document that fails, or for one whose redaction could
not be verified.

### Output

Each document returns a signed link to the redacted PDF, the page counts, a
breakdown of what was found by type, and the verification result.

### What it is not

It does not do face blurring, image redaction, or handwriting. It does not find
names or street addresses — those need a language model and produce false
positives that quietly delete the wrong words. If you need those, this is the
wrong tool and I would rather say so here than take the run.

Scanned documents with no text layer have nothing to search. Run them through
[Searchable PDF OCR](https://apify.com/northbound_works/searchable-pdf-ocr)
first, then through this.

# Actor input Schema

## `pdfUrls` (type: `array`):

Direct links to the PDFs you want redacted. Each one is processed and returned separately.

## `redact` (type: `array`):

Every selected type is found and deleted from the page, not just covered over.

## `customPatterns` (type: `array`):

Anything else to strip — employee IDs, case numbers, internal references. Standard Python regex, one per entry. Invalid regex fails the run rather than silently matching nothing.

## `drawBlackBoxes` (type: `boolean`):

On: the redaction is visible as a black bar, which is what most people expect a redacted document to look like. Off: the text is still removed but the space is left blank.

## Actor input object example

```json
{
  "pdfUrls": [
    "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
  ],
  "redact": [
    "email",
    "phone",
    "ssn",
    "credit_card",
    "iban",
    "date_of_birth"
  ],
  "customPatterns": [],
  "drawBlackBoxes": true
}
```

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "pdfUrls": [
        "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("northbound_works/pdf-pii-redactor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "pdfUrls": ["https://www.irs.gov/pub/irs-pdf/fw9.pdf"] }

# Run the Actor and wait for it to finish
run = client.actor("northbound_works/pdf-pii-redactor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "pdfUrls": [
    "https://www.irs.gov/pub/irs-pdf/fw9.pdf"
  ]
}' |
apify call northbound_works/pdf-pii-redactor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,northbound_works/pdf-pii-redactor"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/72cDK7u1xPbZofrzi/builds/KgyhhpVCtZqQArLfv/openapi.json
