Skip to content
Self-hosted · Apache-2.0

Redact before
you prompt.

Redax is a small, deterministic PII engine that strips emails, phones, names, and identifiers from any text — before it reaches an LLM. Built for teams that refuse to send customer data to someone else's GPU.

  • Apache-2.0
  • No telemetry
  • Runs on a laptop
  • CPU-friendly
POST · /v1/redact
Request application/json

  "text": "Hi, I'm Jordan Reyes from Stripe. "
        "Reach me at jordan@stripe.com or "
        "+1 (415) 555-2671. Card on file: "
        "4111 1111 1111 1111."
Response 200 OK · 8 ms

  "text": "Hi, I'm [PERSON_0000] from [ORG_0000]. "
        "Reach me at [EMAIL_0000] or "
        "[PHONE_E164_0000]. Card on file: "
        "[CREDIT_CARD_0000].",
  "spans": [ /* 4 spans */ ],
  "digest": "8f1d2c…"
Pipeline regex gliner2 consensus replace audit 8 ms · 4 spans

Runs on any hardware · CPU-friendly · no telemetry

fastapipydantictransformersgliner2openmed-piiprometheusopentelemetryredisarqstructloghuggingfacetransformers.js
fastapipydantictransformersgliner2openmed-piiprometheusopentelemetryredisarqstructloghuggingfacetransformers.js
Product

Privacy as an architecture, not a feature flag.

Most "PII tools" are regex libraries bolted onto an LLM SDK. Redax is a small, deterministic service built for the boring, hard part: making sure the same input always produces the same output, with no leakage and a paper trail.

  • 01

    Deterministic by design

    Same input, same output, every time. Two replicas behind a load balancer return byte-for-byte identical results — no drift, no surprises.

  • 02

    Privacy is the architecture

    No cloud calls. No model phones home. Your text and your telemetry never leave the box you deploy Redax on.

  • 03

    Drop-in, not rip-and-replace

    A single POST endpoint, an OpenAI-compatible shape, and a Python SDK. Wrap any LLM call in five lines.

  • 04

    Built for production

    Idempotency, rate limiting, response cache, Prometheus metrics, OpenTelemetry traces, and an append-only audit log.

Try it live

Type a sentence. Watch the PII disappear.

This runs the same deterministic regex pipeline that ships in Redax — entirely in your browser. No request is ever made to a server.

demo · redact.live
Input 0 chars
Redacted 0 spans · 0 ms
Detectors
regex · deterministic
Replacement
[TYPE_NNNN]
Network
none · local-only
Determinism
byte-identical on retries
Pipeline

One request. Six stages.
No PII survives.

The engine is a small DAG: deterministic regex first, then optional encoders, then consensus fusion. Every stage writes to the audit log; nothing writes the values.

  1. 01

    Regex safety net

    Deterministic patterns catch emails, E.164 phones, IBANs, SSNs, IPs, and Luhn-checked credit cards in microseconds.

    stage_01
  2. 02

    GLiNER2 zero-shot NER

    A 205M encoder identifies people, organisations, and contextual entities the regex misses. Runs on CPU.

    stage_02
  3. 03

    OpenMed-PII (optional)

    A 434M clinical-grade encoder with 54 entity types for healthcare and multilingual workloads. Swap in with one env var.

    stage_03
  4. 04

    Consensus fusion

    Spans are merged across detectors, deduped by overlap, and typed with the highest-confidence label.

    stage_04
  5. 05

    Replacement + relex

    Deterministic typed placeholders ([EMAIL_0001]) plus optional hiding-in-plain-sight relexicalization.

    stage_05
  6. 06

    Audit log

    What was redacted and where — never the value itself. fsync'd, rotated, and signed by default.

    stage_06
Request lifecycle app/redaction/pipeline.py
POST /v1/redact
request
field → strategy
policy
regex + GLiNER2
detect
typed placeholder
redact
audit_log.append(digest, span_count, latency) never writes values fsync after every line
Features

Everything you'd ship to production. Nothing you wouldn't.

Twelve carefully chosen capabilities. Each exists because a real operator asked for it — not because a competitor had it on a slide.

  • Seven structured PII types

    Email, phone (E.164), IBAN, SSN, IPv4, credit card with Luhn check, URL — covered with deterministic regex out of the box.

  • Zero-shot NER on CPU

    Default detector is a 0.3B GLiNER2 model that catches PERSON, ORG, and contextual entities without retraining.

  • One env var to swap detectors

    Switch to OpenMed-PII for healthcare workloads with `REDAX_DETECTOR=openmed`. No code change.

  • Reversible typed placeholders

    `[EMAIL_0001]` instead of `[REDACTED]`. The same entity always maps to the same placeholder across requests.

  • Hiding-in-Plain-Sight relex

    Optionally replace names with plausible lookalikes so the output still reads like English.

  • Versioned YAML policies

    Field-by-field redaction rules checked into git. Reviewed in PRs, not runtime configs.

  • Append-only audit log

    Records what was redacted and where — never the values. Configurable rotation, retention, and fsync.

  • Prometheus + OpenTelemetry

    `/metrics` for scraping, OTLP gRPC for traces. SRE-friendly without bolting on a sidecar.

  • Rate limit + idempotency

    Per-API-key token bucket in Redis. `Idempotency-Key` short-circuits retries safely.

  • WASM bundle

    Same model, INT8-quantised, runs in the browser via Transformers.js. No server round-trip needed.

  • RFC 7807 errors

    Every error path returns a problem-details JSON body. Easier debugging, predictable SDKs.

  • Quantified against a benchmark

    RedactionBench R-Score measured against `ai4privacy/pii-masking-200k`. Numbers you can defend in review.

Quickstart

One endpoint.
Five lines.

Wrap any LLM call in front of /v1/redact. PII comes out before the model sees it. Same text in, same text out — every time.

Endpoint
POST /v1/redact
Auth
X-API-Key header (or auth disabled in dev)
Idempotency
Idempotency-Key header short-circuits retries
Response
text + spans + digest (sha256 of output)
Errors
RFC 7807 problem-details JSON
localhost:8000
curl -s -X POST http://localhost:8000/v1/redact \ -H 'Content-Type: application/json' \ -d '{"text": "Email me at alice@example.com or +1-415-555-2671."}'
import asyncio from app.redaction.redactor import Redactor from app.redaction.strategy import Mask from app.inference.regex import RegexDetector redactor = Redactor( detector=RegexDetector(), strategies={"mask": Mask()}, replacement="[REDACTED]", ) result = asyncio.run(redactor.redact( "Email me at alice@example.com or +1-415-555-2671." )) print(result.text)
{ "text": "Email me at [EMAIL_0000] or [PHONE_E164_0000].", "spans": [ {"start": 12, "end": 29, "type": "EMAIL", "confidence": 1.0}, {"start": 33, "end": 47, "type": "PHONE_E164", "confidence": 1.0} ], "digest": "8f1d2c..." }
Latency (regex)
< 1 ms
Latency (gliner2)
~ 123 ms · CPU
Audit log
append-only · fsync
Benchmarks

Numbers we publish.
Numbers you can defend.

Redax is scored against the RedactionBench harness on a 5,060-document stratified sample of `ai4privacy/pii-masking-200k`. The metric rewards both recall and format precision, with a strict penalty for redaction gaps.

pii200k · mean R-Score

Across 5,060 documents

higher is better
regex 0.142
Safety net · n/a p50 < 1 ms
openmed 0.385
Clinical-grade · 434M p50 168 ms
gliner2 winner 0.552
Default · 205M p50 123 ms
Recall@0.5 IOU
strict, deterministic
Format precision
placeholder-shaped
Corpus
ai4privacy/pii-masking-200k
Headline
0.552
pii200k · gliner2

GLiNER2 outperforms OpenMed-PII on both corpora while running 2.1× smaller and 1.4× faster on CPU.

Per-category (pii200k)
  • academic
    0.562
  • code
    0.440
  • emails
    0.649
  • medical
    0.581
  • financial
    0.602
  • logs
    0.473
Read the methodology
docs/bench.md · docs/benchmark-results.md
Deployment

Pick the runway that fits the team.

One Docker image. One Python package. One WASM bundle. Every path lands on the same API contract.

  • Fastest

    Docker Compose

    Clones the repo, brings up Redax + Redis, and ships a working stack with one command.

    git clone https://github.com/sachncs/redax.git
    cd redax
    docker compose up
  • No clone

    Pre-built image

    Pull from GHCR and run on any host with a Docker daemon. Useful for CI and air-gapped nodes.

    docker run --rm -p 8000:8000 \
      ghcr.io/sachncs/redax:latest
  • Dev-friendly

    From source

    Install pinned deps from the lockfile and run Redax in a virtualenv. Best for hacking on the engine.

    python3 -m venv .venv
    source .venv/bin/activate
    pip install -r requirements.lock
    pip install -e '.[dev]'
    make dev
  • Browser

    WASM bundle

    Same GLiNER2 model, INT8-quantised. Runs locally via Transformers.js with no server round-trip.

    import { redact } from '@sachncs/redax/wasm'
    await redact(text)
Open source · Apache-2.0

Ship privacy the way you'd ship anything else.

Star the repo, run docker compose up, and you're two curl commands away from a production-grade redaction layer.