About JSON Diff
JSON Diff compares two JSON documents in your browser. There is no backend, no account and no upload step — the page is a set of static files, and the comparison runs on your own machine.
Why this tool exists
Comparing two API responses is a routine task, and the payloads involved are rarely the ones you would paste into a random website. They carry access tokens, customer records, internal identifiers or production configuration.
Most online diff tools now describe themselves as private. That claim is impossible to verify from the outside: a tool that uploads your document and a tool that does not look exactly the same until you open the network panel. JSON Diff is built so the question does not arise. There is no API endpoint to post to, no session, and no server-side component that could receive the data even if it wanted to.
How it works
Every stage of the pipeline runs in the browser, and the heavier stages are moved off the main thread so the interface stays responsive.
In one sentence: the JSON you paste is parsed, compared and rendered locally, and only two things ever leave the page — a request log entry for the page itself, and a share link if you explicitly create one.
Layers. A recursive diff engine walks both documents and pairs keys by name; a Web Worker runs that engine when the document is large; the interface is plain ES modules with no framework; history and favourites live in IndexedDB on your device.
| Stage | What it does | Runs in |
|---|---|---|
| Parsing | Reads each document and reports the line and column of the first syntax error. | Browser memory (Web Worker for large input) |
| Comparison | Walks both trees recursively and classifies every difference. | Browser memory (Web Worker for large input) |
| Rendering | Builds the line-based diff, the structure tree and the minimap. | Main thread |
| Persistence | Keeps history and favourites between visits. | IndexedDB on your device |
| Sharing | Compresses the comparison into the URL fragment when you ask for a share link. | Browser memory |
Design decisions worth knowing
A few choices shape how the tool behaves, and they are the reason its output can differ from a generic diff.
- Two documents that hold the same data are reported as identical. Reindenting, minifying or reordering keys does not count as a change; key order is ignored by default.
-
A type change is its own category. When
"1"becomes1, or an object becomes an array, the entry is counted separately from an ordinary value change, because the two rarely have the same consequences. -
Array elements can be paired by a key field. When an
array has no meaningful order — a list of records with an
id, for example — the comparison can match elements by that field instead of by position, so inserting one record does not make every following element look changed. -
Share links stay in the fragment. The compressed
comparison is stored after the
#, the part of a URL that browsers never send to a server.
What it deliberately does not do
- No upload, no backend API and no server-side processing.
- No account, sign-up, quota or session to be logged.
- No analytics, no advertising, no third-party scripts and no external font or CDN. Every request the page makes is to its own domain.
- No cloud sync: history and favourites stay on the device they were created on.
The absence of third-party requests is easy to check — open the network panel and reload. The storage behaviour is documented in detail on the privacy page.
Maintenance
The project is versioned, and every release is recorded on the changelog page with its date. The version the running application reports — visible under Settings → Runtime info — matches the newest entry there, so it is possible to tell which build a browser is actually using.
Because the site is static, a release is simply a new set of files. The comparison engine, the interface and the copy are all maintained together, which is why a change in behaviour and a change in wording tend to arrive in the same version.