Skip to content
Intura
Products / Models / Guardrails
IndonesianGuardrailsEntity extraction (NER)

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

Under the hood
Indonesian
Base modeldistilbert-base-multilingual-cased
Parameters66.0M
Size66.6 MB
FormatONNX INT8
Max tokens128

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.

python
  1. >>> 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

  2. >>> classify("Status Pembayaran: LUNAS. Jumlah Transaksi: Rp 8.000.000. Metode Pembayaran: Kartu Kredit (sudah terenkripsi). Booking ID: MNB001.")

    []

    # Reference: nothing ✓ Matches

  3. >>> 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

  4. >>> classify("Udh selesai ya maintenance sistemnya? Mau coba login ulang.")

    []

    # Reference: nothing ✓ Matches

  5. >>> 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:

The classes this model learned to recognise:
LabelMeaning
PERSONA person's name.
NATIONAL_IDNational identity number — NIK, NRIC, SSN.
TAX_IDTaxpayer number — NPWP, TIN.
PASSPORTPassport number.
PHONEPhone or mobile number.
EMAILEmail address.
ADDRESSStreet or postal address.
ACCOUNTBank account number or IBAN.
CREDIT_CARDPayment card number.
IP_ADDRESSIPv4 or IPv6 address.
DOBDate of birth.

The first five example rows, with the label each one carries:

The first five example rows, with the label each one carries:
#TextLabel
0Tagihan 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
1Status Pembayaran: LUNAS. Jumlah Transaksi: Rp 8.000.000. Metode Pembayaran: Kartu Kredit (sudah terenkripsi). Booking ID: MNB001.nothing
2Tanggal Lahir saya adalah 10/06/1990. Mohon cek data KTP 3374091006900007.DOB, NATIONAL_ID
3Udh selesai ya maintenance sistemnya? Mau coba login ulang.nothing
4Hasil 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. 1

    Get it

    Sign in on this site and press Get it. The model goes to your library with every version.

  2. 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. 3

    Install

    pip install "intura-ai[local]" — the SDK plus the CPU runtime it uses to run a model on your machine.

  4. 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.

run.py
# 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.

  1. v1.1RecommendedONNX INT866.6 MBReleased Oct 17, 2026
  2. v1.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.

Start with

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.