All posts

How to format JSON safely before sharing it

Before pasting JSON into a ticket or chat: format it locally, find tokens and personal data with JSONPath, redact by key, and share only the part that matters.

By Last reviewed 5 min readJSONSecurityPrivacy

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-Cookie headers 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 ```json where 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 -d argument, 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

  1. Format it locally and skim the whole structure in Tree view.
  2. Search for tokens, keys and personal data with recursive JSONPath queries.
  3. Redact by key, keeping the structure, then check free-text fields by hand.
  4. Extract only the subtree the reader needs.
  5. 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.

Paste anything. devprix picks the tool.

Press ⌘K on any page, paste JSON, a JWT, a timestamp or a URL, and the right tool opens with your data filled in.