API response diff

Paste two JSON API responses and see only what actually changed — request ids, timestamps and generated UUIDs can be filtered out, and reordered arrays paired by id.

Try:
Diff

Compare two API responses without the noise

Two calls to the same endpoint almost never return byte-identical JSON: a request id, a generatedAt stamp or a freshly minted UUID changes on every hit, and a plain text diff buries the one field you actually care about. This tool compares the two responses structurally and lets you drop the volatile parts first, so what is left is the real behavioural change.

It is built for the everyday API jobs: checking a staging deploy against production, reviewing a version bump (/v1 vs /v2), confirming a cache or pagination fix changed nothing else, and turning "these look different" into a precise list of paths.

Everything runs locally in your browser through WebAssembly — the two responses are never uploaded anywhere.

Worked example

First response (baseline)

{"requestId":"req-8f21","generatedAt":"2026-08-15T09:14:02Z","data":{"total":2,"status":"ok"}}

Second response (candidate)

{"requestId":"req-c07d","generatedAt":"2026-08-16T11:02:47Z","data":{"total":3,"status":"ok"}}

With Ignore fields set to requestId, generatedAt, the result is:

{
  "equal": false,
  "counts": {
    "added": 0,
    "removed": 0,
    "changed": 1,
    "type_changed": 0,
    "ignored": 2
  },
  "truncated": false,
  "notes": [],
  "ignored_paths": [
    "$.requestId",
    "$.generatedAt"
  ],
  "changes": [
    {
      "path": "$.data.total",
      "kind": "changed",
      "old": 2,
      "new": 3
    }
  ]
}

One real change ($.data.total went from 2 to 3), two fields deliberately skipped — and equal tells you at a glance whether anything meaningful moved.

Switch Output to Readable summary for a one-line-per-change view (~ $.data.total: 2 -> 3), or to RFC 6902 JSON Patch to get [{"op":"replace","path":"/data/total","value":3}] you can feed to a patch library.

Ways to say "ignore this"

Skipped locations are counted and listed under ignored_paths, so a filter can never hide a change silently.

Arrays: index, key, or set

Collections are where JSON diffs usually go wrong. Three matching modes cover the common cases:

If an array cannot be matched by key (elements are not objects, or the key repeats), the comparison falls back to index matching and says so in notes rather than failing.

Limits and edge cases

FAQ

How is this different from a plain JSON diff?

A plain diff reports every difference, including the request ids and timestamps that change on every call. This tool is built around suppressing that churn: ignore lists by name, path or glob, value-shape filters for timestamps and UUIDs, a numeric tolerance for rounding drift, and array matching by key so a reordered list is not reported as a rewrite.

Do the ignored fields still show up somewhere?

Yes. Every skipped location is counted in counts.ignored and listed in ignored_paths (and the summary output prints the ignored count). Nothing is dropped invisibly, so you can double-check that a filter matched what you intended — and only what you intended.

Why did my `ignore` pattern not match?

A pattern that contains a dot or a bracket is treated as an anchored path from the root, so data.token does not match $.result.data.token. Use a bare name (token), a ** prefix ($.**.token), or a wildcard segment ($.*.data.token). A bare name always matches at any depth, which is usually what you want for volatile fields.

Can I compare responses whose numbers differ slightly?

Set a numeric tolerance. With 0.01, a price of 10.00 and 10.005 compare equal while 10.5 is still reported. This is the usual fix for floating-point rounding, currency conversion and aggregation drift between two backends.

What do the change kinds mean?

added is present only in the second response, removed only in the first, changed is present in both with a different value of the same type, and type_changed means the JSON type itself moved (a number became a string, a value became null). Turn on Compare across types if "5" and 5 should count as equal.

Is the JSON Patch output applicable to the first response?

It is a standard RFC 6902 array of add / remove / replace operations built from the reported changes, so applying it to the first response reproduces the second — except for anything you deliberately ignored, which is left untouched by design. Patch output requires index array matching.

Developer & Automation Access

Run it from the terminal

Same engine as this page, headless — via the gizza CLI:

gizza tool api-response-diff '{"requestId": "req-8f21", "data": {"total": 2, "status": "ok"}}' 'right={"requestId": "req-c07d", "data": {"total": 3, "status": "ok"}}'

New to the CLI? Get gizza →

Open it by URL

Pre-fill and auto-run this tool with query parameters — the names match the API/CLI:

https://gizza.ai/tools/api-response-diff/?left=%7B%22requestId%22%3A%20%22req-8f21%22%2C%20%22data%22%3A%20%7B%22total%22%3A%202%2C%20%22status%22%3A%20%22ok%22%7D%7D&right=%7B%22requestId%22%3A%20%22req-c07d%22%2C%20%22data%22%3A%20%7B%22total%22%3A%203%2C%20%22status%22%3A%20%22ok%22%7D%7D&ignore=requestId%2C%20generatedAt%2C%20%24.data.token%2C%20%2A_at&ignore_timestamps=true&ignore_uuids=true&array_match=index&array_key=id&numeric_tolerance=0.01&ignore_case=true&trim_strings=true&null_equals_missing=true&coerce_types=true&output=report&indent=2

Machine-readable descriptor: tool.json — title + parameters JSON Schema for agents.