PII Detector
Finds names, ID numbers, addresses and 8 more kinds of personal data as character spans.
A named-entity model that returns the exact character offsets of personal data in a text, across eleven entity types, so you can mask, redact or route on the substring that is sensitive. Regular expressions find what has a format; this model is for what does not — names, addresses, and numbers that are personal only because of the sentence around them. Use both.
What it answersA list of spans: entity type, start and end offsets, and the matched text.
Specs
Under the hood
| Indonesian | |
|---|---|
| Base model | distilbert-base-multilingual-cased |
| Parameters | 66.0M |
| Size | 66.6 MB |
| Format | ONNX INT8 |
| Max tokens | 128 |
Distilled from the base model by keeping fewer layers and trimming the vocabulary to the languages served, then quantised to INT8 so it fits a CPU, an edge device or embedded hardware.
Use cases
What you can do with it
Masking before text reaches an LLM
Replace each span with a placeholder such as [NAME] or [NATIONAL_ID] before a prompt leaves your network, then restore them in the answer.
Redacting logs and support transcripts
Run it in the pipeline that ships logs to your warehouse, so analytics never holds a customer's NIK or phone number.
Compliance with UU PDP
Personal data that never leaves your servers is the simplest data-protection story. The model runs on the same machine as the data.
Example results
Example results
Real outputs of this exact build on held-out rows — data it never saw in training. Each shows the input, what the model answered, and the reference label it was checked against. Nothing here is written by hand.
>>> classify("Tagihan Jasa Kurir Ekspres. Invoice Ref: KRE/2024/6/1500. Alamat Pengirim: Jl. Raya Cimahi No. 7, 40523. Alamat Tujuan: Jl. Gajah Mada No. 11, 10130. Total Biaya: Rp 75.000.")
[ { "type": "ADDRESS", "start": 75, "end": 103, "value": "Jl. Raya Cimahi No. 7, 40523", "score": 0.9965 }, { "type": "ADDRESS", "start": 120, "end": 148, "value": "Jl. Gajah Mada No. 11, 10130", "score": 0.9967 } ]# Reference: ACCOUNT, ADDRESS, ADDRESS ✗ Differs
>>> classify("Status Pembayaran: LUNAS. Jumlah Transaksi: Rp 8.000.000. Metode Pembayaran: Kartu Kredit (sudah terenkripsi). Booking ID: MNB001.")
[]
# Reference: nothing ✓ Matches
>>> classify("Tanggal Lahir saya adalah 10/06/1990. Mohon cek data KTP 3374091006900007.")
[ { "type": "DOB", "start": 26, "end": 36, "value": "10/06/1990", "score": 0.9962 }, { "type": "NATIONAL_ID", "start": 57, "end": 73, "value": "3374091006900007", "score": 0.9948 } ]# Reference: DOB, NATIONAL_ID ✗ Differs
>>> classify("Udh selesai ya maintenance sistemnya? Mau coba login ulang.")
[]
# Reference: nothing ✓ Matches
>>> classify("Hasil Tes Lab Darurat. Pasien: Galih Rakasiwi. Akses Log masuk dari IP Address: 192.168.1.105.")
[ { "type": "PERSON", "start": 31, "end": 45, "value": "Galih Rakasiwi", "score": 0.9963 }, { "type": "IP_ADDRESS", "start": 80, "end": 93, "value": "192.168.1.105", "score": 0.9955 } ]# Reference: PERSON, IP_ADDRESS ✗ Differs
Training data
Training data
Synthetic documents generated with Gemini on Vertex AI with labelled character spans, across genres from chat to contracts. Scored at entity level: a name found as "Budi" when it was "Budi Santoso" counts as a miss.
The classes this model learned to recognise:
| Label | Meaning |
|---|---|
PERSON | A person's name. |
NATIONAL_ID | National identity number — NIK, NRIC, SSN. |
TAX_ID | Taxpayer number — NPWP, TIN. |
PASSPORT | Passport number. |
PHONE | Phone or mobile number. |
EMAIL | Email address. |
ADDRESS | Street or postal address. |
ACCOUNT | Bank account number or IBAN. |
CREDIT_CARD | Payment card number. |
IP_ADDRESS | IPv4 or IPv6 address. |
DOB | Date of birth. |
The first five example rows, with the label each one carries:
| # | Text | Label |
|---|---|---|
| 0 | Tagihan Jasa Kurir Ekspres. Invoice Ref: KRE/2024/6/1500. Alamat Pengirim: Jl. Raya Cimahi No. 7, 40523. Alamat Tujuan: Jl. Gajah Mada No. 11, 10130. Total Biaya: Rp 75.000. | ACCOUNT, ADDRESS, ADDRESS |
| 1 | Status Pembayaran: LUNAS. Jumlah Transaksi: Rp 8.000.000. Metode Pembayaran: Kartu Kredit (sudah terenkripsi). Booking ID: MNB001. | nothing |
| 2 | Tanggal Lahir saya adalah 10/06/1990. Mohon cek data KTP 3374091006900007. | DOB, NATIONAL_ID |
| 3 | Udh selesai ya maintenance sistemnya? Mau coba login ulang. | nothing |
| 4 | Hasil Tes Lab Darurat. Pasien: Galih Rakasiwi. Akses Log masuk dari IP Address: 192.168.1.105. | PERSON, IP_ADDRESS |
intura-ai script
Run it with the intura-ai SDK
- 1
Get it
Sign in on this site and press Get it. The model goes to your library with every version.
- 2
Create a download key
On your account page, create a download key and set it as INTURA_API_KEY. It only downloads what you own.
- 3
Install
pip install "intura-ai[local]" — the SDK plus the CPU runtime it uses to run a model on your machine.
- 4
Run it
Run the script. It downloads the build once and checks each file's SHA-256, then runs on your CPU, edge box or embedded Linux — no network call after the download.
# pip install "intura-ai>=3.0.0"
# export INTURA_API_KEY=... # a download key from your account
from intura_ai import Intura, LocalModel
client = Intura()
# Downloads once into ./guardrails-pii-detection-id/v1.1; later runs reuse the files on disk.
model_dir = client.models.download("guardrails-pii-detection-id", version="v1.1")
model = LocalModel.load(model_dir) # CPU, no network from here on
print(model.predict('Tagihan Jasa Kurir Ekspres. Invoice Ref: KRE/2024/6/1500. Alamat Pengirim: Jl. Raya Cimahi No. 7, 40523. Alamat Tujuan: Jl. Gajah Mada No. 11, 10130. Total Biaya: Rp 75.000.'))
# [{"type": ..., "start": ..., "end": ..., "value": ...}, ...]Offsets index into the exact string you passed. Mask on that string, not on a re-tokenised copy. Gini does not apply to span extraction; precision, recall and F1 are entity-level.
Want to see what it answers before you get it? Read the Example results
Versions
Versions
Every version stays downloadable once you own the model. A version id names exactly the bytes you download.
v1.1RecommendedONNX INT866.6 MBReleased Oct 17, 2026v1.0ONNX INT866.6 MBReleased Oct 14, 2026
Feedback
Need something changed in this model?
Ask for a new label or language, tell us where it misses on your data, get help running it, or report a bug. A person reads every message and replies by email.
Find the model for your task.
Search by what it has to do, read real example results, and download it to run on your own CPU — from $9 during early bird.