Data Masking

Keep sensitive values out of model-provider requests while preserving the real values for your app and users.

Data Masking helps teams use cloud LLMs without sending raw sensitive values to the model provider. When masking is enabled, PromptRails replaces detected PII and secrets with opaque placeholders before an outbound LLM call. On the response path, placeholders are restored so your agent, tools, and application continue to work with the real values.

The Data Masking settings page controls the workspace default and shows recent masking activity, including LLM calls, hit ratio, masked values, and restored values.

Data Masking is available on the Pro and Enterprise plans. Free and Starter workspaces will see an upgrade prompt on the masking settings page.

Technical detailsDetector and masking mechanics

What Gets Masked

Built-in detectors run on outbound LLM calls when masking is enabled:

CategoryTypes
IdentityEmail, phone, credit card (Luhn-validated), IBAN (mod-97), US SSN, TC Kimlik No (TR national ID)
NetworkIPv4, IPv6
SecretsJWT tokens, AWS access keys, generic API keys (OpenAI / Anthropic / Stripe / GitHub / Slack / Google), PEM private key blocks

Detectors pair patterns with validators where possible, so values like credit cards, IBANs, SSNs, and TC Kimlik numbers must pass format checks before they are masked.

Two additional types — Name and Address — have no regex (their shapes are too ambiguous) and are masked only when you mark them explicitly on a datasource column.

How It Works

Prompt / tool result (real PII)
    │
    ▼
Detect + replace with [PII_TYPE_xxxxxxxx] placeholders
    │
    ▼
Cloud LLM provider (sees only the placeholders)
    │
    ▼
Response with placeholders preserved
    │
    ▼
Restore originals before the agent / tool / chat client reads them

The placeholder format is stable within the call path, so the LLM can still reason about references such as "the email I mentioned earlier" while the provider only sees placeholders.

Workspace Policy

Open Settings > Data Masking in your workspace. The main controls are:

  • Enabled — off by default. When on, every outbound LLM call from this workspace runs through the masking engine.
  • Failure mode — what to do if the masking engine cannot complete:
    • Strict (recommended) — abort the request rather than risk leaking PII. Best for compliance-sensitive workspaces.
    • Permissive — log a warning and let the request through. Useful in dev workspaces where stability beats strict guarantees.

You can also restrict masking to a subset of detector types — for example, "only mask EMAIL and PHONE" — when you want a targeted policy.

Per-Agent and Per-Datasource Overrides

The workspace policy is the default. Individual agents and data sources can override it.

In the Studio detail page for an agent or data source, open the PII Masking tab (it's hidden behind the + menu — you opt in to see it). The tab offers a three-way control:

  • Inherit workspace policy — follow whatever the workspace setting is. Recommended unless this specific resource has a different requirement.
  • Force on — always mask this resource's outbound calls, even if the workspace policy is off.
  • Force off — skip masking on this resource even if the workspace policy is on. Use sparingly — typically for a non-PII dev datasource where masking adds noise.

A small chip on the tab label tells you at a glance whether an explicit override is set.

Agent-level masking overrides live in Studio. Use them when a specific agent needs stricter or looser masking than the workspace default.
Datasource overrides can force masking on for returned values and add field policies for columns such as founders, names, addresses, or other values that generic detectors cannot infer reliably.

Marking Datasource Columns

Detectors catch values whose shape is recognizable (an email always looks like an email). They don't catch names, internal customer IDs, or domain-specific identifiers — but those are usually the values you most want to mask in queries.

Open a credential's detail page in Settings > Credentials. The schema view has a PII dropdown per column:

Mark a column asBehaviour
Email, Phone, Credit card, IBAN, SSN, TC Kimlik, IP, JWT, AWS / API / Private keyValidator type is matched — useful when a column holds the value but the detector would also catch it from raw text.
Name, AddressHigh-confidence masking for values no regex would catch.
noneDefault. The column flows through unmasked unless a detector matches its content.

After saving, every value returned in that column from a datasource tool call gets masked before the prompt that wraps it reaches the LLM. The trace count badge tells you how many fields were intercepted.

Trace Visibility

Every LLM span in the trace UI shows a small amber N PII masked chip in its header when the call had PII intercepted. The number tells you the count; the trace store never holds the original values themselves — only the count, model name, and the usual timing / token usage. This means an auditor can verify that masking ran without giving them a path to the raw PII that was masked.

The chip appears on the trace list view too, so you can scan a session for which calls had PII flow through them.

Technical detailsAPI masking hints

Upstream Hints (API Clients)

When you call the OpenAI-compatible gateway directly (without going through an agent), you can attach structured PII markers with the X-Masking-Hints header. The value is a base64-encoded JSON array:

HINTS=$(printf '%s' '[{"value":"John Doe","type":"NAME"},{"value":"alice@x.com","type":"EMAIL"}]' | base64)
 
curl https://api.promptrails.ai/v1/chat/completions \
  -H "Authorization: Bearer $PROMPTRAILS_API_KEY" \
  -H "X-Workspace-ID: $WORKSPACE_ID" \
  -H "X-Masking-Hints: $HINTS" \
  -d '{
    "model": "pr/gpt-4o",
    "messages": [{"role":"user","content":"draft an email to John Doe at alice@x.com"}]
  }'

Hints take precedence over the built-in detectors on overlap — and they're the only way to mask NAME and ADDRESS values for ad-hoc text outside a datasource.

What Happens On Downgrade

If a workspace was on the Pro plan with masking enabled and then downgrades to Starter, the gateway notices on the next request and stops masking — your settings document is preserved, so re-upgrading restores the prior behaviour. If you actively try to enable masking from a plan without the feature, the API returns 402 Payment Required and the dashboard surfaces an upgrade card with a link to billing.

What Doesn't Change

  • The agent runtime sees real values. Tools called with a masked email get the real email when they execute.
  • Coreference within a single conversation works — the LLM is given the same placeholder for repeat mentions, so it can still reason about "the customer", "their email", etc.
  • Streaming continues to work — placeholders that span chunk boundaries are reassembled before they reach your client.

Audit Notes

  • Masking state is per-workspace; no data crosses between workspaces.
  • The placeholder mapping store is encrypted at rest. Plaintext PII is never written to the masking store.
  • Workspace mappings expire one hour after last activity by default.
  • The trace store only ever sees masked content and the count attribute. There is no path from the trace UI to the original values.
  • Guardrails — content-safety scanners that run around the LLM call. Composes with masking; both are independently configurable.
  • Security — workspace isolation, encryption, and authentication that masking builds on.
  • Billing & Plans — feature-flag matrix per plan tier.