How to sanitize json before structured logging
- Step 1Capture a representative payload — Take one real request/response body that flows through your logger, save it as
.json, and drag it onto the dropzone. It is read in-browser; the secret-bearing payload is never uploaded. - Step 2List the secret keys — Type the sensitive field names into Keys (comma-separated) — e.g.
password, token, authorization, apiKey, cardNumber, cvv, ssn, secret. Spaces are trimmed automatically. - Step 3Keep Remove listed — Stay on the default Remove listed mode so the named secret keys are the ones removed. This mirrors a deny-list redactor — the standard pattern for log sanitisation.
- Step 4Leave Deep on — Keep Deep (all levels) ticked so secrets are scrubbed from nested objects and array elements, not just the top level. Most real payloads nest credentials, so Deep on matches a real redactor.
- Step 5Run and confirm the count — Click Filter Keys. The panel shows the scrubbed JSON and a
N keys removedcount — confirm it matches the number of secret occurrences you expected so you know none slipped through. - Step 6Use the safe copy — Copy or download the scrubbed
.filtered.jsonfor your fixture or ticket. To go further and irreversibly mask values you must keep (e.g. hash an email rather than drop it), follow up with the JSON Anonymizer.
Common secret keys and what gets caught
Behaviour with Remove listed + Deep on. Exact, case-sensitive matching — these are exactly the keys removed, and the lookalikes that are NOT.
| Key listed | Removed | NOT removed (gap to watch) | Note |
|---|---|---|---|
| password | password at any depth | passwordHash, Password | Hash fields can still be sensitive — list them if needed. |
| token | token everywhere | refreshToken, csrfToken, tokenType | List each token field explicitly. |
| authorization | authorization header field | Authorization | HTTP header casing varies — list both. |
| cardNumber | cardNumber | card_number, pan | Snake-case and aliases need separate entries. |
| secret | secret | clientSecret, secretKey | Compound secret names are not substring-matched. |
What this scrubs vs what it cannot
Key removal is structural. It cannot reach secrets that are not stored as their own key.
| Secret location | Caught? | Do this instead |
|---|---|---|
A dedicated key (password, token) | Yes — list the key | Remove listed mode |
Inside a free-text string (e.g. a URL with ?token=...) | No | Redact the string value separately |
| Under a key name you did not list | No | Add that exact key name |
| A secret you must keep but mask | Removed, not masked | Use the JSON Anonymizer |
Cookbook
Before/after redactions on real-shaped payloads. Secret values are placeholders — this is what the result panel shows.
Scrub a login request body
ExampleClassic auth payload: drop the credential, keep the rest for debugging. Keys: password, Remove, Deep on.
BEFORE
{ "username": "ada", "password": "hunter2", "rememberMe": true }
AFTER (1 key removed)
{ "username": "ada", "rememberMe": true }Remove a nested bearer token
ExampleTokens often live inside an auth/session block. Deep mode reaches them. Keys: token, authorization.
BEFORE
{ "req": { "headers": { "authorization": "Bearer abc" } },
"auth": { "session": { "token": "sess_123" } } }
AFTER (2 keys removed)
{ "req": { "headers": {} },
"auth": { "session": {} } }Scrub card data from a payment payload
ExampleStrip PAN and CVV before the payload reaches any log. Keys: cardNumber, cvv, expiry.
BEFORE
{ "amount": 42, "cardNumber": "4111111111111111", "cvv": "123", "expiry": "12/27", "currency": "USD" }
AFTER (3 keys removed)
{ "amount": 42, "currency": "USD" }Spot a redaction gap from casing
ExampleA reminder of why testing matters: Authorization survives if you only list authorization. Keys: authorization.
BEFORE
{ "authorization": "Bearer a", "Authorization": "Bearer b" }
AFTER (1 key removed — capitalised header leaked!)
{ "Authorization": "Bearer b" }Scrub secrets across an array of log events
ExampleDeep mode removes the secret from every event in a batch. Keys: apiKey.
BEFORE
[
{ "event": "call", "apiKey": "sk_live_1" },
{ "event": "call", "apiKey": "sk_live_2" }
]
AFTER (2 keys removed)
[
{ "event": "call" },
{ "event": "call" }
]Errors and edge cases
Real errors and silent failures sourced from each platform's own documentation. Match the wording to the row, fix what the row says to fix.
Secret embedded in a string value
Not caughtKey removal only drops whole keys. A token in a URL ("url": "https://x?token=abc") or in a free-text message survives because it is not its own key. Redact string values with a different approach.
Casing mismatch on header fields
Not removedHTTP-style fields vary in case (authorization vs Authorization). Matching is case-sensitive, so list every casing your payloads use or a secret can leak.
Compound secret name
PreservedListing secret removes only secret; clientSecret, secretKey, and webhookSecret stay. List those exact names too.
Input is not valid JSON
Invalid JSONCaptured log lines are sometimes truncated or wrapped. If JSON.parse fails, nothing is scrubbed. Clean the snippet or run it through the JSON Format Fixer first.
Secret must be kept but masked
By designThis tool removes the key entirely; it cannot replace a value with ***. If your log needs the field present but redacted, use the JSON Anonymizer instead.
Listed key absent from this sample
By designA secret key that does not appear in this payload is ignored and adds 0 to the removed count. A different request may still contain it — test multiple samples.
Empty values left behind
PreservedRemoving token from { "headers": { "token": "x" } } can leave { "headers": {} }. The empty object is fine to log; remove it later with the JSON Null Stripper if you prefer.
File over the 2 MB free limit
BlockedFree accounts cap JSON at 2 MB. A large captured batch may exceed it — trim to a sample or upgrade to Pro.
This is a testing aid, not runtime redaction
Manual stepIt validates your key list against a sample but does not run inside your app. Implement the same deny-list in your logging middleware so redaction happens on every request automatically.
Frequently asked questions
Does this redact secrets in my running app?
No — it is a testing/validation aid. You paste a sample payload to prove out the key list, then implement the same deny-list in your logging middleware so redaction runs on every request automatically.
Will it catch a token inside a URL string?
No. It removes whole keys, not substrings of string values. A ?token=... in a URL value survives. Redact string contents with a separate step.
Why did Authorization leak when I listed authorization?
Matching is case-sensitive. HTTP header casing varies, so list authorization, Authorization (and any other casing) to be safe.
Does it scrub secrets nested deep in the payload?
Yes, with Deep (all levels) on. It removes the listed keys from nested objects and from each array element at any depth.
Can I keep the field but mask the value (show ***)?
No — this tool removes the key/value pair. To keep a field but mask or hash its value, use the JSON Anonymizer.
Will listing password also remove passwordHash?
No. Matching is exact, not substring. List passwordHash separately if it is also sensitive.
How do I know the secrets were actually removed?
Check the N keys removed count in the result panel against the number of secret occurrences you expected. Zero usually means a casing or naming mismatch.
Is the payload uploaded anywhere?
No. Parsing and scrubbing happen in your browser, so you can safely process a real secret-bearing payload.
What if the captured JSON is malformed?
Parsing fails and nothing is scrubbed. Repair it with the JSON Format Fixer or validate with the JSON Validator first.
It left empty objects behind — is that a problem?
No, an empty {} is safe to log. If you want them gone, post-process with the JSON Null Stripper.
How large a payload can I test?
Up to 2 MB per JSON file on the free tier; larger samples need Pro or trimming.
Does it change the order of remaining fields?
No. All unlisted keys and array order are preserved; only listed secret keys are removed.
Privacy first
Conversion runs locally in your browser. No file is uploaded — only metadata counters are saved for signed-in dashboard stats.