Redacting JSON means replacing sensitive values with safe placeholders before the data is shared, logged or used as a test fixture. Good redaction removes the risk while keeping the document useful: the structure stays the same, types stay the same, and relationships between records are still visible. This guide shows patterns that achieve that.
"REDACTED" can hide type-related bugs or cause new ones.userId and ownerId hold the same value, the redacted versions should also match, so you can still tell that the same user owns the record.Before:
json{ "email": "asha.k@realcompany.com", "token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiI0MiJ9.abc", "address": { "line1": "500 Main St", "zip": "78701" } }
After:
json{ "email": "REDACTED_EMAIL", "token": "REDACTED_TOKEN", "address": { "line1": "REDACTED", "zip": "REDACTED" } }
When the same value appears in several places, map each real value to a stable placeholder:
json{ "userId": "USER_001", "ownerId": "USER_001", "approverId": "USER_002" }
You can still see that the owner and the user are the same person, and that the approver is someone else. Keep the mapping out of the shared copy.
Sometimes a value's format matters for debugging, for example when validation rejects a malformed email. Keep the shape but use reserved or fake values:
user1@example.com (the example.com domain is reserved for documentation)+1-555-0100 to +1-555-0199 (reserved for fiction in North America)192.0.2.10 (reserved for documentation by RFC 5737)4242 4242 4242 4242{ "accountId": 111111 } instead of { "accountId": 123456 }For values people need to recognize but not read in full, keep a few characters:
json{ "card": "**** **** **** 4242", "email": "a***@example.com", "apiKey": "sk_live_****9f2a" }
Showing the last few characters of a key is often enough to tell which key was used, without revealing it.
jq can redact specific fields everywhere in a document. This replaces every email, token and password value at any depth:
bashjq 'walk(if type == "object" then with_entries(if (.key | test("^(email|token|password)$"; "i")) then .value = "REDACTED" else . end) else . end)' input.json
Run it on a copy and review the output. Field names vary (e_mail, accessToken, secret), so a block list never catches everything on the first try.
Check all of these, including nested objects and arrays:
notes, description and message, where people paste anythingAfter redacting, search the output for @, eyJ (the start of most JWTs), Bearer, sk_ and key, and scan it in the JSON Formatter tree view. For more habits that prevent leaks, see JSON privacy & safety tips.