How it works
AgentMark implements PII masking as an OpenTelemetrySpanProcessor that wraps the export pipeline. When a span finishes, the masking processor intercepts it before the exporter sends data over the network.
Span finishes
Your application completes an LLM call or tool invocation. The span is ready for export.
MaskingSpanProcessor intercepts
If you configure masking, the processor runs env var suppression first, then your mask function on each sensitive attribute.
- The processor redacts configured attributes before export. The processor runs in-memory, in your application, before any network call, so attributes you mask never leave the process in their raw form.
- Zero overhead when masking is off. The SDK only adds the processor to the pipeline when you configure a
maskfunction or set env vars. - Standard OTel pattern. The
MaskingSpanProcessorwraps your existingBatchSpanProcessororSimpleSpanProcessor, with no forking or patching required.
Before and after
WithcreatePiiMasker() enabled, PII tokens like [EMAIL], [SSN], and [PHONE] replace sensitive data in the trace viewer:
![Trace with PII masking enabled, sensitive data replaced with tokens like [EMAIL], [SSN], [PHONE]](https://mintcdn.com/puzzlet-9ba7bb98/5xsP1AqgWmw7fWzd/images/pii-masking/trace-masked.png?fit=max&auto=format&n=5xsP1AqgWmw7fWzd&q=85&s=b2af35f969a957fa2a6a007a5246f15a)
AGENTMARK_HIDE_INPUTS=true, all input attributes show [REDACTED] while outputs remain visible:
![Trace with input suppression, all inputs show [REDACTED]](https://mintcdn.com/puzzlet-9ba7bb98/5xsP1AqgWmw7fWzd/images/pii-masking/trace-redacted.png?fit=max&auto=format&n=5xsP1AqgWmw7fWzd&q=85&s=45f0ddef9e1c12de8c15395a1d421280)
createPiiMasker({ email: true, ssn: true }):
AGENTMARK_HIDE_INPUTS=true:
gen_ai.request.model and gen_ai.usage.total_tokens are never masked. These operational attributes contain no user data.
Basic usage
Pass amask function to AgentMarkSDK. The function receives each string attribute value and returns the redacted version.
mask function on every maskable span attribute before it hands the span to the exporter. The function must be synchronous. You have full control over the replacement logic.
Built-in PII masker
AgentMark ships a built-in PII masker that covers common patterns. Enable the patterns you need:Built-in patterns
email: Matches email addresses likeuser@example.com. Replaced with[EMAIL].phone: Matches phone numbers like(555) 123-4567. Replaced with[PHONE].ssn: Matches Social Security numbers like123-45-6789. Replaced with[SSN].creditCard/credit_card: Matches credit card numbers like4111 1111 1111 1111. Replaced with[CREDIT_CARD].ipAddress/ip_address: Matches IP addresses like192.168.1.100. Replaced with[IP_ADDRESS].
false. AgentMark applies only the patterns you explicitly enable.
TypeScript uses camelCase (
creditCard, ipAddress) while Python uses snake_case (credit_card, ip_address) following each language’s conventions.Custom patterns
You can add custom patterns alongside the built-in ones. Each entry needs a regex pattern and a replacement string.Environment variable suppression
For a zero-code option, set environment variables to suppress all inputs, all outputs, or both:[REDACTED]. This requires no code changes.
If you configure both environment variable suppression and a
mask function, suppression runs first. The mask function then receives the already-suppressed values.Masked attributes reference
AgentMark masks specific span attributes depending on their category. Input attributes (suppressed byAGENTMARK_HIDE_INPUTS):
gen_ai.request.input: the prompt or messages sent to the modelagentmark.request.input: vendor-namespaced input written byobserve()/setInput()(dual-emitted withgen_ai.request.input)gen_ai.request.tool_calls: tool call arguments included in the requestagentmark.dataset_input: the dataset row input attached during experiment runsai.prompt,ai.prompt.messages,ai.prompt.tools,ai.prompt.toolChoice,ai.toolCall.args: prompt, message, and tool-call content emitted by the Vercel AI SDK (experimental_telemetry)gen_ai.input.messages,gen_ai.system_instructions,gen_ai.tool.definitions,gen_ai.tool.call.arguments: input content per the OpenTelemetry GenAI semantic conventionsgen_ai.prompt: legacy OpenTelemetry GenAI prompt attributegen_ai.tool.input: tool input recorded by the Claude Agent SDK integration
AGENTMARK_HIDE_OUTPUTS):
gen_ai.response.output: the model’s text responseagentmark.response.output: vendor-namespaced output written byobserve()/setOutput()(dual-emitted withgen_ai.response.output)gen_ai.response.output_object: structured output from the modelai.response.text,ai.response.toolCalls,ai.response.object,ai.result.text,ai.result.toolCalls,ai.result.object,ai.toolCall.result: response and tool-result content emitted by the Vercel AI SDK (experimental_telemetry)gen_ai.output.messages,gen_ai.tool.call.result: output content per the OpenTelemetry GenAI semantic conventionsgen_ai.completion: legacy OpenTelemetry GenAI completion attributegen_ai.tool.output: tool output recorded by the Claude Agent SDK integration
agentmark.metadata.*: custom metadata attached to spans
Error handling
PII masking uses fail-closed behavior. If yourmask function throws an error, the processor drops the span entirely and never exports it. This ensures that unmasked data never reaches the trace backend.
Tracing continues normally for subsequent spans after a mask failure. The dropped span doesn’t affect the rest of the trace pipeline.
Recipes
Microsoft Presidio (Python)
Microsoft Presidio uses NLP to detect unstructured PII like person names, addresses, and passport numbers that regex patterns miss. Since Presidio is a Python library, this recipe applies to the Python SDK.Python
PERSON, LOCATION, US_PASSPORT, IBAN_CODE, and CRYPTO. See the Presidio supported entities for the full list.
Healthcare (HIPAA)
Combine built-in patterns with custom patterns for Protected Health Information:Python
Financial services
For PCI-DSS compliance, enable credit card masking and add patterns for financial identifiers:TypeScript
For maximum compliance assurance, combine a
mask function with AGENTMARK_HIDE_INPUTS=true as a defense-in-depth strategy. The env var acts as a safety net in case a new input attribute appears that the mask function doesn’t cover.Next steps
Verify your masking in the trace detail view: see Traces and logs for where span attributes appear.Have questions?
Reach out any time:
- Email the team at hello@agentmark.co for support
- Schedule an Enterprise Demo to learn about AgentMark’s business solutions