Paste a whole array response, or many separate JSON records, and compare them against each other. Finds the fields that are only sometimes there, the ones that change type between records, the ones that are null in every sample, and the same field living under two different names.
Paste a JSON array of objects — a list endpoint's response works as-is — and every element is treated as one record. Or paste separate JSON documents divided by a line containing just -----, optionally labelling each with ### name so the results are easier to read.
Every JSON diff tool takes exactly two documents: a left and a right. That's the right shape for "what changed between v1 and v2" — but it's the wrong shape for the question you actually have when you're staring at forty records from the same endpoint. Is email guaranteed, or does it only show up on some users? Is age a number or a string? Which of these fields can I safely mark non-nullable? Answering that with a pairwise diff means running it against every combination, which is 780 comparisons for forty records, and then holding the results in your head.
The common workaround is a shell loop that fetches N responses and diffs each one against the first — which finds fields that record 1 happens to have, and quietly misses any field that only appears in records 7 and 23. This tool looks at all of them together in one pass instead, which is the only way some of these problems are visible at all.
Optional fields — present in some records and absent in others, with the count and which records are missing it. This is the single most common cause of a client crashing on real data after working fine against a sample.
Type drift — the same field arriving as a number in most records and a string in a few, or an object in some and an array in others. Typed clients break on exactly this, and it's invisible when you inspect one record at a time.
Always-null fields — a field that exists in the payload but is null in every single record you've supplied. You can't infer a type from it, and it's worth knowing your sample simply doesn't cover it rather than assuming the field is a string.
Missing versus present-but-null — a field that's sometimes absent and sometimes explicitly null. These are two different states, they usually need different handling in a client, and mixing them is often unintentional on the server side.
Naming drift — two similar field names, like user_id and userId, that never appear in the same record. That pattern almost always means one field being serialized two different ways, usually because two code paths or two service versions produce the response. Similar names that do coexist in a record are left alone, since those are genuinely separate fields.
Tools that generate TypeScript interfaces or JSON Schema from several samples do read all of them — but their job is to produce something that compiles against every sample, so they resolve inconsistency silently. A field missing from some records becomes email?: string. A field that's sometimes a string and sometimes a number becomes a union. That's correct behaviour for code generation and precisely wrong for auditing, because the thing you wanted to see is the thing that got absorbed into the output.
This tool does the opposite: it never normalizes, it just tells you what varies and by how much. Run it before you generate types, then generate them knowing which optionals are real and which are gaps in your sample.
No. Parsing and comparison run in your browser using the built-in JSON parser, with no libraries loaded and no requests made. That matters here more than on most tools, since API responses routinely contain customer names, email addresses, and internal identifiers — you can check a production payload without it leaving the machine, which you can confirm in your browser's Network tab.
Nested objects are flattened to dot paths, so meta.region is tracked as its own field and compared across records like any other. An array of objects collapses to a single items[] path rather than one path per element, so a record with a hundred line items produces one entry, not a hundred. Nesting is followed six levels deep, which covers essentially every real API response.
Two hundred records with thirty fields each analyzes in well under a tenth of a second, and there's no hard cap — the practical limit is your browser's memory. Two records is the minimum for the comparison to mean anything; with one, there's nothing to compare it against and the tool says so rather than reporting a clean result.
No. Records that fail to parse are listed separately with their error, and the comparison runs on the rest. That's deliberate — a malformed sample shouldn't block the audit of the twenty good ones. Just keep in mind that a field's "present in 19 of 19" count only covers the records that parsed.
No, and it doesn't grade them for you. Plenty of optional fields are optional by design and documented that way. The report is a list of things that vary, so you can confirm each is intentional — the value is in noticing the one you didn't know about, not in driving the list to zero. If a field turns out to be genuinely optional, that's a fact worth encoding in your schema rather than discovering again later.