How automated detection turns GDPR's abstract duties into running code: finding Article 4 personal data in unstructured content, enforcing minimization, answering DSARs, scoping breaches, and applying pseudonymization that satisfies Article 32.
Explore the GuideGDPR Article 4(1) defines personal data as "any information relating to an identified or identifiable natural person." Every word in that sentence was chosen to be broad. "Any information" covers opinions, behavior, and inferences, not just identifiers. "Relating to" captures data that is about a person even when it does not name them. And "identifiable" means identification does not have to have happened — it is enough that it reasonably could, directly or indirectly, using the data plus anything else reasonably available.
The article's own examples make the scope concrete: a name, an identification number, location data, an online identifier, or factors specific to physical, physiological, genetic, mental, economic, cultural, or social identity. Recital 30 adds IP addresses, cookie identifiers, and RFID tags explicitly. European case law has extended the definition to written exam answers, vehicle telemetry, and dynamic IP addresses held by website operators. If your systems touch EU residents, the working assumption should be: free text about people almost certainly contains personal data.
This breadth is precisely why detection has to be entity-diverse. A tool that only finds emails and phone numbers covers a fraction of Article 4. A GDPR-grade scan needs names, addresses, birth dates, national identifiers, IBANs, IP addresses and device identifiers, location data, and the Article 9 special categories — health, ethnicity, religion, political opinion, sexual orientation — which carry a near-prohibition on processing. PII Detection API covers all of these among its 150+ entity types, each returned with offsets and confidence so downstream systems can act precisely.
Equally important is what personal data is not: information about companies (though a sole trader's data is personal), and data rendered truly anonymous. The boundary between those categories and personal data is exactly where detection tooling earns its keep — the difference between "we believe this export is clean" and "we scanned it and can show the result."
Article 6 requires a lawful basis for every processing operation, and Article 5(2) requires you to be able to demonstrate compliance. Neither is possible for data you do not know you hold. Detection supports the lawful-basis regime in four concrete ways.
The Article 30 record of processing activities must describe categories of data subjects and personal data. Structured systems are easy to catalog; the free-text long tail — tickets, notes, logs, shared drives — is not. Scanning samples of each store with a broad entity list turns "we think this system holds contact data" into a documented inventory of which categories actually appear, and where. See database PII discovery for the systematic sweep.
Data collected for support under contract necessity cannot silently flow into marketing analytics or model training — that is a new purpose needing its own basis. A detection-and-masking step at the boundary between systems enforces this technically: the analytics copy leaves the support system with identifiers stripped, so the secondary use never touches raw personal data. The test data guide shows the same pattern for dev environments.
Article 9 data — health, ethnicity, religion, political opinions, sexual orientation — is prohibited to process unless a narrow exception applies. Users volunteer it anyway, in reviews, tickets, and chat. Detecting entity types like MEDICAL_DATA, RELIGION, and SEXUAL_ORIENTATION lets you alert or mask the moment special-category data appears where no Article 9 exception covers it.
Storage limitation (Art. 5(1)(e)) means personal data must go when its purpose expires — including the copies embedded in free text. Scheduled detection jobs over aging stores find the identifiers that survived their retention period, so erasure scripts can mask them in place instead of deleting whole documents that still have business value.
Minimization sounds like a design principle — collect only what you need — but in real organizations the battle is fought after collection, against accumulation. Users paste card numbers into chat despite the form saying not to. Debug logging captures full request bodies. Email threads accrete signatures, forwarded histories, and attachments. The dataset you designed minimally grows maximal on its own.
Detection converts minimization from policy into a pipeline property. The pattern that works is minimize-at-ingest: every write path into a durable store passes through a detection step that strips or masks the entity types that store has no purpose for. A ticket system needs the customer's name and contact details but never needs the card number a frustrated customer typed; a log store needs request semantics but not raw client IPs beyond the security-operations window; an LLM prompt log needs the conversation shape, not the identifiers inside it (see LLM guardrails).
The entities and exclude_entities parameters express these per-store policies directly: the same API call scrubs cards and SSNs from tickets while leaving names for service continuity, or hashes IPs in logs while preserving everything else. Because masking happens before storage, the minimized state is the only state — there is no raw copy to breach, subpoena, or forget about.
Supervisory authorities have repeatedly fined controllers for exactly this failure mode: data kept "just in case", call recordings never purged, logs retaining identifiers for years. A documented ingest-time masking pipeline is both the fix and — because the API returns entity counts per document — its own audit evidence.
Articles 15–17 give individuals the right to see, correct, and delete their data — and give you one month to comply. The hard part is never the structured profile; it is the mentions scattered through free text. Detection powers all three phases of a defensible DSAR workflow.
Keyword search finds exact strings; it misses nicknames, misspellings, and identifiers you did not think to search for. The stronger approach: run detection over candidate stores to extract all person-referring entities, then match the extracted set (name variants, emails, phone numbers, account identifiers) against the requester. This inverts the problem — instead of guessing search terms, you enumerate what is actually there and filter.
Article 15(4) requires that fulfilling one person's access request must not "adversely affect the rights and freedoms of others." A support thread about the requester also names agents, family members, and other customers. Before releasing the compiled file, run it back through detection and mask every personal entity that does not belong to the requester — a step manual DSAR teams routinely get wrong under deadline pressure.
PERSON_NAME, contact, and ID entities of non-requesterscustom_instruction can whitelist the requester's own identifiersArticle 17 erasure rarely means deleting whole documents — the invoice, the ticket, the audit trail must often survive for legal-obligation reasons. What must go is the personal data within them. Detection-driven masking rewrites each document with the requester's entities removed or replaced, satisfying erasure while preserving the record's non-personal content and your Article 17(3) retention carve-outs.
When personal data is breached, Article 33 gives you 72 hours from awareness to notify the supervisory authority — including a description of "the categories and approximate number of data subjects" and "the categories and approximate number of personal data records concerned." Article 34 then asks whether the breach poses high risk to individuals, which determines whether you must notify them directly. Both duties hinge on one question your incident team must answer under extreme time pressure: what exactly was in the exposed data?
For structured databases the schema answers it. For the exposed S3 bucket of support exports, the leaked log archive, or the compromised mailbox, nobody knows what is inside — and reading gigabytes manually in 72 hours is impossible. This is where bulk detection becomes an incident-response tool: stream the exposed corpus through the API and you get, per file, the entity types present and their counts. Aggregated, that is precisely the Article 33 inventory — "approximately 14,200 records containing names and emails; 310 containing IBANs; 12 containing health data."
The entity breakdown also drives the Article 34 risk call. Exposure of hashed newsletter emails and exposure of national identifiers or Article 9 health data are different universes of risk; regulators expect the notification decision to reflect that difference, with reasoning. A scan report gives the DPO defensible numbers instead of guesses — and if the scan shows the exposed copy had been masked at ingest, it may support the Article 33(1) position that the breach is "unlikely to result in a risk" at all.
Teams that practice this — keeping a ready-to-run bulk scanning script in their incident runbook — turn the worst 72 hours of the year into a mechanical exercise. The cybersecurity industry guide covers the full IR integration, and email PII scanning addresses the compromised-mailbox case specifically.
These two words decide whether GDPR applies to a dataset at all, and conflating them is one of the most common — and most consequential — compliance errors. Detection is the first step of both, but their legal effects are opposite.
Replacing identifiers so data can no longer be attributed to a person without additional information kept separately. Consistent hashing of names and account numbers (mask_mode: "hash") is the canonical example. Pseudonymized data is still personal data — every GDPR duty continues to apply — but the regulation rewards it: Article 32 names it as an appropriate security measure, it supports Article 6(4) compatibility for new purposes, and it materially lowers breach risk assessments.
Processing after which the person is no longer identifiable by any means reasonably likely to be used — by you or anyone else, considering cost, time, and available technology. Truly anonymous data exits GDPR entirely. The bar is high: removing direct identifiers is necessary but not sufficient, because quasi-identifier combinations (age + ZIP + occupation) re-identify. Irreversible masking of direct identifiers (mask_mode: "redact" or "replace") plus generalization of quasi-identifiers is the working recipe.
Choose pseudonymization when you still need to link records to individuals — ongoing analytics, fraud detection, longitudinal studies. Choose anonymization when the use case survives without re-identification — aggregate statistics, published datasets, most ML training data. In API terms: hash preserves linkage (pseudonymization); replace/redact with a broad entity list including quasi-identifiers moves you toward anonymization.
Neither technique is stronger than the detection feeding it. A pseudonymization pipeline that misses 8% of names leaves 8% of the dataset fully identified — and your risk assessment silently wrong. This is why recall measurement on your own data (see accuracy guide) belongs in the DPIA for any anonymization or pseudonymization project.
Article 32 requires "appropriate technical and organisational measures" proportionate to risk — and names pseudonymization first in its list of examples. In modern architectures, automated PII detection has become one of those baseline measures: it is the mechanism that keeps identifiers out of logs, prevents secrets and personal data mixing in telemetry, enforces masking before third-party transfers, and continuously verifies that supposedly-clean stores stay clean. When a supervisory authority asks what measures protected the data, "every ingest path runs context-aware PII detection with documented recall, and long-term stores hold only masked text" is a strong, evidenceable answer.
Article 35 requires a Data Protection Impact Assessment before high-risk processing — large-scale processing of special categories, systematic monitoring, innovative technologies (which today reliably includes LLM deployments). Detection appears twice in a good DPIA. As an input: scanning representative samples tells you which data categories the processing actually touches, replacing assumptions with measurements. As a mitigation: masking pipelines, threshold policies, and special-category alerts are exactly the kind of measures Article 35(7)(d) expects you to document against each identified risk.
Two practical notes. First, proportionality cuts both ways: for high-risk stores, run detection with a low threshold and human review of borderline matches; for low-risk internal telemetry, an automated default-threshold pipeline is proportionate. Second, if data residency or confidentiality rules prevent sending text to a cloud API even for scanning, the on-premise deployment runs the same engine inside your boundary — a configuration many DPIAs end up requiring for special-category workloads. See pricing and contact for deployment options.
GDPR-grade detection must recognize European identifier formats, not just US ones — and European names, addresses, and phrasing in 24 official languages. A sample of the EU-specific formats covered (the full list is on the entities page; language coverage on supported languages):
| Identifier | Country / Scope | Format Example | API Entity Type |
|---|---|---|---|
| IBAN | All EU/EEA (and beyond) | DE89 3704 0044 0532 0130 00 — country code + mod-97 check digits | IBAN_CODE |
| BIC / SWIFT | International banking | COBADEFFXXX | SWIFT_BIC |
| National insurance number | UK (NINO) | QQ 12 34 56 C | NATIONAL_ID |
| Codice fiscale | Italy | RSSMRA85M01H501Z — encodes name, birth date, and birthplace | NATIONAL_ID / TAX_ID |
| NIF / DNI | Spain | 12345678Z — with letter check digit | NATIONAL_ID |
| INSEE / NIR | France | 1 85 05 78 006 084 36 — encodes sex, birth year/month, and place | NATIONAL_ID |
| Steuer-ID | Germany | 12 345 678 901 — 11-digit tax identifier | TAX_ID |
| BSN | Netherlands | 123456782 — 9 digits with "11-test" checksum | NATIONAL_ID |
| PESEL | Poland | 44051401359 — encodes birth date and sex, with check digit | NATIONAL_ID |
| EU phone formats | All member states | +49 30 123456, +33 1 23 45 67 89, national conventions | PHONE_NUMBER |
| European addresses | All member states | Street-first and postcode conventions per country (e.g. "Hauptstraße 5, 10115 Berlin") | ADDRESS, ZIP_CODE, CITY |
| Online identifiers (Recital 30) | EU-wide | IPv4/IPv6, cookie IDs, device identifiers | IP_ADDRESS, COOKIE, DEVICE_ID |
Several of these formats carry internal checksums (IBAN mod-97, BSN 11-test, PESEL and codice fiscale check digits), which the validator layer verifies — the reason European identifier detection stays precise even in number-dense financial text. More detail in the bank account detection guide.
Three GDPR workflows against the live endpoint: an Article 33 breach-scope scan, an Article 32 pseudonymization pass, and a DSAR third-party redaction step.
# Python — breach-scope scan: entity category counts for an Art. 33 notification
import requests, collections, pathlib
counts = collections.Counter()
docs_affected = collections.Counter()
for path in pathlib.Path("exposed_bucket/").glob("**/*.txt"):
text = path.read_text(errors="ignore")[:50000]
resp = requests.post(
"https://piidetectionapi.com/api/moderate.php",
json={
"api_key": "YOUR_API_KEY",
"api_type": "pii_detection",
"text": text,
"threshold": 0.4, # favor recall during incident response
},
timeout=60,
)
entities = resp.json()["detected_entities"]
for e in entities:
counts[e["type"]] += 1
for t in {e["type"] for e in entities}:
docs_affected[t] += 1
print("Art. 33 inventory — entity type: total matches / files affected")
for t, n in counts.most_common():
print(f"{t}: {n} / {docs_affected[t]}")
# cURL — Art. 32 pseudonymization: consistent hashes keep analytics linkage
curl -X POST https://piidetectionapi.com/api/moderate.php \
-H "Content-Type: application/json" \
-d '{
"api_key": "YOUR_API_KEY",
"api_type": "pii_detection",
"text": "Kunde Hans Meier ([email protected], +49 171 2345678) überwies von DE89 3704 0044 0532 0130 00.",
"entities": ["PERSON_NAME", "EMAIL_ADDRESS", "PHONE_NUMBER", "IBAN_CODE"],
"mask_mode": "hash"
}'
# -> same customer yields the same tokens across every document,
# so cohort analytics survive while raw identifiers are gone
// JavaScript — DSAR disclosure prep: mask third parties, keep the requester
async function prepareDisclosure(documentText, requesterName, requesterEmail) {
const resp = await fetch("https://piidetectionapi.com/api/moderate.php", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
api_key: process.env.PII_API_KEY,
api_type: "pii_detection",
text: documentText,
entities: ["PERSON_NAME", "EMAIL_ADDRESS", "PHONE_NUMBER",
"ADDRESS", "DATE_OF_BIRTH", "NATIONAL_ID"],
mask_mode: "replace",
// Art. 15(4): protect others; the requester's own data stays visible
custom_instruction: `Do not mask information belonging to ${requesterName} (${requesterEmail})`,
}),
});
const data = await resp.json();
return { text: data.anonymized_text, auditCount: data.entities_detected };
}
mask_mode: "hash", you have pseudonymized, not anonymized — valuable, but still within GDPR scope.Scan a sample of your own data in the live demo — see exactly which Article 4 categories it contains — then choose a plan or an on-premise deployment.
Try the Live Demo View Pricing