Get Started
On-device PII anonymization for Expo, React Native, the browser and Node. Redact locally, send only placeholders to any LLM, rehydrate the reply.
local-pii anonymizes personal data before it leaves the device, sends only
placeholders to your LLM, and rehydrates the reply locally. The
placeholder → original mapping never leaves the device.
Ontem encontrei João Silva. Meu telefone é +49 151 12345678.
│ anonymize (on device)
▼
Ontem encontrei [GIVEN_NAME_1] [SURNAME_1]. Meu telefone é [PHONE_1]. ← only this is sent
│ ↕ your LLM
▼ rehydrate (on device)
João Silva / +49 151 12345678 come back — the mapping never left the device.Install
bun add local-pii # or npm / pnpm / yarnThe deterministic pipeline (emails, phones, cards, IBAN, SSN, IP, URLs) works with nothing else installed, in React Native, the browser and Node.
Quickstart
import { createAnonymizer, rehydrate } from "local-pii"
const pii = createAnonymizer()
const { redactedText, mapping } = await pii.anonymize(
"Email me at ana@acme.com or call +49 151 12345678",
)
// redactedText → "Email me at [EMAIL_1] or call [PHONE_1]"
const reply = await callYourLlm(redactedText) // only placeholders leave the device
const answer = rehydrate(reply, mapping) // originals restored locallymapping is plain data ({ "[EMAIL_1]": "ana@acme.com", … }). Keep it in
memory — never log it, send it, or put it in analytics/crash reports.
Add on-device AI
The deterministic detectors don't catch names or addresses — that's the Rampart NER model's job. Pick the backend for your platform:
- Expo / React Native →
rampart()viaonnxruntime-react-native. - Browser / web →
rampartWeb()viaonnxruntime-web(WASM/WebGPU).
import { createAnonymizer } from "local-pii"
import { rampart } from "local-pii/expo" // or: rampartWeb from "local-pii/web"
const pii = createAnonymizer({
ner: rampart({ model: require("@local-pii/model-rampart/assets/rampart-q4.onnx") }),
})
// "Ontem encontrei João Silva" → "Ontem encontrei [GIVEN_NAME_1] [SURNAME_1]"Wrap your LLM calls
Adapters wrap the whole anonymize → call → rehydrate cycle, including tool calls, so you barely change your code:
- Vercel AI SDK —
withPii(model) - OpenAI & Grok/xAI —
withPiiOpenAI(client)
Where next
- Core Concepts — the pipeline, sessions, the vault, trust boundaries
- Placeholder Strategies —
sequential,hashed,token - Tool Calls — the hard part, solved
- Limitations — what it does not catch (read this)