Compare approaches

Four ways teams keep personal data out of an LLM prompt. This page compares the approaches, not vendors - every zer0pii claim below cites the code or doc it comes from; the other columns state only general properties of that approach.

Compare approaches

Does the provider ever see raw PII?

zer0pii (masking gateway)
No - detected entities are replaced with placeholder tokens before the request leaves the gateway, and restored in the response.Source: apps/gateway/core/pipeline.py, apps/gateway/core/token_vault.py
Provider-side data controls
The provider does see the raw text; the control is a contractual or configuration promise (zero-retention terms, an enterprise data-processing agreement) about what happens to it afterward, not a technical barrier before the call.
Generic DLP
Usually inspects traffic to detect or block a pattern; it does not rewrite the payload, so if the request is allowed through, the provider sees the raw content.
DIY regex
Only whatever the regex actually matches is removed before sending; anything the pattern misses reaches the provider raw.

Does the model still get useful context?

zer0pii (masking gateway)
Yes - placeholders preserve sentence structure and entity type, and are restored in the reply, so the model reasons over the same shape of text.Source: apps/gateway/core/reconstitutor.py
Provider-side data controls
Yes, always - since the model receives the unmodified text.
Generic DLP
Not applicable in the same sense - a block/alert tool does not rewrite the payload, so context is either fully present (allowed) or the request never proceeds (blocked).
DIY regex
Depends on the replacement chosen; a blunt find-and-delete regex can strip words the model needed, or leave gaps that read oddly.

Names, organizations, places (context-dependent entities)

zer0pii (masking gateway)
Semantic tier (NER) catches these when it fires; measured recall varies by entity and language, and is not perfect.Source: docs/DETECTION-EVAL.md (NER tier2: PERSON 76.2%, LOCATION 86.8%, ORGANIZATION 51.4% on the 1,500-row sample)
Provider-side data controls
Not addressed by this approach at all - it does not detect or redact anything, since it only governs what the provider does with whatever it receives.
Generic DLP
Weak on this class by design: DLP pattern libraries are built around structured identifiers (card numbers, ID formats), not free-text names or organizations, which do not have a fixed shape to match.
DIY regex
Effectively unable to catch these reliably - a name or place has no fixed pattern, so a regex either misses most of them or over-matches common words.

Checksum-valid IDs (cards, national IDs, IBANs)

zer0pii (masking gateway)
Deterministic tier validates structured identifiers against their checksum (Luhn, mod-97, etc.) before treating a match as real.Source: apps/gateway/core/deterministic.py; docs/DETECTION-EVAL.md (e.g. IBAN 99.92% recall against gold)
Provider-side data controls
Not addressed - this is a detection capability the provider-side control does not have.
Generic DLP
Often supported - checksum validation for common identifier formats is a standard DLP pattern-library feature.
DIY regex
Possible to hand-write, but each checksum algorithm is its own bug surface, and coverage is only as complete as the identifiers someone thought to add.

Streaming responses restored correctly?

zer0pii (masking gateway)
Yes - a dedicated reconstitutor handles token boundaries that split a placeholder across arbitrary SSE chunks, without buffering the full response.Source: apps/gateway/core/reconstitutor.py (StreamReconstitutor)
Provider-side data controls
Not applicable - nothing is masked, so there is nothing to restore in a stream.
Generic DLP
Not applicable to LLM response streams in the way it applies to network traffic; most DLP tooling targets file transfer and email, not token-by-token model output.
DIY regex
Hard to get right - a hand-rolled scan-and-replace over a stream has to handle a match split across two chunks, which is easy to miss and easy to get subtly wrong.

Code blocks left intact?

zer0pii (masking gateway)
Yes by design - markdown code blocks, variable names, package names and AST syntax are excluded from masking unless a hardcoded credential is confirmed.Source: CLAUDE.md (Core Principle 4, CODE RESILIENCE); apps/gateway/core/ast_filter.py
Provider-side data controls
Not applicable - nothing is rewritten, so code is never at risk of corruption from a redaction pass.
Generic DLP
Depends on the tool; a pattern scanner not written for source code can flag or mangle look-alike strings (a hex constant, a fake-looking test fixture) inside code.
DIY regex
A real risk - a general-purpose regex tuned for prose will often match inside code (a UUID literal, a phone-shaped test constant) and break it.

Proof of what happened (signed receipts)?

zer0pii (masking gateway)
Yes - each request is attested with an Ed25519 signature over a hash of the raw and sanitized payloads, verifiable independently of zer0pii.Source: apps/gateway/core/attestation.py (Attestor.sign, verify)
Provider-side data controls
Only whatever the provider's own logs or compliance reports state; no independently verifiable, per-request cryptographic proof is a standard feature of this approach.
Generic DLP
Usually an internal log entry in the DLP vendor's own console, not a portable, independently verifiable artifact.
DIY regex
None unless someone builds it - a homegrown script has no attestation layer unless it is added deliberately.

Latency cost

zer0pii (masking gateway)
Deterministic-only path: p50 under 10ms, p99 under 20ms. Semantic (NER) path: p50 under 300ms for a full pasted page, and it fails open to the deterministic path if it would exceed that budget.Source: CLAUDE.md (LATENCY BUDGET, PER PATH)
Provider-side data controls
None beyond the provider's own response time - there is no separate scanning step in front of the call.
Generic DLP
Varies by deployment (inline network inspection adds some latency; out-of-band monitoring adds none to the request itself), but is not a number this page can state without a specific product in mind.
DIY regex
Depends entirely on the implementation; a naive large regex set run per request can be slow, but there is no fixed number, since it is whatever code someone writes.

Setup effort

zer0pii (masking gateway)
Point the SDK base URL at the gateway host and add the API key - the request/response shape is unchanged otherwise.Source: apps/web (integrations/docs pages: base URL + header swap pattern)
Provider-side data controls
Usually a contract or account-tier change (enterprise terms, a data-processing addendum) rather than a code change.
Generic DLP
Typically an infrastructure deployment: an agent, a proxy, or a network tap, plus policy authoring - more operational surface than a client-side change.
DIY regex
Fast to start, since it is just a script - but every entity type, edge case and checksum has to be written and maintained by hand.

What it does NOT cover

zer0pii (masking gateway)
PASSWORD recall is 47.96% (fundamentally low-context strings) and PHONENUMBER recall is 84.41% on the gold eval; the semantic tier degrades to deterministic-only when it would exceed its latency budget; and Cursor and Claude Code's subscription-seat mode are not coverable (no base-URL override / no key to proxy for a subscription seat).Source: docs/DETECTION-EVAL.md (lines 64-65); CLAUDE.md (LATENCY BUDGET fail-open); docs: Developer tools (dev-tools.md)
Provider-side data controls
Does not detect or redact anything at all - it is a policy about the provider's handling of whatever it receives, not a technical control on the data itself.
Generic DLP
Free-text, context-dependent entities (names, organizations, addresses) with no fixed shape to match; also generally not designed for token-level LLM streaming output.
DIY regex
Anything the author did not anticipate - new formats, new locales, streaming, checksum validation, and code-safety are all separate problems a regex-only approach does not solve on its own.

Source: docs/DETECTION-EVAL.md, apps/gateway/core/pipeline.py, apps/gateway/core/reconstitutor.py, apps/gateway/core/deterministic.py, apps/gateway/core/attestation.py, apps/gateway/core/ast_filter.py, CLAUDE.md

When not to choose zer0pii

When not to choose zer0pii

If your only requirement is a contractual zero-retention promise from the model provider and you do not need entity-level detection, provider-side data controls alone may be simpler. If you need to inspect non-LLM traffic (email, file transfers, general network egress), that is DLP's actual scope, not this gateway's. And if your volume is tiny and your formats are fixed and known in advance, a small DIY regex may genuinely be enough - until the format changes.