Beautify JSON online: paste a 40 KB single line, a webhook envelope buried in backslashes, or a log file with one object per row. This page is about those awkward real-world shapes — the JSON that does not pretty print cleanly on the first try.
Beautify, format, prettify, pretty print — four words, one operation: putting back the line breaks and indentation a machine left out. No specification defines any of them, so every tool picked its own; if you searched for one, this is the other three as well. The genuine opposites are beautify and minify.
{"event":"invoice.paid","ts":1717243800,"data":{"id":"in_88","total":4250,"lines":[{"sku":"seat","qty":3}]},"retry":false}
{
"event": "invoice.paid",
"ts": 1717243800,
"data": {
"id": "in_88",
"total": 4250,
"lines": [
{
"sku": "seat",
"qty": 3
}
]
},
"retry": false
}
How wide that indent should be — two spaces, four, or tabs — and whether to sort the keys is answered on the JSON formatter page. The rest of this page deals with input that will not become readable just by re-indenting it.
.json file onto the page.The commonest reason a payload will not become readable is that it is not one JSON document but two, nested. A service serialised an object into a string and put that string in a field of another object; the inner quotes had to be escaped to survive, so what arrives is a wall of backslashes.
{"id":"evt_31","payload":"{\"user\":{\"id\":1,\"name\":\"Ada\"},\"ok\":true}","received":1717243800}
{
"user": {
"id": 1,
"name": "Ada"
},
"ok": true
}
Beautifying the outer document barely helps: to the parser payload is one
token. It gets a line of its own and stays a wall of backslashes, so you have to pull the
inner document out and beautify it separately.
JSON.stringify on a value that was already a string.
The giveaway is a run of \" sequences inside a value, usually
opening with "{\". An ordinary string needs
\" only when the text really contains a quotation mark, so a dozen
in a row means the value is a serialised document — and three backslashes before a quote
means three levels deep.
When the whole payload is one quoted string rather than a field, paste it as-is: the viewer recognises a JSON string that contains JSON and offers an Unescape button. If you own the producing code, stop stringifying twice.
JSON is defined over Unicode text, and it offers two equally legal spellings for any
character that is not a quote, a backslash or a control character: the character itself,
or a \uXXXX escape. "café" and
"caf\u00e9" are the same four-character string, so a payload
that arrives like this is not broken.
{
"city": "M\u00fcnchen",
"note": "\u0441\u043f\u0430\u0441\u0438\u0431\u043e",
"mood": "\ud83d\ude00"
}
A beautifier will not turn those back into München,
спасибо and an emoji, and it should not: swapping escapes for literal
characters rewrites the bytes of your document. The tree does make them readable,
because it shows parsed values and the escapes decode on the way in.
Python is the usual explanation: json.dumps escapes every non-ASCII
character because ensure_ascii defaults to True, and
ensure_ascii=False sends them through as UTF-8. JavaScript's
JSON.stringify does the opposite, which is why the same object serialised by
a Node service and a Python service can look nothing alike.
A \uXXXX escape carries exactly four hex digits, which only
reaches U+FFFF. Anything above that — emoji, many CJK extension characters — must be
written as a UTF-16 surrogate pair: a high surrogate in U+D800–U+DBFF then a low surrogate
in U+DC00–U+DFFF. U+1F600 becomes \ud83d\ude00. Two side
by side decode to one character; a lone one usually means a string was cut in half by a
length-based truncation upstream.
Past a certain size, beautifying stops being the thing that makes JSON readable. A 40 KB line becomes three thousand lines, and scrolling three thousand lines is not comprehension. These are the moves that work.
customer_id but not where it lives.$.data.lines[0].sku. Paste that into the ticket and the next person lands where you were.The JSON tree viewer page covers navigation properly: beautify to check the document is sane, then switch to the tree to find anything.
Log pipelines, bulk exports and streaming APIs often emit JSON Lines — also written NDJSON — one complete JSON value per line, with no commas between them and no brackets around the whole thing. That way a process can append one record at a time and a reader can handle one at a time.
The consequence surprises people: a JSON Lines file is not a JSON document. Paste the whole thing into a beautifier and you get a parse error at the start of line two, because the document already ended when the first value did.
{"ts":"2026-08-06T09:15:02Z","level":"info","msg":"cache warm","ms":12}
{"ts":"2026-08-06T09:15:03Z","level":"warn","msg":"retry","attempt":2}
{"ts":"2026-08-06T09:15:09Z","level":"error","msg":"upstream timeout"}
Three valid documents; zero valid documents taken together. Beautify one line at
a time when you are chasing a single request ID through a log dump. Otherwise
wrap the lines into an array: [ before the first record,
] after the last, and a comma at the end of every line but the last — one
valid array that beautifies in a single pass.
[
{"ts":"2026-08-06T09:15:02Z","level":"info","msg":"cache warm","ms":12},
{"ts":"2026-08-06T09:15:03Z","level":"warn","msg":"retry","attempt":2},
{"ts":"2026-08-06T09:15:09Z","level":"error","msg":"upstream timeout"}
]
Two things to watch. A comma after the last record is a syntax error — the mistake everyone makes when adding commas with find-and-replace — and blank lines between records become empty elements that will not parse. Log records are also very often the double-encoded case from earlier, so you may need both moves in sequence.
Nothing — all four name the same operation: putting line breaks and indentation back into JSON so a person can read it. No specification defines the terms, so different tools picked different words. The real opposites are beautify and minify.
Beautify the outer document first to see which field holds the escaped text, then copy that field's value and beautify it separately. Clicking a value in the tree copies the decoded string, so the backslashes are already gone. If the whole payload is one quoted string, the viewer offers an Unescape button.
Because whatever produced it escaped every non-ASCII character. \u0441 is the Cyrillic letter с, and "caf\u00e9" is the same string as "café" — both spellings are valid JSON, so a beautifier leaves them alone. The usual cause is Python's json.dumps, which escapes non-ASCII unless you pass ensure_ascii=False.
Not in one pass: a JSON Lines file is not one JSON document but one independent value per line. Either beautify a line at a time, or make it a valid array first — brackets around the whole set, and a comma at the end of every line but the last.
No — only the whitespace between tokens moves, so the text parses to the same value, and Unicode escapes are left as they were. The caveat is that a beautifier parses and re-serialises, so numbers return in canonical form: 1.0 comes back as 1, and an ID beyond about sixteen digits can be rounded.
No. The beautifier is JavaScript running in your browser: the text is parsed, indented and rendered locally, and nothing is uploaded. That makes it safe for API responses, access tokens and customer records.