PII Masker — Redact CPF, CNPJ, Emails, Phones, Names (LGPD) avatar

PII Masker — Redact CPF, CNPJ, Emails, Phones, Names (LGPD)

Pricing

from $0.35 / 1,000 record processeds

Go to Apify Store
PII Masker — Redact CPF, CNPJ, Emails, Phones, Names (LGPD)

PII Masker — Redact CPF, CNPJ, Emails, Phones, Names (LGPD)

Find and mask personal data in texts, JSON or any Apify dataset: CPF, CNPJ (incl. alphanumeric), e-mails, phones, cards, IBAN, IPs and names. Redact, mask, partial or hash. Check-digit validated. LGPD/GDPR ready.

Pricing

from $0.35 / 1,000 record processeds

Rating

0.0

(0)

Developer

Leandro Zanatta

Leandro Zanatta

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

14 days ago

Last modified

Categories

Share

PII Masker — Redact CPF, CNPJ, E-mails, Phones & Names (LGPD / GDPR)

Find and hide personal data in texts, JSON records or any Apify dataset in one call. Detects Brazilian documents (CPF, CNPJ including the new alphanumeric format, PIS, RG, CEP, license plates) and international data (e-mails, phone numbers, credit cards, IBAN, IP addresses), plus person names with a small language model. Choose how to hide them: redact, mask, partial or hash (consistent pseudonyms).

One fictitious record shown original, redacted, masked, partially masked and hashed

Real output of this Actor on fictitious data.

Why use it

  • ✅ Fewer false alarms: CPF, CNPJ and PIS are validated by their check digits, cards by the Luhn algorithm and IBANs by mod-97. Order numbers, prices, dates, barcodes and protocol numbers are left alone.
  • 🇧🇷 Built for Brazil (LGPD): CPF, CNPJ (numeric and the alphanumeric CNPJ in use since July 2026), PIS/PASEP/NIS, RG, CEP and Mercosur plates, in all their usual formats.
  • 🧩 Keeps your data usable: JSON structure stays the same; only the sensitive values change. Hash turns each value into the same token every time, so you can still count, group and join records.
  • 🔗 Plugs into any scraper: give it a dataset ID and it cleans the whole output of another Apify run, ready to share or load into BI and AI tools.
  • 🤖 Safer AI: strip personal data before sending tickets, chats or documents to an LLM, a vector database or a third-party API.
  • 🔒 Runs inside the Actor: no external AI or API is called; nothing is logged.

Who uses it

SectorTypical use
Companies under LGPD / GDPRAnonymize exports before sharing with partners, vendors or analytics teams
Customer support & CXClean tickets, chats and call transcripts before analysis or AI training
Data & AI teamsRemove PII from datasets before LLM fine-tuning, RAG or vector search
Developers & QATurn production data into safe test data, keeping formats and joins
Scraping & lead workflowsMask personal fields in scraped data before storage or resale of aggregated insights
Legal, health & financePrepare documents and records for audits, research and data-subject requests

What it detects

TypeExamplesValidation
CPF529.982.247-25, 52998224725Check digits; unformatted numbers only with "CPF" or a matching field name nearby
CNPJ11.222.333/0001-81, 12.ABC.345/01DE-35Check digits, numeric and alphanumeric
PIS / PASEP / NIS120.12345.67-2Check digit
RGRG: 12.345.678-9Needs an "RG / identidade" label (no national check digit)
E-mailmaria@empresa.com.brFormat
Phone(11) 98765-4321, +55 21 99876-5432, 0800 123 4567, +1 415 555 2671Format; not part of longer codes
Credit card4111 1111 1111 1111, 3782 822463 10005Luhn + card formats; barcodes and order numbers ignored
IBANGB82 WEST 1234 5698 7654 32mod-97
IP address192.168.0.12, IPv6Valid ranges; "version 10.2.3.4" ignored
CEP01310-100Format with hyphen
License plate (BR)ABC1D23, ABC-1234Old and Mercosur formats
Person nameMaria da Silva, John SmithLanguage model (Portuguese and English)

Measured on 500 synthetic texts mixing real-format documents with order numbers, prices, dates, barcodes and protocol codes: 100% of CPF, CNPJ, card, phone, e-mail, CEP, IP and plate values found, 0 false positives. Person names: 96% found in 200 simple Portuguese and English sentences, with no city, street or company names flagged. Real texts are messier than test data; review a sample for critical uses.

Masking methods

MethodCPF 529.982.247-25 becomesBest for
Redact (default)CPF [CPF]Sharing, AI prompts, logs
MaskCPF ***.***.***-**Keeping the layout of documents and screens
PartialCPF ***.982.247-**Customer service screens (the LGPD-style CPF display), e-mail m***@gmail.com, card **** 1111
HashCPF CPF_5d91b935fb0fAnalytics and joins: the same value gives the same token (with the same secret)

For hash, set a Hash secret and reuse it in every run to get the same tokens across runs. Without a secret, a random one is used, so tokens only match within the run. Hashing with a secret is pseudonymization: under the LGPD and GDPR, whoever holds the secret can still link records, so keep it safe.

Input

FieldTypeDefaultDescription
Texts (texts)array—Free texts; each is one record
JSON records (records)array—Objects of any shape; structure is kept
Apify dataset ID (datasetId)string—Clean every item of an existing dataset (e.g. a scraper's output)
Masking method (method)stringredactredact, mask, partial or hash
Data types (piiTypes)arrayall documentsWhich types to look for
Detect person names (detectNames)booleantrueUse the language model for names
Language for names (namesLanguage)stringautoauto, pt or en
Only these fields (fields)arrayallDot paths such as contact.email
Hash secret (hashSecret)stringrandomSecret for consistent hashing (stored encrypted)
Return positions (includeEntities)booleanfalseAdd type, field and character positions of each finding (never the original value)
Add _pii summary (addSummary)booleantrueCount of findings per record
Max records (maxRecords)integer0Stop after N records (0 = all)

Example: clean the output of a scraper run, keeping joins possible:

{
"datasetId": "aBcDeFgHiJkLmNoP",
"method": "hash",
"hashSecret": "my-long-random-secret",
"fields": ["name", "email", "phone", "comments"]
}

Output

One dataset row per text or record, in the same order. JSON records keep their structure:

{
"name": "A. S.",
"cpf": "***.982.247-**",
"contact": { "email": "a***@empresa.com.br", "phone": "+** ** *****-5432" },
"note": "Entrega no CEP *****-*00",
"_pii": { "found": 5, "byType": { "person": 1, "cpf": 1, "email": 1, "phone": 1, "cep": 1 } }
}

Texts come back as { "index": 0, "text": "Cliente [PERSON], CPF [CPF], ...", "_pii": {...} }. A run summary (records processed and findings per type) is saved as SUMMARY in the key-value store. Original values are never written to the output.

Pricing

Pay per record processed (a text or a JSON record of up to 5,000 characters; longer ones count once per started 5,000 characters), plus a tiny per-run start fee. No subscription. Apify plan discounts apply automatically (see the Pricing tab).

ExampleRecords billed
1,000 support tickets1,000
A scraper dataset with 20,000 items20,000
One 12,000-character document3

Use Max records or the run's maximum cost setting to cap spending.

Use it from code or an AI agent

Python: clean texts before sending them to an LLM

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("adorable_partial/pii-masker").call(run_input={
"texts": ["Oi, sou a Maria Souza, CPF 529.982.247-25, meu e-mail é maria@gmail.com"],
"method": "redact",
})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
print(row["text"]) # Oi, sou a [PERSON], CPF [CPF], meu e-mail é [EMAIL]

JavaScript: mask a scraper's output

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const scrape = await client.actor('<some-scraper>').call({ /* ... */ });
const run = await client.actor('adorable_partial/pii-masker').call({
datasetId: scrape.defaultDatasetId,
method: 'partial',
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

HTTP

curl -X POST "https://api.apify.com/v2/acts/adorable_partial~pii-masker/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \
-H "Content-Type: application/json" \
-d '{"texts": ["Contato: joao@empresa.com, (11) 98765-4321"]}'

No-code and agents: chain it after any Actor with an integration or webhook, use it in Make, Zapier or n8n, or call it from an AI agent through the Apify MCP server as a privacy step.

FAQ

Does it keep the original values anywhere? No. Only masked values are written. With includeEntities you get positions and types, never the values.

Is masked data anonymous under the LGPD / GDPR? Redact and mask remove the values; whether the remaining text is anonymous depends on what else it contains (e.g. a rare job title plus a city). Partial and hash are pseudonymization, still personal data under the law. Review your use case with your DPO.

Why was a number not detected as CPF? Unformatted 11-digit numbers pass the CPF check digit by chance about 1 time in 10, so they are only treated as CPF when "CPF" (or a field name like cpf_cliente) is nearby. Formatted CPFs (529.982.247-25) are always detected.

Which languages are supported for names? Portuguese and English models. Documents, e-mails, phones and cards work in any language.

Can it process PDFs or images? Not directly; extract the text first. For faces and plates in images and videos, see the anonymizer below.

Models and licenses: spaCy pt_core_news_sm (CC BY-SA 4.0) and en_core_web_sm (MIT) for names; everything else is rule-based.

Support

Missing a document type or format? Open an issue in the Issues tab with a (fictitious) example.

Need a different tool? Request it

Missing a feature, an input or output format, or a whole different tool for your workflow? Open an issue in the Issues tab and describe what you need:

  • what goes in (files, URLs, data) and what should come out,
  • roughly how much you process (per day or month),
  • one example, if you can share it.

Requests with a real use case get built, either as a new option in this Actor or as a new Actor in this collection, and you get notified in the issue when it's live. Every request is read.