Skip to main content
A workspace’s schema can hold the kind of data that needs careful handling — emails, phone numbers, payment metadata, contractual details. The platform supports this with a single piece of declarative metadata on each field: a sensitivity tag. Tags propagate through the runtime, the rendering pipeline, and the audit trail; they decide what shows up in a log line, what reaches a third-party capability, and what a page block is allowed to render. By the end of this page you will know what the tags are, where they apply, and how to choose the right one when you declare a field.

A field with a sensitivity tag

You add a sensitivity value to a field declaration on the workspace schema. Everything else — redaction in logs, masking in rendered pages, allow-listing on outbound capability calls — falls out of the tag.
schema.json
{
  "customers": {
    "fields": {
      "id":       { "type": "uuid",   "primary": true },
      "name":     { "type": "string", "sensitivity": "personal" },
      "email":    { "type": "string", "sensitivity": "contact" },
      "ssn_last4":{ "type": "string", "sensitivity": "restricted" },
      "notes":    { "type": "string" }
    }
  }
}
name is treated as personal data; email is contact-class; ssn_last4 is restricted. notes has no tag and is treated as public-by-default — the platform does not infer sensitivity from field names because the same name means different things in different schemas.

The tag set

Five tags exist. They are ordered by handling strictness; the strictest tag a value carries is the one that wins when a value is composed from several fields. The tags are a contract, not just a hint. The runtime enforces the handling described in the right column; you cannot opt a restricted field into a log line by setting a flag elsewhere.

Where the tag is enforced

Sensitivity is checked at four boundaries. Each one inspects the tag and applies the right action without the page author or the developer having to remember.

How redaction looks

The redactor preserves enough shape for an operator to recognize the field type while removing the value. Examples (for contact):
email     →  a*****@example.com
phone     →  +1 (***) ***-1234
postal    →  *** *** Street, Springfield, **
For restricted, the redaction is total — the value is replaced with <redacted:restricted> and no shape is preserved. The redactor does not produce a deterministic token; the same value redacted twice produces the same masked output only when the field type is what determines the mask, not the underlying value.

End-user sessions and tag scope

A signed-in end user can see their own contact and financial fields. The runtime resolves the calling end-user’s identity from the session and matches it against ownership claims on the record. A row owned by user A renders A’s email; the same row read in B’s session renders the masked form. The tag set is not affected by who is reading — restricted is restricted for everyone. What changes per session is whether the masking applies. A workspace owner reading a customer’s record sees the redacted form on a default block; the end user reading their own record sees the unmasked value because the block resolves the ownership claim.

Tag composition

When a value is composed from several fields — a Table block rendering a row, an email template interpolating columns — the strictest tag in the composition wins. A row that contains one restricted field is treated as restricted as a whole for the purpose of decisions made about that composition. Individual fields keep their own tags for purposes of how they render and where they ship. This rule prevents accidentally exposing a sensitive value by burying it inside an otherwise-public surface. If you want to render a row publicly, the row must not contain a sensitive field, full stop.

Declaring a block’s sensitivity policy

Blocks declare what tags they handle. The declaration is opt-in: a block that does not opt into contact will not render any contact-tagged field. The runtime does not silently auto-render across the boundary. The defaults are conservative: a fresh block renders only public and personal. You opt into stricter tags explicitly.

Reading sensitivity on a record from the API

When you read a record through the API, the response carries the redacted form by default. Pass ?reveal=contact,financial on the query (with a token that holds the right scope) to receive the underlying values. The reveal is logged to the audit chain by field — the platform tracks not just that the row was read, but which sensitive fields were unmasked.

When to tag (and when not to)

Tag a field as the strictest level its content might ever hold. Tag escalation is hard — you have to re-decorate every block that touches the field. Tag relaxation is cheap — you change the schema and the platform stops applying the stricter handling. Errors on the strict side are recoverable; errors on the lax side aren’t. Don’t tag fields that are derived from other fields. A computed value inherits the strictest tag of its inputs at evaluation time; tagging the derivation separately is redundant and creates two places to keep in sync.