Skip to content

pii · Guide

Categories ​

31 built-in categories: 28 regex/checksum categories in the pattern tier, plus 3 dictionary-only categories (person, organization, location) raised by the Turkish gazetteer pass. Only 11 are on by default — the rest are precise enough to be useful but not precise enough to run unattended.

Import categories / categoriesById (JS) or PII_CATEGORIES / PII_CATEGORIES_BY_ID (Python) to inspect this table at runtime. Pass your own categories map to detect/redact/mask/tokenizeText (or their Async counterparts) to override which ones run — see JavaScript API / Python API.

What defaultEnabled means ​

Every defaultEnabled: true category was a measurement, not a guess. Four categories added most recently — geoCoordinates, cardCvv, pin, macAddress — were spot-checked against 3,000 random rows of the project's own test corpus and 157 hand-written negative texts: every hit a genuine-looking match, zero false alarms on the negatives, so they ship on. username and password failed the same test: on the same 3,000 rows, roughly half of what the bare keyword-anchored patterns fired on was ordinary prose ("kullanıcı profili", "şifre sıfırlama"), because these categories have no shape to validate — unlike a checksum or a coordinate range, "the token after this keyword" is only as good as the keyword's own ambiguity in running text. They stay usable (enable them explicitly) but off by default.

tc_kimlik validates a real, official checksum digit, so a random 11-digit run does not false-positive just because of its length. tr_vkn also computes a checksum, but that algorithm has never been checked against an official test vector, so it ships off by default with a deliberately low base score (0.25) — treat a tr_vkn finding as context-dependent, not checksum-certain.

Global / cross-language ​

idDefaultValidatorNotes
emailOn— (regex only)RFC-style user@domain.tld. Mask keeps the domain and the first local-part character.
phoneOnFormat guard7–15 digits. Explicitly rejects IPv4-shaped runs, dd/mm/yyyy and yyyy/mm/dd dates, and bare 11-digit runs starting 2–9 (the shape of a checksum-invalid TCKN) — all measured false-positive sources against other categories.
creditCardOnLuhn checksum13–19 digits.
ibanOnLength only (15–34 chars)Not a mod-97 checksum — length-validated, not arithmetic-validated. Whitespace- and dash-grouping tolerant.
swiftOff—SWIFT/BIC code shape.
ipAddressOffOctet range (0–255)IPv4 only.
urlOff—http(s):// or www.
socialHandleOff—@handle-style, 3–30 chars.
apiKeyOff—Any opaque 32+ char [A-Za-z0-9_-] token — broad by design, so it stays opt-in.
cryptoWalletOff—Bitcoin (1…/3…) or Ethereum (0x…40 hex) address shapes.
birthDateOffCalendar-plausibilityNumeric dd/mm/yyyy, dd.mm.yyyy, yyyy-mm-dd, plus Turkish and English month-name forms ("4 Haziran 1987", "June 4, 1987"). Matches every calendar-valid date, not only birth dates — it has no way to tell them apart without a keyword.
geoCoordinatesOnLat/lon range (±90 / ±180)Decimal lat, lon pair, 4+ decimal places each — the digit-count guard is what keeps a Turkish thousands amount ("1.250,00 TL") or an IP octet run from matching.
usernameOff— (keyword-anchored)The token after kullanıcı adı / username / login; only the value is the finding, not the keyword.
passwordOff— (keyword-anchored)The token after şifre(m/mi/si) / parola(m) / password / pwd.
cardCvvOn— (keyword-anchored)3–4 digits after cvv/cvc/güvenlik kodu, including the Turkish possessive form (cvv'si).
pinOn— (keyword-anchored)4–6 digits after pin/pin kodu/şifre pin, including the Turkish possessive form (pin'i).
macAddressOnStructural checkSix hex octet pairs, one consistent separator; rejects all-zero and broadcast (FF:FF:FF:FF:FF:FF) addresses.

English-specific (languages: ['en']) ​

idDefaultValidatorNotes
address_enOff—US-style street address (Street, Ave, Blvd, …).
ssn_usOff—123-45-6789 digit-group shape only, no checksum.
passport_enOff—A1234567 / AB123456 shape only.

Turkish-specific (languages: ['tr']) ​

idDefaultValidatorNotes
tc_kimlikOnOfficial checksum (two-step mod-10)11-digit Turkish national ID. Tolerates space/hyphen-grouped forms people actually type; the checksum runs on the digits alone.
tr_phoneOnFormat guardMobile (5xx), landline (2xx/3xx/4xx area code), 444 short-codes, 0850 numbers.
tr_ibanOn— (regex shape only)TR + 24 digits, dash/space-grouping tolerant. Unlike iban, this category has no length or checksum validator at all.
tr_vknOffChecksum, unverified against an official test vector10-digit tax ID. Deliberately low baseScore (0.25) — needs a nearby context word ("vergi no", "VKN") to become a real finding.
tr_plakaOff— (regex shape only)Province code (01–81) + 1–3 letters + 2–5 digits.
tr_passportOff—Current format: U + 8 digits.
address_trOff—Mahalle/Mah. + a following No: building number, optionally Daire/Kat.

German-specific (languages: ['de']) ​

idDefaultValidatorNotes
de_phoneOff—+49 / 0 prefix.

Dictionary-only (no regex — raised by the gazetteer pass, pattern+dictionary+) ​

idDefaultSourceNotes
personOffGazetteer (pattern+dictionary) or the char-CNNA person's name. See Turkish specifics for how titles, first/surname pairs, and case suffixes are handled.
organizationOffGazetteer or char-CNNA capitalised run ending in a known organisation suffix (A.Ş., Ltd. Şti., Holding, …).
locationOffGazetteer or char-CNNA province or district name, or a province/district pair.

person/organization/location are listed with defaultEnabled: false in the catalog, but they only ever fire when you opt into pattern+dictionary (or a later mode) — the pattern-only default set never includes them regardless.

Spelled-out digits ​

Independent of the category table above: the pattern tier also reconstructs digit-word runs ("tc sıfır sekiz iki beş üç dört beş dokuz yedi altı dokuz") in Turkish and English, 7–32 words long, and hands the reconstructed digit string to the same validators the digit-shaped categories already use. A spelled-out number becomes a candidate only when it would have been a real finding written as digits, and it is only ever a front-tier (L1) candidate — pattern+ner-verified passes it through unjudged, because the model was never trained on spelled numbers. See Turkish specifics for the full word list and the run-boundary rules.

Custom patterns ​

Both languages accept your own rules via customPatterns (JS) / custom_patterns (Python) — id, category id, a regex source string, flags, an optional severity, and an enabled flag. Each one runs through a bounded sweep so a catastrophic pattern cannot hang the process: JavaScript compiles it inside a vm context with a wall-clock timeout (the only thing that can interrupt a synchronous regex mid-match); Python uses a SIGALRM-based timeout, which is POSIX- and main-thread-only — see the Python API for that platform limitation. A pattern source longer than 512 characters is rejected outright. See JavaScript API and Python API for the exact option shape.

Where to go next ​

  • Detection modes — which categories the CNN judge can score at all (CATEGORY_TO_CNN_TYPE).
  • Turkish specifics — checksums, suffix trimming, homonyms, and case handling in depth.
  • Redaction & tokens — the mask strategy each category uses when you call mask().

Studio · Pulse · Console · Agent SDK and more — the Cognipeer documentation hub