Redaction
Remove passwords, personal details and other sensitive fields from Python traces inside your app, before anything is sent to Recount.
The SDK redacts sensitive data at the span level before it is sent. Redacted values are rendered as a censored placeholder in the dashboard.
HTTP headers (automatic)
For http spans, the following request and response headers are always redacted automatically - no configuration needed:
AuthorizationCookie/Set-CookieX-Api-KeyX-Auth-TokenX-Api-SecretX-Access-TokenProxy-Authorization
Header names are matched case-insensitively.
Field redaction syntax
All redact options accept a list of exact paths from the root. Dot notation targets nested fields. Arrays are traversed without consuming a path segment.
| Specifier | Example | Effect |
|---|---|---|
| Root key | 'password' | Redacts the top-level password field only |
| Dot path | 'customer.name' | Redacts name inside the top-level customer object only |
A simple name like 'password' only redacts the root-level field - not fields with the same name deeper in the object. Use a dot path to target nested fields:
# 'name' alone would only redact the root-level 'name' - NOT customer.name or currentPlan.name
# use dot paths to target nested fields:
redact = ["customer.name", "customer.billing.accountName", "customer.billing.accountNumber"]
# output after redaction:
{
"customer": {
"name": "****",
"address": "42 Eucalyptus Drive, Sydney NSW 2000",
"accountNumber": "ACME-00123", # untouched - different path
"billing": {
"accountName": "****",
"bsb": "062-000",
"accountNumber": "****",
},
},
"currentPlan": {
"name": "Standard", # untouched - 'customer.name' does not match this path
"type": "SINGLE_RATE",
},
}Table spans - .redact(fields)
Chain .redact() on the table builder. Fields are matched against the original key name before any label transforms are applied:
recount.table("Current Bill") \
.from_object({
"name": customer["name"], # redacted
"address": customer["address"],
"peakKwh": usage["peak"],
}) \
.redact(["name"]) \
.build()Works with both .from_object() and .from_records(). Dot paths are not supported - matching is by column key only.
Other span types - redact option
Pass a redact list to add_span to redact fields from input and output. Paths are matched from the root; arrays are traversed without consuming a path segment:
recount.add_span("db", "Customer lookup", {
"redact": [
"customer.name",
"customer.billing.accountName",
"customer.billing.accountNumber",
],
"input": {"filter": {"accountNumber": "ACME-00123"}},
"output": {
"customer": {
"name": "Jane Smith",
"billing": {"accountName": "Jane Smith", "accountNumber": "12345678"},
},
"currentPlan": {"name": "Standard"}, # not redacted - different path
},
})Database parameter redaction - redactParams
Pass the exact parameter values to redact from a db span's input.params:
recount.add_span("db", "User lookup", {
"input": {"query": "SELECT * FROM users WHERE id = $1", "params": [user_id]},
"redactParams": [user_id],
})Manual redaction
Use recount.REDACTED to redact a value yourself before passing it anywhere:
import recount
recount.add_span("json", "Payload", {
"output": {
"apiKey": recount.REDACTED,
"endpoint": config["endpoint"],
},
})