PII Redaction
Automatically redact personally identifiable information from traces before storage.
Neatlogs has two independent controls:
| Control | Where it runs | What it protects | Failure behavior |
|---|---|---|---|
SDK mask callback | In your process, after Neatlogs canonicalizes telemetry and before batching/export | Telemetry sent by that SDK client: span attributes and typed I/O, events/exceptions, logs, and sanctioned resource fields | Fail closed. A callback exception, timeout, cancellation, or invalid result drops the affected telemetry item instead of exporting the unmasked original. |
| Server-side PII redaction | In Neatlogs ingestion before user-visible span storage | Configured fields and span kinds for the project | If redaction cannot finish, normal asynchronous trace ingestion must fail closed and retry the event. It does not forward the original content to user-visible span storage. |
These controls are not aliases. Server PII options do not run local hashing/redaction, and a local mask does not change the project's server-side policy.
This server behavior applies to normal asynchronous trace ingestion. Other
product endpoints and helpers have their own documented contracts. Do not infer
their failure behavior from this trace-ingestion guarantee. If data must not
leave your infrastructure, use the SDK mask callback as the first control.
SDK Doctor local mode is network-free, so it cannot exercise server-side redaction. Probe mode uses the normal authenticated trace pipeline and verifies its exact persisted result without reproducing or exposing private classification rules.
Client-side masking
def redact(item, *, context=None):
attrs = item.get("attributes", {})
for key in list(attrs):
if "email" in key.lower() or "phone" in key.lower():
attrs[key] = "***"
return item
neatlogs.init(mask=redact)Python accepts synchronous and awaitable callbacks. TypeScript accepts values or promises. Go supplies a cancellable context.Context. Masking runs on a bounded export worker rather than the application span-end path.
Python preserves the legacy mutate-in-place convention: returning None exports the mutated clone. TypeScript and Go use a null/nil result to intentionally drop the item. In every language, callback failure or timeout drops data rather than sending the original secret.
Per-span masking
Python and TypeScript also accept mask on span()/trace(). A per-span callback applies only to that span and takes precedence over the client's global callback; it does not automatically apply to sibling or child spans.
@neatlogs.span(kind="TOOL", mask=redact)
def lookup_customer(email: str):
...Server-side PII redaction
Configure the project policy in Settings → PII Redaction: enabled state, detected entity types, replacement operator, and included span kinds. It can cover core I/O, LLM messages and completions, prompt-template telemetry, tool arguments/results, retrieval and reranker documents, and MCP request/response values.
Python can persist project-level overrides during init():
neatlogs.init(
pii_enabled=True,
pii_entities=["PERSON", "EMAIL_ADDRESS"],
pii_span_types=["LLM", "TOOL"],
)These are project settings, not per-process filters. Supplying them changes the saved project policy seen by other applications and in the dashboard. Omit an option to preserve the existing setting. TypeScript's legacy pii and piiSpanTypes options likewise describe server processing; a value such as hash does not hash content inside the TypeScript process. Go currently has no SDK-side project-policy override.
Managed prompts are a separate data path
Telemetry masking applies to trace/log export only. It does not rewrite prompt content sent through getPrompt/createPrompt or Python's managed-prompt methods. Prompt CRUD is an intentional authenticated product-data request; see Managed prompt privacy, ownership, and retention.
If prompt content must be transformed before storage, transform it explicitly in application code before calling the prompt API. Neatlogs does not currently expose a prompt transform option, and enabling telemetry masking must not be treated as proof that managed-prompt content was masked.
