NeatlogsNeatlogs
Core Concepts

PII Redaction

Automatically redact personally identifiable information from traces before storage.

Neatlogs provides two layers of PII redaction: client-side masking that runs in your process before data leaves, and server-side redaction powered by a Presidio-based microservice that runs on the backend before data is stored.

Client-Side Masking

Use the mask parameter in neatlogs.init() to redact sensitive data before it's exported from your application:

def redact(span):
    attrs = span.get("attributes", {})
    for key in list(attrs):
        if "email" in key or "phone" in key:
            attrs[key] = "***"
    return span

neatlogs.init(mask=redact)

The mask function receives the full span dict and must return the (possibly modified) dict. It runs on every span before export.

Per-Span Masking

Apply a mask to specific spans only using @span(mask=fn) or with trace(..., mask=fn). Per-span masks take precedence over the global mask:

@neatlogs.span(kind="TOOL", mask=redact_pii)
def lookup_customer(email: str):
    ...

Server-Side Redaction

Server-side redaction runs automatically on the Neatlogs backend using a Presidio-based microservice. It detects and redacts PII entities (names, emails, phone numbers, addresses, etc.) from span payloads before they are stored.

Configuration

Server-side redaction is configured at the team level in the Neatlogs dashboard under Settings > PII Redaction. You can configure:

  • Enabled/Disabled — toggle redaction on or off for all projects in the team
  • Entity types — which PII types to detect (e.g., PERSON, EMAIL_ADDRESS, PHONE_NUMBER)
  • Operator — how to redact detected entities:
    • replace — replace with the entity type label (e.g., John<PERSON>)
    • mask — mask characters (e.g., John****)
    • redact — remove the entity entirely
  • Span types — which span kinds to apply redaction to (e.g., only LLM and TOOL spans)

SDK Overrides

Override the team-level settings per project using neatlogs.init():

# Enable redaction regardless of the dashboard setting
neatlogs.init(pii_enabled=True)

# Only redact PII in LLM and TOOL spans
neatlogs.init(pii_span_types=["LLM", "TOOL"])

# Disable redaction for a dev/test environment
neatlogs.init(pii_enabled=False)

When pii_enabled or pii_span_types is not set (default), the team-level dashboard configuration is used.

What Gets Redacted

Server-side redaction covers all user-visible span fields:

CategoryFields
Core I/Oinput_value, output_value
LLM contentcompletion_text, intermediate_steps
Prompt templatesprompt_template, prompt_template_variables, user_prompt_template, user_prompt_template_variables
Tool fieldstool_input, tool_output, tool_parameters, tool_call_function_arguments
Retrievalretrieval_query, retrieval_documents
Rerankerreranker_query, reranker_input_documents, reranker_output_documents
MCPmcp_request_argument, mcp_response_value

Graceful Degradation

If the PII redaction microservice is unavailable or times out, the original data is stored unchanged — ingestion is never blocked. A warning is logged server-side when this occurs.

When to Use Which

ApproachUse when
Client-side maskYou need to redact data before it leaves your infrastructure
Server-side redactionYou want automatic, team-wide PII detection without modifying application code
BothDefense in depth — mask known fields client-side, let the server catch anything else