---
title: Sensitive encoding
description: The $sensitive marker format for flagging sensitive values in span
  payloads — enabling the encoding, marker shape, escaping literal keys, and
  read-back.
editUrl: true
head: []
template: doc
sidebar:
  hidden: false
  attrs: {}
pagefind: true
draft: false
---

Sensitive encoding is the payload format your integration uses to flag sensitive values in a [span](/platform/concepts/span)'s input and result. When the encoding is enabled for a payload, Prefactor parses it for `$sensitive` markers and handles each marked value under the storage, redaction, and discard rules described in [Sensitive data](/platform/sensitive-data).

## Enabling the encoding

The encoding is off by default and enabled per payload. Set `sensitive_encoding: true` when you create the span to have the input payload parsed, and again when you finish the span to have the result payload parsed. The two are independent.

With the flag off, nothing is parsed: the payload is stored as-is, and a literal `$sensitive` key in your data is just a key. With the flag on, that key needs escaping — see Escaping literal `$sensitive` keys below.

## Marker shape

A marker is a JSON object that wraps a single value. It records the value's type, the categories of sensitive data the value contains, and the value itself:

```json
{
  "email": {
    "$sensitive": "string",
    "labels": ["personal_identifiers", "contact_information"],
    "value": "ada@example.com"
  }
}
```

| Field | Type | Description |
| --- | --- | --- |
| `$sensitive` | `"string"`, `"number"`, or `"boolean"` | The wrapped value's type. |
| `labels` | array of strings | The data categories the value contains. |
| `value` | string, number, or boolean | The value itself. |

The `labels` list uses the same data-category vocabulary as [risk profiles](/platform/concepts/risk-profile) — `personal_identifiers`, `contact_information`, `financial_information`, `health_and_medical`, `authentication_and_secrets`, and the rest, including the GDPR special categories.

## Escaping literal `$sensitive` keys

With the encoding on, Prefactor parses every object that contains a `$sensitive` key, so your data cannot use that key directly. To keep a literal `$sensitive` key, wrap the object that contains it in an escape marker:

```json
{
  "mapping": {
    "$sensitive": "escape",
    "value": {
      "$sensitive": "a field name in your own data",
      "other": "data"
    }
  }
}
```

The wrapper has exactly two fields — `$sensitive` set to `"escape"`, and `value` holding the object — and anything else is rejected. The escape shields only the outer object: markers nested inside `value` are parsed as usual. On read-back, any object containing a `$sensitive` key is returned in the escape-wrapped form, including data written with the encoding off, so a literal key always survives the round trip.

Few payloads contain a `$sensitive` field of their own, so few integrations need the escape marker. If you are not sure whether yours does, it almost certainly does not — this section exists for completeness.

## Read-back

Marked values are stored separately from the span record, but the API always accepts and returns the combined payload: your integration sends markers in and reads the same payload back out.

Read-back is also where you choose who the payload is safe for. Span list and detail queries accept a `redacted` parameter that defaults to `false` — the API returns the real values unless you ask otherwise, the opposite of the web app, which redacts by default. Pass `redacted: true` when the data is headed somewhere less trusted, such as an export or an evaluation pipeline. Each marker then comes back without its value:

```json
{
  "email": {
    "$sensitive": "string",
    "labels": ["personal_identifiers", "contact_information"]
  }
}
```

The type and labels survive, so the redacted form still records what kind of data was there; only the value is gone. Summaries on the same queries render with the redaction labels in place of the values, matching what the web app shows.

A discarded value never comes back: its marker has no value on any read, however `redacted` is set.

## SDK support

In the TypeScript SDK, pass `sensitiveEncoding: true` in the span options and build the marker objects in your payload; the SDK sends them through unchanged. The Python SDK does not support sensitive encoding yet — call the [HTTP API](/api/http) directly to mark values from Python.

## Related

- [Sensitive data](/platform/sensitive-data) — the model behind the markers: separate storage, redaction by default, reveal on demand, and discard.
- [Risk profile](/platform/concepts/risk-profile) — where the data-category vocabulary in `labels` comes from.
- [Summary templates](/api/summary-templates) — how redacted values render in span summaries.
- [OpenAPI spec](/api/platform) — the span create, finish, and query operations.