Sooner or later a response body ends up in a ticket, a pull request comment, a chat thread or an AI assistant. JSON copied straight from DevTools tends to carry more than the bug: bearer tokens, session cookies, API keys, customer emails and phone numbers. Once posted, it is typically indexed for search, copied into notification emails and kept for as long as that system keeps anything. Rotating a leaked key takes far longer than redacting it.
Start by formatting the JSON in a browser-local formatter so you can see what is actually in it. Then find the sensitive parts, redact them, cut the document down to the relevant piece, and pick a layout your reader can use.
Where you format matters
Pasting a payload into an online formatter that processes it on a server is already sharing it, with a party you know nothing about. The DevPrix formatter parses and prints with your browser's own JSON engine, so nothing you paste is uploaded. You don't have to take that on trust: open your browser's developer tools, switch to the Network tab, paste, and confirm that no request carries your data.
One DevPrix feature needs care. The Share button copies a link that contains your input, Base64url-encoded, after the #. Browsers don't send that fragment to the server, but the link is the data: anyone who receives it can decode it, and every place you paste it keeps a copy. For sensitive input, copy the output instead of sharing a link.
Find everything sensitive first
Scrolling through three thousand formatted lines is not a search. The JSONPath evaluator lists every match for a key at any depth with recursive descent:
$..accessToken
$..refreshToken
$..email
$..password
Each expression returns all matching values wherever they sit. Key matching is exact and case-sensitive, so try the spellings your API uses, such as access_token, Authorization or apiKey. Beyond key names, look for:
- Strings starting with
eyJ, which is how Base64-encoded JSON such as{"alg"begins. These are almost always JWTs, and cutting off the signature doesn't help: the payload is encoded, not encrypted. See how to read JWT claims for what anyone can read from one. - Signed URLs, whose query strings carry signatures or temporary credentials.
- Cookies and
Set-Cookieheaders in captured requests. - Personal data: names, emails, phone numbers, addresses and IP addresses.
- Internal hostnames, account IDs and connection strings inside error messages.
Redact, don't delete
Replace sensitive values with placeholders instead of removing the keys. The reader still sees the structure, which is often the reason you are sharing at all. With jq, redacting by key name at every level:
jq 'walk(if type == "object" then with_entries(
if (.key | test("token|secret|password|authorization|api-?key"; "i"))
then .value = "[REDACTED]" else . end)
else . end)' response.json
The same idea in a browser console or Node, with a JSON.stringify replacer, where data is the parsed response:
const SECRET = /token|secret|password|authorization|api-?key/i;
const safe = JSON.stringify(data, (key, value) => (SECRET.test(key) ? "[REDACTED]" : value), 2);
Either one turns this:
{"session": {"accessToken": "example-access-token", "refreshToken": "example-refresh-token"},
"headers": {"Authorization": "example-auth-header", "x-api-key": "example-api-key"}}
into this:
{
"session": {
"accessToken": "[REDACTED]",
"refreshToken": "[REDACTED]"
},
"headers": {
"Authorization": "[REDACTED]",
"x-api-key": "[REDACTED]"
}
}
Two refinements. If the reader needs to tell records apart, use stable pseudonyms such as user-A and user-B rather than one placeholder for everything. And key-based redaction only catches keys: a secret inside free text, such as an error message quoting a connection string or a URL with a token in its query string, needs a manual pass.
Share only the part that matters
The safest data is the data you leave out. If the bug is about failed orders, the session block and the customer profile don't belong in the ticket. Given a response like this:
{
"session": { "accessToken": "example-access-token", "refreshToken": "example-refresh-token" },
"customer": { "id": "cus_7731", "email": "ana@example.com" },
"orders": [
{ "id": "ord_1001", "status": "paid", "total": 1299 },
{ "id": "ord_1002", "status": "failed", "total": 499, "error": { "code": "card_declined" } },
{ "id": "ord_1003", "status": "failed", "total": 2150, "error": { "code": "timeout" } }
]
}
The expression $.orders[?(@.status == 'failed')] returns just the two failed orders:
[
{
"id": "ord_1002",
"status": "failed",
"total": 499,
"error": {
"code": "card_declined"
}
},
{
"id": "ord_1003",
"status": "failed",
"total": 2150,
"error": {
"code": "timeout"
}
}
]
Narrow further with $.orders[?(@.status == 'failed')].error, or list the affected IDs with $.orders[?(@.error)].id. Filters in the evaluator test a direct child key, either for existence or with ==, !=, <, <=, > or >=. A single match prints as itself and several print as an array; copy the result, or download it as jsonpath-results.json.
Pretty or minified?
- Pretty-printed with 2 spaces for anything a person will read: tickets, pull request comments, chat. Put it in a code block, for example a fenced block opened with
```jsonwhere Markdown is supported, so the app doesn't reflow whitespace or swap straight quotes for curly ones. Curly quotes are one of the common JSON syntax errors your reader will hit when they paste it back. - Minified when it has to fit on one line: a curl
-dargument, an environment variable, a log search. It is unreadable in review, so keep it out of tickets. - Sorted keys when the reader will compare your copy against theirs. Sort keys in the formatter sorts keys at every level, so both copies line up.
A pre-share checklist
- Format it locally and skim the whole structure in Tree view.
- Search for tokens, keys and personal data with recursive JSONPath queries.
- Redact by key, keeping the structure, then check free-text fields by hand.
- Extract only the subtree the reader needs.
- Pretty-print it inside a code block, and copy the text rather than sending a share link.
Next steps
Paste the payload into the JSON formatter, then run a few $.. queries in the JSONPath evaluator before anything leaves your machine. If you are sharing two versions of a response to show a regression, compare them structurally and post the diff instead of both bodies.