Learn how to automatically find, classify, and locate person names in text, documents, chat logs, and transcripts using PII Detection API. Context-aware AI handles titles, multicultural name formats, and lookalike words that trip up regex-based scanners.
A person's name is the most fundamental piece of personally identifiable information there is, and it is also the hardest one to find reliably. Names have no fixed pattern: there is no character class, no checksum, and no standard length that separates "Amara Okafor" from any other pair of capitalized words. A name can be two words, one word, or five. It can carry a title, a suffix, a hyphen, an apostrophe, or diacritics. It can also be a word that means something else entirely in another sentence — "Hunter" is a person in one support ticket and a job description in the next.
PII Detection API solves this with transformer-based named entity recognition (NER) rather than pattern matching. The model reads the surrounding sentence, so it knows that "May Johnson called yesterday" contains a person while "May sales exceeded targets" does not. When you scan text for the PERSON_NAME entity, the API returns every detected name with its exact character offsets, its matched text, and a confidence score — and, if you want it, a masked copy of the input as an optional next step.
This guide walks through the full problem space: why name detection matters for compliance, how to call the API, which name formats and cultural conventions you need to plan for, how to keep false positives under control, and how to tune detection for your own domain. Everything shown here also works across the other 150+ entity types listed on our supported entities page.
Name detection is usually the first requirement in any data protection project, because names are the anchor that links every other data point to an identifiable human being. A leaked phone number is a nuisance; a leaked phone number next to a full name is a reportable incident. Knowing exactly where names live in your text is the precondition for redaction, access control, data mapping, and breach response.
Detection first, redaction second. Many teams jump straight to masking, but detection output on its own — types, offsets, confidence — is what powers data inventories, DSAR search, and risk scoring. PII Detection API always returns the structured entity list; the masked text is an optional extra controlled by mask_mode.
One HTTPS request is all it takes. Send your text to the REST API with the PERSON_NAME entity selected, and you get back every detected name with offsets and confidence scores. Grab a free key on the get started page or try it without code in the live demo.
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": "Please forward the invoice to Priya Ramanathan. Her manager, Dr. James O'\''Neill-Baker, signs off on Fridays.", "entities": ["PERSON_NAME"], "mask_mode": "replace" }'
import requests resp = requests.post( "https://piidetectionapi.com/api/moderate.php", json={ "api_key": "YOUR_API_KEY", "api_type": "pii_detection", "text": "Please forward the invoice to Priya Ramanathan. " "Her manager, Dr. James O'Neill-Baker, signs off on Fridays.", "entities": ["PERSON_NAME"], "mask_mode": "replace", }, timeout=30, ) data = resp.json() for e in data["detected_entities"]: print(e["type"], e["text"], e["start"], e["end"], e["confidence"])
const resp = await fetch("https://piidetectionapi.com/api/moderate.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ api_key: "YOUR_API_KEY", api_type: "pii_detection", text: "Please forward the invoice to Priya Ramanathan. Her manager, Dr. James O'Neill-Baker, signs off on Fridays.", entities: ["PERSON_NAME"], mask_mode: "replace" }) }); const data = await resp.json(); data.detected_entities.forEach(e => console.log(e.type, e.text, e.start, e.end, e.confidence) );
The response contains the structured entity list plus, because mask_mode was set, a masked copy of the input:
{
"detected_entities": [
{"type": "PERSON_NAME", "text": "Priya Ramanathan", "start": 30, "end": 46, "confidence": 0.97},
{"type": "PERSON_NAME", "text": "James O'Neill-Baker", "start": 66, "end": 85, "confidence": 0.96}
],
"anonymized_text": "Please forward the invoice to [NAME]. Her manager, Dr. [NAME], signs off on Fridays.",
"entities_detected": 2,
"processing_time_ms": 142,
"mask_mode_used": "replace",
"status": 200
}
A few practical notes on the request contract. The text field accepts up to 50,000 characters per request, so most documents fit in a single call. If you omit entities, the API scans for all 150+ supported types at once; passing ["PERSON_NAME"] narrows the scan and shaves latency. The start and end offsets are zero-based character positions into the exact string you sent, which makes it trivial to highlight matches in a UI or splice in your own replacements.
The same human being can appear in your data under a dozen surface forms, and a detector that only recognizes "Firstname Lastname" will miss most of them. Before you trust any name detection pipeline, test it against the formats that actually occur in your text.
Titles are strong contextual evidence that a name follows: "Dr.", "Mr.", "Mrs.", "Ms.", "Prof.", "Rev.", "Sen.", "Capt.", and their international equivalents ("Herr", "Señora", "Monsieur"). PII Detection API uses titles as detection signals but keeps the entity span on the name itself, so "Dr. Sarah Mitchell" yields the entity "Sarah Mitchell" and your masked output reads "Dr. [NAME]" — preserving the professional role, which is often useful analytical context. Job titles that precede names ("CFO Elena Petrova") behave the same way.
Watch the short forms. Single-token mentions ("Sarah", "Reyes") carry less context than full names and typically score lower confidence. If you filter aggressively with a high threshold, first-name-only mentions are the matches you will lose first. Test with real samples from your own corpus before locking in a threshold.
If your users come from more than one country — and they do — your name detector must handle naming conventions that break every Western assumption. There are cultures with no surnames, cultures where the family name comes first, and cultures where a single person's legal name contains four or five components with connective particles. PII Detection API's models are trained on multilingual corpora covering 60+ languages, so these conventions are recognized natively rather than forced through an anglocentric template.
| Convention | Example | What detection must handle |
|---|---|---|
| Western given-name-first | Emily Carter | Baseline case; middle names and initials extend the span |
| East Asian family-name-first | Zhang Wei, Kim Min-jun, Sato Haruka | Order inversion; two-character given names; romanized and native-script forms of the same person |
| Spanish / Portuguese compound surnames | María García Rodríguez, João Souza dos Santos | Two family names (paternal + maternal); particles like "de", "dos", "da" inside the span |
| Arabic patronymic chains | Mohammed bin Rashid Al Maktoum | Connectives "bin"/"ibn"/"bint", definite article "Al-", long multi-part spans |
| Icelandic patronymics | Björk Guðmundsdóttir | No inherited surname; "-son"/"-dóttir" endings; diacritics (ð, þ, ö) |
| Indian conventions | Ravichandran Ashwin, A. R. Rahman | Initial-heavy South Indian forms; village or father's name used as prefix; honorifics like "Shri" |
| Mononyms | Sukarno, Dewi | Single-token legal names common in Indonesia and elsewhere; no second token to confirm |
| Slavic gendered surnames | Ivan Petrov / Anna Petrova | Same family, different surname endings; patronymic middle names ("Sergeyevich") |
Two consequences follow for your integration. First, never post-process detected names with assumptions like "the last token is the surname" — that is wrong for a third of the planet. Treat the text span the API returns as the complete name unit. Second, expect the same person to appear in multiple scripts (for example "村上春樹" and "Haruki Murakami") within a bilingual document; the API detects both, but they are separate entity occurrences with separate offsets.
Language support: The full list of supported languages is on our supported languages page. You do not need to declare the language in the request — detection is language-agnostic and handles mixed-language text in a single call.
The hardest part of name detection is not finding names — it is not finding things that merely look like names. English is full of words that moonlight as first names, and the corporate world is full of organizations named after their founders. A detector that flags every capitalized pair destroys data utility: masking "Morgan Stanley" in a finance ticket or "Paris" in a travel itinerary makes the text useless.
Because the model reads full sentence context, these distinctions come built in. Your remaining levers are the threshold parameter, which suppresses low-confidence borderline matches, and custom_instruction, which lets you declare domain-specific exclusions in plain English — both covered in the next sections. When you do encounter a systematic false positive in your domain (say, an internal project codenamed "Rebecca"), a one-line custom instruction fixes it without retraining anything.
Teams routinely start with a regex like [A-Z][a-z]+ [A-Z][a-z]+ plus a dictionary of common first names. It fails in both directions at once. It misses "bell hooks" (lowercase by choice), "LeBron" (mid-word capital), "O'Neill-Baker" (punctuation), "Zhang Wei" written as "ZHANG Wei" (academic convention), every mononym, and every name absent from the dictionary — which disproportionately means non-Anglo names, turning your privacy tool into a bias generator. Simultaneously it flags "New York", "Best Buy", "Happy Monday", and every capitalized sentence opener.
Dictionary lookups cannot fix this, because the set of human names is open-ended and overlaps heavily with the set of everything else. What works is what the NLP field converged on: transformer-based NER models that classify each token using bidirectional sentence context. The verb next door ("May reviewed the file" vs "in May"), the presence of a title, agreement with pronouns later in the sentence — all of it feeds the decision. That is the architecture behind PII Detection API, and it is why the service ships confidence scores: the model's certainty is real information you can route on, rather than a binary regex hit. For a deeper comparison of the approaches, see our guide NER vs Regex vs Rules.
Hybrid by design: For pattern-shaped entities like SSNs or credit cards, deterministic structure checks add value — and the API uses them where they help. Names have no structure to check, which is why they are the entity type where AI-based detection outperforms rules by the widest margin.
Every detected entity carries a confidence between 0 and 1, and the request-level threshold parameter (default 0.5) filters what the API returns. Where you set it is a precision/recall trade-off that should follow from your use case, not from a default.
# High-recall scan for a redaction pipeline 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": "Rose from accounting said Hunter Willis already signed.", "entities": ["PERSON_NAME"], "threshold": 0.35 }'
import requests # Low threshold: catch short, ambiguous mentions; review the borderline ones resp = requests.post( "https://piidetectionapi.com/api/moderate.php", json={ "api_key": "YOUR_API_KEY", "api_type": "pii_detection", "text": "Rose from accounting said Hunter Willis already signed.", "entities": ["PERSON_NAME"], "threshold": 0.35, }, timeout=30, ) for e in resp.json()["detected_entities"]: bucket = "auto-mask" if e["confidence"] >= 0.7 else "review" print(bucket, e["text"], e["confidence"])
const resp = await fetch("https://piidetectionapi.com/api/moderate.php", { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ api_key: "YOUR_API_KEY", api_type: "pii_detection", text: "Rose from accounting said Hunter Willis already signed.", entities: ["PERSON_NAME"], threshold: 0.35 }) }); const { detected_entities } = await resp.json(); const toReview = detected_entities.filter(e => e.confidence < 0.7);
The custom_instruction field (up to 500 characters) lets you steer detection with natural language — no allow-list files, no model retraining. Typical uses for names: excluding public figures quoted in news content, keeping author bylines intact, or ignoring your own staff signatures in outbound email templates.
resp = requests.post( "https://piidetectionapi.com/api/moderate.php", json={ "api_key": "YOUR_API_KEY", "api_type": "pii_detection", "text": article_text, "entities": ["PERSON_NAME"], "custom_instruction": "Do not flag names of public figures or " "politicians quoted in the article, and keep " "the author byline at the top untouched.", "mask_mode": "replace", }, timeout=30, )
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": "Senator Maria Cantwell praised the ruling. Our reader Tom Bailey disagreed by email.", "entities": ["PERSON_NAME"], "custom_instruction": "Do not flag names of public figures or politicians; only flag private individuals.", "mask_mode": "replace" }'
In the cURL example above, only "Tom Bailey" is returned as an entity — the senator is recognized as a public figure and excluded per the instruction. This is the fastest way to encode editorial policy that pure entity selection cannot express.
Real documents mention the same person many times and in shrinking forms: "Dr. Sarah Mitchell" in paragraph one becomes "Sarah" in paragraph three, "Dr. Mitchell" in paragraph five, and "she" everywhere in between. For detection purposes, each named mention is returned as its own entity occurrence with its own offsets — which is exactly what you want for redaction, since every surface form must be found and handled.
Where the linkage matters is downstream analysis. If you need to know that three mentions refer to one individual — counting distinct people in a dataset, or tracking one customer through a long thread — use mask_mode: "hash". Hash mode replaces each detected name with a consistent, irreversible token, so identical names map to identical placeholders throughout the text. The narrative structure survives ("PERSON_a7f3 emailed PERSON_c21b, then PERSON_a7f3 called back") while the identities do not.
Pronouns ("she", "her") are deliberately not treated as PERSON_NAME entities — masking every pronoun would shred readability while adding little privacy, since a pronoun with no name nearby identifies no one. If your risk model requires it, pronoun context is usually neutralized automatically once all names, email addresses, and phone numbers around them are gone.
A name rarely travels alone. Emails embed names ("priya.ramanathan@..."), signatures stack name, phone, and address together, and a redacted name next to an intact email is no privacy at all. Request the whole cluster in one call:
resp = requests.post( "https://piidetectionapi.com/api/moderate.php", json={ "api_key": "YOUR_API_KEY", "api_type": "pii_detection", "text": signature_block, "entities": ["PERSON_NAME", "EMAIL_ADDRESS", "PHONE_NUMBER", "ADDRESS"], }, timeout=30, )
Benchmark accuracy numbers are computed on news text; your data is support tickets, medical notes, or chat slang. Sample a few hundred real records, run them through the interactive demo or the API, and hand-check the misses and the false alarms before choosing a threshold. Measure precision and recall separately — they fail in different directions and demand different fixes.
When applying your own downstream logic, always use the returned start/end offsets instead of re-searching for the matched text. String search breaks when the same word appears both as a name and as a common noun ("Bill" the person vs "bill" the invoice) — the offsets are unambiguous.
Detection feeding a search index can run fully automated. Detection feeding permanent redaction of legal originals should route sub-0.7-confidence matches through review. The confidence score exists precisely so you can automate the easy 95% and escalate the rest.
New products, new hires, and new slang change your text over time. Re-run your validation sample quarterly, and encode any recurring domain exceptions with custom_instruction rather than post-processing hacks. Volume pricing for continuous scanning workloads is on our pricing page.
On mixed real-world benchmarks the PERSON_NAME model operates in the high-90s F1 range, with full names scoring higher than isolated single-token mentions. Accuracy varies by language and domain, which is why every match carries a confidence score — you can hold automated actions to a stricter standard than review queues. Our guide to measuring detection accuracy explains how to run your own evaluation.
Names are detected in 60+ languages, including languages without capitalization (Chinese, Japanese, Arabic, Hebrew) where casing heuristics are useless and context is the only signal. Mixed-language documents work in a single request with no language parameter needed.
No — context-aware NER classifies "Morgan Stanley" as an organization when the sentence treats it as one, so it is not returned under PERSON_NAME. If a specific ambiguous term in your domain keeps getting misclassified, add a one-line custom_instruction to exclude it.
Yes. The model flags anything functioning as a person name in context, whether the person is real, historical, or fictional. If you want public or historical figures excluded — common in media and publishing pipelines — say so in custom_instruction and only private individuals will be returned.
PERSON_NAME returns the complete name span as it appears in text, whether that is a full name, a lone first name, or an initialed form. Given the diversity of global name structures, splitting spans into "first" and "last" components reliably is not possible in general — if your workflow needs partial masking, use the returned span and apply your own formatting to it.
Use mask_mode: "hash". Identical names map to identical irreversible placeholders, so counts, threads, and relationships survive masking while the actual identity is removed. This is the standard pattern for analytics on anonymized support and chat data.
Test the PERSON_NAME detector on your own text in the live demo, or grab an API key and integrate in minutes.
Try the Live Demo View Pricing