AIBOX

JSON Formatter and Validator

Pretty-print JSON with 2 spaces, 4 spaces or tabs, minify it back to a single line, or find out why it will not parse — with the line and column of the error. Nothing you paste leaves your browser.

Paste an API response, a config file or a fragment you typed by hand. While you type, short inputs are checked automatically. In the box, Ctrl/⌘ + Enter formats.

Top level
Keys inside objects
Nesting depth
Characters in
Bytes in (UTF-8)
Lines in

Nothing you type is sent to us — parsing, formatting and minifying all run in this page. See our privacy policy.

How to use it

  1. Paste the JSON. An API response, a config file, a log payload or a fragment you typed by hand. Short inputs are validated as you type; anything longer is left until you ask, because re-parsing a large file on every keystroke makes typing feel broken.
  2. Pick an indent and press Format. Two spaces is the convention most tools emit and what diff views expect; four spaces is common in Java and .NET projects; tabs keep the file small and let each reader choose their own width. Minify does the opposite: one line, no spaces at all.
  3. Read the result, then copy or download. The statistics underneath tell you what the parser actually saw: the type at the top level, how many keys exist in total, how deep the structure goes, and the size in characters and UTF-8 bytes.

If the text is not valid JSON you get no output at all — you get the line, the column and a plain-language reason. That is on purpose: a half-formatted result would look like a success.

Invalid JSON is reported, never repaired

Many formatters quietly fix what you paste: they delete a trailing comma, convert single quotes to double quotes, strip comments. That produces a file which looks correct in your editor and still fails in the program you send it to — and it hides the real problem, which is usually that the text was never JSON to begin with.

This tool does not rewrite your input. When parsing fails you get the position and the reason, and the decision about what the data was meant to be stays with you. The seven causes below account for most of what people paste:

What was pastedWhat JSON requiresWhere it usually comes from
{"a": 1,}No comma before } or ]Hand-edited config, or a JavaScript object literal
{'a': 1}Double quotes for keys and stringsPython dictionaries, JavaScript literals
{a: 1}Keys must be quoted stringsJavaScript object shorthand, YAML
// noteNo comments of any kindJSONC, tsconfig files, annotated examples in docs
NaN, Infinity, undefinedOnly numbers, strings, booleans, null, arrays and objectsSerialising a JavaScript value that never matched the spec
01, 0x1F, +5No leading zeros, no hex, no leading plusNumbers copied out of code
{"a": 1 "b": 2}A comma between membersEditing by hand, or a truncated paste

Two of these deserve a note, because the error message is not where the mistake is. A missing comma is reported at the character that should have followed it, and an unclosed bracket is reported past the end of the text — the file simply stopped. In both cases the reported position is correct; it just points at the moment the parser could no longer continue.

Where the line and column come from

Browsers describe the same JSON error in completely different words. Chrome's engine reports a character position and a line and column; Firefox's reports only a line and column; Safari's often reports neither. So this tool never copies the message — it takes the character position when the engine provides one, and when it does not, it locates the failure with its own strict scanner that follows the JSON grammar token by token.

Line and column are then computed from that character offset against the text you pasted, with three rules:

  • Lines are counted by line breaks. A CRLF file and an LF file with identical content report the same line and the same column — otherwise the same document would appear to have two different errors on Windows and macOS.
  • Columns are counted in characters, not bytes or UTF-16 units. A Chinese character or an emoji occupies one column, which is what your editor shows.
  • If nothing can locate the character, the tool says so. It does not print an invented position to look authoritative.

This matters more than it sounds. The position is the only part of a syntax error you can act on: without it you are scanning a 4,000-line payload by eye.

Two cases where formatting changes your data

Formatting should be lossless, and for well-formed JSON it is. There are exactly two exceptions, and this tool reports both instead of leaving you to discover them later.

Duplicate keys

JSON's grammar permits an object to contain the same key twice; it does not say what that means. Every JavaScript engine, including the one in your browser, keeps the last value and discards the earlier one. So formatting {"a": 1, "a": 2} gives you {"a": 2}, and the first value is gone. This tool lists the duplicate paths it found, because that is the difference between "reformatting" and "changing the file".

Integers beyond the exact range

JavaScript has a single number type, a 64-bit double, and it represents integers exactly only up to 9,007,199,254,740,991 (253 − 1). A 20-digit order ID or a snowflake ID has already been rounded by the time anything can look at it: 12345678901234567890 becomes 12345678901234567000. The tool counts integers past that limit and names them, because a rounded identifier is the kind of defect that surfaces days later in production rather than in your editor.

In both cases the fix is on your side of the fence: if the earlier duplicate was intended, or if the ID must be preserved exactly, the answer is a tool that keeps number literals — for example jq on the command line, or a parser configured to read big numbers as strings.

Large files, long pastes and the browser tab

Parsing and re-serialising happen on the same thread that draws the page, so there is a point past which a formatter stops being a convenience and starts looking like a frozen tab. Three limits follow from that, all of them stated rather than silently enforced:

  • 2,000,000 characters is the hard maximum. Larger input is refused with an explanation instead of being attempted, because the freeze would be indistinguishable from a crash.
  • Pastes over 300,000 characters show a working indicator first and are computed on the next tick of the event loop, so the interface paints before the work starts. Below that, the work finishes inside a frame and the indicator would only flicker.
  • Very deeply nested JSON can be valid and still not survive re-serialisation: the native writer is recursive, and around five thousand levels of nesting it runs out of stack. The tool detects that case and tells you the data is fine and the tool is the problem — which is the honest framing, and the reason the answer is a command-line parser.

None of these limits apply to correctness: a 400 KB payload is formatted as exactly as a 4-byte one.

What leaves this page

Nothing. There is no upload, no request to our server, no analytics event attached to your data and no storage of any kind: the page imports one small module of pure functions and works from there. Close the tab and the JSON you pasted is gone.

That does not make it a safe place for every payload. If you are on a shared or managed machine, the clipboard, the download and the browser's own memory are all outside this page's control — and any live credential you paste is a live credential. The tool shows you what it saw, but you are still responsible for what you carry around.

Common questions

Why does my JSON fail here when it was fine in JavaScript?
Because a JavaScript object literal is not JSON. In JavaScript you can leave keys unquoted, use single quotes, add a trailing comma, write // comments and use NaN or undefined. JSON allows none of those, and JSON.parse rejects all of them. This tool follows JSON, so a trailing comma is reported as an error at its line and column rather than being removed. If the text came from a .js file, that difference is usually the whole problem.
Can I trust the line and column it reports?
They are computed from the character position of the error, not copied from the browser error message, because browsers describe the same error in completely different words: Chrome gives a character position, Firefox gives a line and column, and Safari often gives neither. When the browser reports no position, this tool locates the failure with its own strict scanner. Line numbers count line breaks, CRLF counts the same as LF, and a multi-byte character counts as one column, so the numbers match what your editor shows. If neither source can locate the character, the tool says the position is unknown instead of printing a guess.
Is formatting my JSON the same as validating it?
No, and it is worth separating them. Validating answers one question: is this text valid JSON? Formatting assumes it is and re-indents it. This tool always parses before it prints anything, so a formatted result is proof that the input parsed. That is also why there is no "auto-fix" button: repairing a trailing comma silently would make this tool agree with text that the program you are sending it to will still reject.
What happens to duplicate keys?
The last one wins, because that is what JSON.parse does in every JavaScript engine — it is a language rule, not a setting. This tool does not pretend otherwise: when it finds duplicate keys it lists them, so you can decide whether the duplicate was intentional. If the earlier value was the one you wanted, formatting the file has just changed your data, and the warning is the only thing that tells you.
Why do large integer IDs change when I format them?
Because JavaScript has one numeric type: a 64-bit double, and doubles hold integers exactly only up to 9,007,199,254,740,991. An ID like 12345678901234567890 becomes 12345678901234567000 once parsed. This tool detects integers beyond that limit and warns you instead of quietly handing back a rounded value. For payloads built around large IDs, keep the file as text and use a tool that preserves number literals.
How large a file can I paste?
Up to 2,000,000 characters, which is roughly 2 MB of text. Above that the tool refuses instead of locking up your tab, because parsing and re-serialising run on the same thread that draws the page. Pastes over 300,000 characters get a working indicator first, so you can see that something is happening. If your file is bigger than the limit, split it — or use a command-line tool, which is the better instrument for a file that large anyway.

No data of any kind. This page contains no schema, no sample payload and no lookup table — every character it shows comes from what you pasted. It does not check your JSON against anything except the JSON grammar.