# JSON Formatter & Validator — AO tool

> Tidy, minify and check JSON — and when it is broken, be told exactly where and why. Runs entirely client-side: no upload, no server, no file limits, no sign-up.

Human page: https://abstractobjective.dev/tools/json-format/
Status: live · Category: text

## Input and output
- In: JSON input typed or pasted into the page
- Out: Result, copyable and downloadable

## Programmatic use (the AI-facing twin)
All computation happens locally in the page context.

- `window.AOJson.process(text, {mode, indent, sortKeys}) -> {ok, output, error, stats}`
  Format or minify JSON. mode: format|minify. On failure, error carries message, line, column and sourceLine. stats carries keys, nodes, depth, rootType and byte sizes.
- `window.AOJson.findError(text) -> {message, line, column, sourceLine, index} | null`
  Locate the first structural problem in JSON text, with a human-readable explanation. Returns null when the text is well-formed.
- `window.AOJson.format(text, indent=2) -> string`
  Pretty-print JSON, returning an empty string if the input is invalid.
- `window.AOJson.minify(text) -> string`
  Minify JSON, returning an empty string if the input is invalid.

## Notes
- Parsing uses the browser's native JSON.parse, which is fast and exactly correct. Error LOCATION is AO's own scanner, because the engines disagree: V8 reports a character offset, SpiderMonkey a line, and JavaScriptCore neither.
- Errors name the actual mistake — a trailing comma, a single-quoted string, a Python None or True — rather than "Unexpected token".
- Nothing you paste is transmitted. This matters here: JSON pasted into a formatter is very often an API response containing tokens, keys or personal data.

## Properties
- Privacy: files never leave the browser tab.
- Limits: none imposed by us; the practical ceiling is your device's memory.
- Cost model: client-side compute — free without caps, sustainably.

---

## Errors that tell you something

Most JSON formatters, when your input is broken, say **"Unexpected token }"** and leave you to find it. That is not the formatter being lazy — it is repeating whatever the browser's parser said, and the browsers disagree with each other about how much to tell you. Chrome gives a character offset. Firefox gives a line. Safari gives neither.

So this page does the locating itself. It runs its own scan over your text and reports the **line and column**, prints the offending line with a caret underneath it, and — where it can tell — names the actual mistake rather than the symptom:

- *A trailing comma is not allowed in JSON.*
- *JSON strings use double quotes, not single quotes.*
- *JSON has no None — write null.*
- *JSON booleans are lowercase — write true.*
- *A string was left open at the end of the line.*
- *Object keys must be double-quoted strings.*

Those last few are worth calling out. Half the broken JSON in the world is broken because it is not JSON at all — it is a Python dictionary, or a JavaScript object literal, pasted in by someone who reasonably expected them to be the same thing. Being told *that* is far more useful than being told a token was unexpected.

The parsing itself still uses the browser's own `JSON.parse`, which is fast and exactly correct. Only the fault-finding is ours.

## Why it matters that this stays local

Think about what people actually paste into a JSON formatter: an API response they are debugging. Those routinely contain access tokens, session identifiers, internal URLs, customer records, email addresses.

Pasting that into a website means sending all of it to someone else's server, to have whitespace added. The computation is trivial and your browser can do it instantly — there has never been a technical reason to transmit it. Nothing you paste here leaves this tab, and you can confirm that in the network panel.

## What else it does

**Format** makes JSON readable with two spaces, four spaces or tabs. **Minify** strips every unnecessary byte for shipping — and tells you how many bytes that saved. **Sort keys alphabetically** puts object keys in a deterministic order, which is the quickest way to make two structurally identical configurations actually diff cleanly.

Alongside the result you get a quick shape report: how many keys, how deeply nested, what the root type is, and the size before and after. For a large unfamiliar payload, the depth and key count often tell you more at a glance than the content does.
