Skip to main content
When working with LangSmith traces, you may need to prevent sensitive information from being logged to maintain privacy and comply with security requirements. LangSmith provides multiple approaches to protect your data before it’s sent to the backend:
If your compliance or privacy requirements mandate that certain operations should never be traced at all (for example, clients with zero-retention policies), consider using conditional tracing to disable tracing selectively for specific requests instead of masking data.

Hide inputs and outputs

If you want to completely hide the inputs and outputs of your traces, you can set the following environment variables when running your application:
This works for both the LangSmith SDK (Python and TypeScript) and LangChain. You can also customize and override this behavior for a given Client instance. This can be done by setting the hide_inputs and hide_outputs parameters on the Client object (hideInputs and hideOutputs in TypeScript). The following example returns an empty object for both hide_inputs and hide_outputs, but you can customize this to your needs:

Hide metadata

The hide_metadata parameter allows you to control whether run metadata is hidden or transformed when tracing with the LangSmith Python SDK. Metadata is passed with the extra parameter when creating runs (e.g., extra={"metadata": {...}}). hide_metadata is useful for removing sensitive information, complying with privacy requirements, or reducing the amount of data sent to LangSmith. You can configure metadata hiding in two ways:
  • Using the SDK:
  • Using environment variables:
The hide_metadata parameter accepts three types of values:
  • True: Completely removes all metadata (sends an empty dictionary).
  • False or None: Preserves metadata as-is (default behavior).
  • Callable: A custom function that transforms the metadata dictionary.
When set, this parameter affects the metadata field in the extra parameter for all runs created or updated by the Client, including runs created through the @traceable decorator or LangChain integrations.

Hide all metadata

Set hide_metadata=True to remove all metadata completely from runs sent to LangSmith:

Custom transformation

Use a callable function to selectively filter, redact, or modify metadata before it’s sent to LangSmith:

Rule-based masking of inputs and outputs

This feature is available in the following LangSmith SDK versions:
  • Python: 0.1.81 and above
  • TypeScript: 0.1.33 and above
To mask specific data in inputs and outputs, you can use the create_anonymizer / createAnonymizer function and pass the newly created anonymizer when instantiating the Client. The anonymizer can be either constructed from a list of regex patterns and the replacement values or from a function that accepts and returns a string value.
For redacting API keys, tokens, and other credentials, see Redact secrets from traces for ready-to-use regex patterns and recipes.
The anonymizer will be skipped for inputs if LANGSMITH_HIDE_INPUTS = true. Same applies for outputs if LANGSMITH_HIDE_OUTPUTS = true. However, if inputs or outputs are to be sent to Client, the anonymizer method will take precedence over functions found in hide_inputs and hide_outputs. By default, the create_anonymizer will only look at maximum of 10 nesting levels deep, which can be configured via the max_depth parameter.
Please note, that using the anonymizer might incur a performance hit with complex regular expressions or large payloads, as the anonymizer serializes the payload to JSON before processing.
Improving the performance of anonymizer API is on our roadmap! If you are encountering performance issues, please contact support via support.langchain.com.
Hide inputs outputs Older versions of LangSmith SDKs can use the hide_inputs and hide_outputs parameters to achieve the same effect. You can also use these parameters to process the inputs and outputs more efficiently.

Processing inputs and outputs for a single function

The process_outputs parameter is available in LangSmith SDK version 0.1.98 and above for Python.
In addition to Client-level input and output processing, LangSmith provides function-level processing through the process_inputs and process_outputs parameters of the @traceable decorator. These parameters accept functions that allow you to transform the inputs and outputs of a specific function before they are logged to LangSmith. This is useful for reducing payload size, removing sensitive information, or customizing how an object should be serialized and represented in LangSmith for a particular function. Here’s an example of how to use process_inputs and process_outputs:
In this example, process_inputs creates a new dictionary with processed input data, and process_outputs transforms the output into a specific format before logging to LangSmith.
It’s recommended to avoid mutating the source objects in the processor functions. Instead, create and return new objects with the processed data.
For asynchronous functions, the usage is similar:
These function-level processors take precedence over Client-level processors (hide_inputs and hide_outputs) when both are defined.

Examples

You can combine rule-based masking with various anonymizers to scrub sensitive information from inputs and outputs. The following examples will cover working with regex, Microsoft Presidio, and Amazon Comprehend.

Regex

The implementation below is not exhaustive and may miss some formats or edge cases. Test any implementation thoroughly before using it in production.
You can use regex to mask inputs and outputs before they are sent to LangSmith. The implementation below masks email addresses, phone numbers, full names, credit card numbers, and SSNs.
The anonymized run will look like this in LangSmith: Anonymized run The non-anonymized run will look like this in LangSmith: Non-anonymized run

Microsoft Presidio

The implementation below provides a general example of how to anonymize sensitive information in messages exchanged between a user and an LLM. It is not exhaustive and does not account for all cases. Test any implementation thoroughly before using it in production.
Microsoft Presidio is a data protection and de-identification SDK. The implementation below uses Presidio to anonymize inputs and outputs before they are sent to LangSmith. For up to date information, please refer to Presidio’s official documentation. To use Presidio and its spaCy model, install the following:
Also, install OpenAI:
The anonymized run will look like this in LangSmith: Anonymized run The non-anonymized run will look like this in LangSmith: Non-anonymized run

Amazon Comprehend

The implementation below provides a general example of how to anonymize sensitive information using Amazon Comprehend. It is not exhaustive and does not account for all run shapes or content types. Test any implementation thoroughly before using it in production.
Comprehend is a natural language processing service that can detect personally identifiable information. The implementation below uses Comprehend’s DetectPiiEntities API to anonymize inputs and outputs before they are sent to LangSmith.
Amazon Comprehend does not provide a batch PII endpoint. detect_pii_entities processes one document per call, and batch_detect_entities detects generic entities (people, places, organizations) — it is not a PII-specific API. To process many documents, either call detect_pii_entities in a loop (shown below) or use the asynchronous start_pii_entities_detection_job on documents in S3.
To use Comprehend, install boto3:
Also, install OpenAI:
You will need to set up credentials in AWS and authenticate using the AWS CLI. Follow the AWS Comprehend setup instructions. The example below walks the entire input/output payload recursively and runs every string through Comprehend. Walking the payload (rather than only inspecting data["messages"] or data["choices"][0]["message"]) ensures PII is scrubbed across spans of all shapes — not just chat-completion-shaped runs.
Because comprehend_anonymize issues one Comprehend API call per string it encounters, it can become rate-limit-bound on high-throughput traces. For higher throughput, use the batch processing approach below, or pre-filter with contains_pii_entities and only call detect_pii_entities when PII is present.
The anonymized run will look like this in LangSmith: Anonymized run The non-anonymized run will look like this in LangSmith: Non-anonymized run

Using create_anonymizer with Comprehend

If you prefer LangSmith’s built-in create_anonymizer helper (which already handles the recursive walk and integrates cleanly with langchain agent middleware), you can pass a Comprehend-backed callable to it instead of writing the walk yourself:
This gives you the same redaction behavior as comprehend_anonymize above with less boilerplate, and is the recommended approach when you also use create_anonymizer elsewhere in your stack.

Batch processing for high-throughput masking

The previous approaches on this page process each run individually. If your masking logic involves a rate-limited API or model inference—such as the Presidio or Amazon Comprehend examples—processing runs one at a time can create a bottleneck. process_buffered_run_ops lets you intercept a batch of raw run dicts before they are serialized and sent to the API, so you can amortize the cost across multiple runs at once. LangSmith processes these runs in a background thread, which does not block your application. LangSmith holds runs in an in-memory buffer and flushes them as a batch when either:
  • run_ops_buffer_size run operations have accumulated, or
  • run_ops_buffer_timeout_ms milliseconds have elapsed since the last run was added (default: 5000 ms).
Your function receives the batch as a list of raw run dicts and must return a list of the same length, in the same order, with run IDs unchanged. Breaking either constraint raises a ValueError.
run_ops_buffer_size counts individual run operations, not unique runs. Each traced call typically produces two operations: a create (when the run starts) and an update (when it ends with outputs). Set your buffer size accordingly. For example, run_ops_buffer_size=1000 will buffer approximately 500 traced calls. Because of this, the same run ID may appear twice in a single batch: once with inputs and once with outputs.
The buffer only flushes automatically when the size limit is reached or the timeout elapses. Always call client.flush() before your program exits to avoid dropping buffered runs.
Each run dict in the batch is either a create operation (with inputs, sent when the run starts) or an update operation (with outputs, sent when it ends). Here’s what a typical pair looks like for a single traced call:
Amazon Comprehend does not have a batch PII endpoint. batch_detect_entities detects generic entities (people, places, organizations), not PII, and is not a drop-in replacement for detect_pii_entities. The batch optimization below comes from deduplicating identical strings across runs and from amortizing per-run buffering overhead — not from a single bulk API call. If you need true bulk PII detection, run the asynchronous start_pii_entities_detection_job over documents in S3 outside of the tracing path.
The following example collects every string across the entire buffer, deduplicates them, and calls Comprehend’s detect_pii_entities endpoint once per unique string. For traffic that repeats common prompts, system messages, or tool inputs, this can drastically reduce the number of Comprehend calls compared to a per-run approach. The example walks the full payload recursively so it works for any run shape — chat messages, tool inputs/outputs, retriever spans, etc.
process_buffered_run_ops and run_ops_buffer_size must always be set together—providing one without the other raises a ValueError.