Important
This repository is deprecated. Development has moved to
Desert-Ant-Labs/desert-ant-core.
Redact's SDK now lives in that monorepo, written once and bound to every platform, alongside the other Desert Ant model SDKs:
| What | Where it lives now |
|---|---|
| Swift / Core ML | Sources/ModelCatalog/Redact/ (SwiftPM product Redact) |
| JavaScript / TypeScript | packages/redact-node/ |
| Kotlin / Android | packages/redact-kotlin/ |
Nothing changes for you if you install from a package manager. The published
coordinates are the same: @desert-ant-labs/redact on npm, ai.desertant:redact
on Maven Central, and the model on the Hub at
desert-ant-labs/redact.
Swift Package Manager users depend on desert-ant-core and take its Redact
product instead of pointing at this repository.
Issues and pull requests should go to the monorepo. This repository stays up so
existing SwiftPM pins keep resolving, but it no longer receives fixes: the last
release from here was v0.7.3.
On-device multilingual PII redaction for Swift, Android, and JavaScript. Redact finds and masks personal data in text: names, addresses, emails, phone numbers, cards, IBANs, national IDs, VAT numbers, URLs, IP addresses, and more across all 24 official EU languages. Everything runs locally, so your text never leaves the device or browser.
Redaction is reversible. Mask PII before sending text to an LLM or another service, then restore the originals in the response on device. Keep the placeholder mapping and the result is pseudonymized; drop it and the masked copy is anonymized.
Email Anna Kovács at anna@example.hu.
Email [GIVEN_NAME_1] [SURNAME_1] at [EMAIL_1].
- Features
- Swift
- Android
- JavaScript and TypeScript
- Reversible redaction for LLMs
- Categories
- Model and caching
- License
- Runs fully on device or in the local runtime. Text never leaves the machine.
- Detects 20 model categories plus deterministic IMEI: names, addresses, emails, phone numbers, credit cards, IBANs, routing numbers, IP addresses, URLs, government IDs, passports, driving licences, tax IDs, SSNs, and more.
- Supports all 24 official EU languages, including Latin, Greek, and Cyrillic scripts.
- Validates structured fields with dependency-free rules: Luhn cards, ISO-13616 IBANs, BIC, VIN, checksum-validated national IDs for all 24 EU countries, all 27 EU VAT numbers, IMEI, and per-country driving licences.
- Reversible redaction with unique numbered placeholders such as
[EMAIL_1]and[BANK_ACCOUNT_1]. - Small 4-bit model, downloaded on demand and cached by default, or bundled for offline apps.
Requirements: iOS 16+, macOS 13+, tvOS 16+, visionOS 1+, and Swift 5.9+.
Add Redact with Swift Package Manager:
.package(url: "https://github.com/Desert-Ant-Labs/redact.git", from: "0.7.3")Then add the Redact product to your app target.
To bundle the Core ML model for fully offline Apple apps, also add RedactCoreMLResources to your target.
Create one Redact and reuse it. Construction is cheap and non-blocking. The model loads on first use, or earlier if you call download.
import Redact
let redact = Redact()
let result = try await redact.redaction(of: "Email Anna Kovács at anna@example.hu.")
print(result.redactedText)
// Email [GIVEN_NAME_1] [SURNAME_1] at [EMAIL_1].
for item in result.items {
print(item.label.displayName, item.original, item.confidence)
}
let reply = try await myLLM.rewrite(result.redactedText)
let restored = result.restore(reply)Filter by category:
let options = Options(labels: [.email, .phone, .creditCard, .bankAccount])
let contactOnly = try await redact.redaction(of: text, options: options)Choose where the model comes from:
let redact = Redact() // managed cache, download on demand
let redact = Redact(directory: myModelDir) // explicit model directory
let redact = Redact(bundle: myBundle) // bundled model resourcesDownload ahead of time, for example from an onboarding screen:
let redact = Redact()
if !redact.isDownloaded() {
try await redact.download { fraction in
print("\(Int(fraction * 100))%")
}
}Bundle the model in an Apple app:
import Redact
import RedactCoreMLResources
let redact = Redact(bundle: RedactCoreMLResourcesBundle.bundle)Requirements: Android API 24+. The AAR contains prebuilt arm64-v8a and x86_64 native libraries.
Redact is published to Maven Central.
// settings.gradle.kts
dependencyResolutionManagement {
repositories {
google()
mavenCentral()
}
}
// build.gradle.kts
dependencies {
implementation("ai.desertant:redact:0.7.0")
}ai.desertant:redact bundles the LiteRT model by default, so normal installs work offline. To disable bundling, exclude the transitive resources artifact:
dependencies {
implementation("ai.desertant:redact:0.7.0") {
exclude(group = "ai.desertant", module = "redact-tflite-resources")
}
}With that exclusion, Redact(context) downloads on demand and caches the model. Redact(context, directory = modelDir) loads from or downloads into your chosen directory.
import ai.desertant.redact.Options
import ai.desertant.redact.Redact
val redact = Redact(context) // bundled model by default
val result = redact.redaction("Email Anna at anna@example.com.")
println(result.redactedText)
// Email [GIVEN_NAME_1] at [EMAIL_1].
for (item in result.items) {
println("${item.label} ${item.original} ${item.confidence} ${item.start}..${item.end}")
}
val reply = myLlm.rewrite(result.redactedText)
val restored = result.restore(reply)
redact.close()Use use to close the native handle automatically:
Redact(context).use { redact ->
val result = redact.redaction(text)
}Filter by category:
val result = redact.redaction(
text,
Options(labels = setOf("EMAIL", "PHONE", "CREDIT_CARD", "BANK_ACCOUNT"))
)Download before first use:
val redact = Redact(context)
if (!redact.isDownloaded()) {
redact.download()
}Use an explicit model directory or bundled resources:
val cached = Redact(context) // bundled model by default
val explicit = Redact(context, directory = modelDir) // explicit model directory
val offline = Redact.bundled() // explicit bundled constructorTwo entries share one Redact API. The default @desert-ant-labs/redact is the browser build (WebAssembly + LiteRT.js, XNNPACK-accelerated CPU by default, optional WebGPU); it has no native dependencies, so it bundles cleanly for every target of a multi-target bundler (Next.js, Remix, SvelteKit, Nuxt), including the browser bundle and the Client-Component SSR pass those frameworks render in Node. @desert-ant-labs/redact/native is a prebuilt native core for server-side inference in Node.
# Browser (default entry):
npm install @desert-ant-labs/redact @litertjs/core
# Server-side inference in Node (/native entry) needs no extra install:
npm install @desert-ant-labs/redact@litertjs/core is an optional peer dependency (browser build only). The default import is safe to import during server-side rendering, but LiteRT.js initializes only in a browser or Web Worker, so Redact.load() runs inference in the browser; in plain Node it throws an actionable error pointing you to @desert-ant-labs/redact/native. The native build ships for linux-x64, linux-arm64 (LiteRT), and darwin-arm64 (Core ML).
import { Redact } from "@desert-ant-labs/redact"; // browser; use "@desert-ant-labs/redact/native" server-side
const redact = await Redact.load();
const result = await redact.redaction("Email Anna at anna@example.com.");
console.log(result.redactedText);
// Email [GIVEN_NAME_1] at [EMAIL_1].
for (const item of result.items) {
console.log(item.label, item.original, item.confidence, item.start, item.end);
}
const reply = await llm(result.redactedText);
const restored = result.restore(reply);Filter by category:
const result = await redact.redaction(text, {
labels: ["EMAIL", "PHONE", "CREDIT_CARD", "BANK_ACCOUNT"],
});Unlike the Swift and Android packages, the JavaScript package does not bundle the
model: Redact.load() downloads it from the Hugging Face Hub at the SDK's pinned
tag on first use and caches it (the OS cache dir for the native build, the fetch
cache in the browser). To self-host or run offline, pass directory (native
build) or modelBaseUrl (browser):
const redact = await Redact.load({
directory: "/var/cache/redact", // native build: adopt/download files here
modelBaseUrl: "/assets/redact/", // browser: serve the files yourself
onProgress: (fraction) => console.log(fraction),
});Bring your own LiteRT.js module, useful for browser bundlers and React Native:
import * as litert from "@litertjs/core";
import { Redact } from "@desert-ant-labs/redact";
const redact = await Redact.load({ litert, litertWasmDir: "/path/to/@litertjs/core/wasm/" });All platforms return the same redaction shape: masked text, ordered items, and a restore helper.
Input: Email anna@example.com and bob@example.com about IBAN DE89370400440532013000.
Masked: Email [EMAIL_1] and [EMAIL_2] about IBAN [BANK_ACCOUNT_1].
Placeholders are numbered per category, so two emails never collapse into one and restoration is order-independent. Tell your LLM to preserve [LABEL_N] tokens verbatim.
GIVEN_NAME, SURNAME, STREET_NAME, BUILDING_NUMBER, SECONDARY_ADDRESS, CITY, STATE, ZIP_CODE, EMAIL, PHONE, CREDIT_CARD, BANK_ACCOUNT, ROUTING_NUMBER, IP_ADDRESS, URL, GOVERNMENT_ID, PASSPORT, DRIVERS_LICENSE, TAX_ID, SSN, and IMEI.
IMEI is deterministic-only. Structured recognizers report confidence 1.0; neural detections use minimumConfidence, default 0.6.
The model artifacts are published at desert-ant-labs/redact on Hugging Face. Each SDK pins the model revision to its own package version.
Default behavior:
- Swift: downloads the Core ML model on demand to a managed cache, or uses bundled
RedactCoreMLResources. - Android: bundles the LiteRT model by default through the normal
ai.desertant:redactdependency. Excludingredact-tflite-resourcesswitches to on-demand download into app cache. - JavaScript: downloads the LiteRT model on
Redact.load()to the managed cache in Node or browser cache storage when available.
Passing an explicit directory makes that directory the model home. Existing valid files are adopted for offline use; otherwise Redact downloads into that directory and reuses it later.
Desert Ant Labs Source-Available License. Free for most apps; a commercial license is required at scale. Full terms are at the link. Licensing: licensing@desertant.com.