Appearance
Privacy & Redaction
The SDK captures MCP activity inside the vendor server process, then applies Within privacy rules before anything leaves that process. The Within API runs server-side Presidio redaction before SDK activity is stored. CRM connectors must create subjects locally and omit raw CRM identities before delivery.
The TypeScript and Python SDKs apply identical redaction rules and identical subject hashing — the key patterns below, the value patterns, and the hash construction are byte-for-byte equivalent and verified by cross-language parity tests.
What is captured
With the default configuration, the SDK captures:
initialize,tools/list, andtools/calllifecycle events- tool name, timing, success or error state, and MCP client/server metadata
- tool arguments and tool responses after redaction and truncation
get_more_toolsfeedback, stored outside SDK lead scoring- the subject created locally from
identify().userId, when available - redacted
userDatatraits returned fromidentify()
Raw userId and userName are never sent. userId is hashed locally with vendorSlug; userName is dropped.
Default redacted keys
Any object key containing these substrings is removed or replaced with [redacted]:
| Pattern |
|---|
auth |
authorization |
cookie |
email |
e_mail |
full_name |
identity |
firstname |
first_name |
lastname |
last_name |
org_domain |
orgdomain |
phone |
requester_name |
author_name |
customer_name |
user_name |
username |
user_id |
userid |
token |
secret |
password |
api_key |
apikey |
access_token |
refresh_token |
ssn |
card |
cvv |
Matching is case-insensitive and treats spaces or dashes as underscores. Common personal-data and secret-like string values, including email addresses, phone-like strings, SSNs, card-like strings, bearer tokens, and API-key-like values, are also redacted.
Server-side Presidio redaction
Within runs a separate server-side redaction service before writing SDK activity or CRM outcomes to storage. This service uses Microsoft's Presidio analyzer and anonymizer APIs with a model-free recognizer profile. It does not download or run spaCy, transformer, or LLM models.
The server-side profile is rule/checksum/pattern based. It looks for values such as:
- email addresses
- phone numbers
- SSNs, ITINs, passport-like identifiers, MBI, NPI, and other US identifier patterns
- credit-card-like values, bank/routing-number-like values, IBANs, crypto addresses
- URLs and IP addresses
- bearer tokens, API keys, secrets, and password-like assignments
Detected values are replaced with typed placeholders such as <EMAIL_ADDRESS>, <PHONE_NUMBER>, <US_SSN>, or <API_KEY>. Within stores counts-only redaction metadata, such as entity counts, redaction profile, service version, and latency. It does not store original spans or raw values.
Because the Presidio profile is model-free, arbitrary names, locations, and free-form person references are not a guaranteed detection target unless they match a configured pattern or sensitive field key.
Additional redaction
Add domain-specific key redaction with privacy.redactKeys. You can also provide text redaction with redactSensitiveInformation.
redactSensitiveInformation is called once per string value in the event — it receives individual strings (a tool argument, a response fragment, a trait), never the event object. Return the string, transformed or not. Two behaviors to know:
- If your redactor throws, the event is dropped rather than sent unredacted (fail closed). Your server is unaffected, but the event is gone — wrap risky logic and return a placeholder instead of letting errors escape.
- Returning
None/undefinedor a non-string is treated as a no-op for that value; the built-in pipeline still applies.
ts
track(server, 'acme', {
apiKey: process.env.WITHIN_SDK_API_KEY!,
privacy: {
redactKeys: ['license_key', 'private_note', 'internal_cost'],
},
redactSensitiveInformation: async (text) =>
text.replace(/tenant-secret-[a-z0-9]+/gi, '[redacted]'),
});python
import re
from within_sdk import PrivacyOptions
track(server, "acme", WithinOptions(
privacy=PrivacyOptions(
redact_keys=["license_key", "private_note", "internal_cost"],
),
redact_sensitive_information=lambda text: re.sub(
r"tenant-secret-[a-z0-9]+", "[redacted]", text, flags=re.IGNORECASE
),
))Within privacy sanitization runs after custom redaction and before the Within API or vendor exporters. Server-side Presidio redaction runs again before Within storage.
CRM outcome privacy
The upcoming Salesforce connector sends subjects and normalized lifecycle fields, not raw Salesforce identities or record IDs. The CRM outcomes API rejects direct identity and record fields, limits metadata to scalar values, and applies server-side redaction before storage. See Salesforce CRM outcomes for the exact request constraints and availability.
Binary and large payload handling
The SDK omits or truncates values that are risky or too large.
| Data shape | Behavior |
|---|---|
ArrayBuffer or typed array | Replaced with [binary omitted]. |
| Circular reference | Replaced with [circular]. |
| Function or symbol | Omitted. |
| BigInt | Serialized as a string. |
| Error | Captures name and redacted truncated message. |
| Arrays | Limited to first 100 entries. |
| Long string | Truncated above privacy.maxFieldBytes, default 32768. |
| Large captured payload | Replaced with an omission marker above privacy.maxEventBytes, default 128000. |
Exporters
Datadog, Sentry, PostHog, and OTLP exporters (TypeScript SDK only) receive sanitized events only. Exporters do not receive raw userId, userName, direct identity fields, tokens, or unredacted MCP payloads from the SDK.
