# JSON-LD diff: what changed between two versions

> Compare two JSON-LD blocks from the same page, before and after a theme or app change, and see which properties were added, removed or changed.

URL: https://clione.ai/tools/json-ld-diff/
Lang: en

A theme change, a new app or a migration can rewrite the [JSON-LD](/glossary/json-ld/) on your product pages without anything on the page looking different. The diff sets two versions of that markup side by side and lists what changed, path by path. It's for anyone who runs a store, or runs one for a client from an agency, and needs to know after touching something whether the [structured data](/glossary/structured-data/) on a [product page](/glossary/product-page/) still says the same thing. **It runs in your browser**: it doesn't download any page, and what you paste doesn't leave this one.

## When you need it

Whenever something you don't fully control writes the markup on your product pages. The usual cases:

- **You change or update your theme.** If the markup comes from the theme's template, a new version can bring different markup, with properties missing or in a different shape.
- **You install or remove an app that writes JSON-LD**, such as an SEO app or a reviews app. Two systems writing the same data is [field overwrite](/glossary/field-overwrite/) territory: the last one to write wins, and the previous value is lost without warning.
- **You migrate platforms** and keep your URLs: the page is the same, but another system generates the markup.
- **You change how the catalog is fed**, for example with a [PIM](/glossary/pim/) or a new sync, and want to check that the live page didn't lose anything.

What you're looking for in every case is [data drift](/glossary/data-drift/): the gap that opens between what was published correctly and what the page says later, because something changed it.

## How to get the two versions

1. **Save the before, before the change.** Open the live product page, look at its source ("View page source", or `view-source:` in front of the URL), copy everything and save it in a text file with the date. Pick a few pages that differ from each other: a simple product and one with variants.
2. **Make the change and repeat with the same URLs.**
3. **Paste the before into the first box and the after into the second.** The whole page source works, and so does just the JSON-LD, on either side: if the text starts with `<`, the diff reads every `application/ld+json` block in the HTML; if not, it reads it as JSON.
4. **Press Check.** "Load an example" fills both boxes with a fictitious product page before and after a theme change.

Always compare like with like. If JavaScript adds the markup when the page loads, it isn't in the source: in that case, copy the rendered page on both sides (developer tools, Elements, right-click the `<html>` element, Copy outerHTML). Comparing the source from before with the rendered page from after will give you differences that have nothing to do with the change.

## How to read the result

**The count line** says how many paths were added, removed and changed. With the example, "2 added, 2 removed, 1 changed." If there's no difference at all, the diff says so: the two are the same once key order and spacing are set aside.

**The table** has four columns: the result (Removed, Added or Changed), the path, the before value and the after value. Removed paths come first, then added ones and changed ones last, up to 400 rows. The removed ones are the ones most worth reading: a property that's gone is exactly what a theme change breaks without anything showing on the page.

**The path** says where each value lives. `offers.price` is the price inside the offer; `image[0]` is the first item in a list; `@graph[#product].offers.price` is the price of the `@graph` node whose [`@id` identifier](/glossary/id-json-ld/) is `#product`.

**The values** are shown as JSON: strings in quotes, numbers without. That's why a price that goes from `29.9` to `"29.90"` shows up as changed even though the figure is the same: what changed is the type. You decide whether it matters.

In the button's example, the fictitious product page loses `gtin13` and `offers.availability`, gains `brand.@type` and `brand.name`, and its `offers.price` goes from `"29.90"` to `"24.90"`. Three things you can't see on the page that change what a machine knows about the product.

### What isn't a difference

- **Key order and whitespace.** In JSON, an object is an unordered collection of name-value pairs, and whitespace around the syntax means nothing.[^rfc8259] The diff sorts the keys before comparing.
- **A node that moves within [`@graph`](/glossary/graph/) and keeps the same `@id`.** In JSON-LD, `@id` identifies the node.[^w3c-jsonld11] The diff names each node in a list by its `@id` when it has one, so moving it doesn't change its path.

### What shows up even when the meaning is the same

- **A list without `@id` that changes order.** JSON-LD treats lists as unordered unless told otherwise,[^w3c-jsonld11] but the diff compares by position: two images that swap places show up as two changes.
- **A property that changes shape.** If `brand` goes from `{"@type": "Brand", "name": "Calella"}` to `"Calella"`, you'll see `brand.@type` and `brand.name` removed and `brand` added.
- **One block more or one block fewer.** If one version has one JSON-LD block and the other has two, every path changes shape and almost everything shows up as removed and added. In that case, compare block by block, pasting only each block's JSON-LD.

## What to look at first

Not every path weighs the same. For a page that wants to appear in Google's [merchant listings](/glossary/merchant-listings/), these come first:

- **`offers.price` and `offers.priceCurrency`.** Both are required, the price has to be above zero and the currency is an ISO 4217 code.[^google-merchant-listing] A removed price, or one that changes when the price on the page hasn't, is the first thing to fix.
- **`offers.availability`.** It's recommended and takes a single value.[^google-merchant-listing] If it disappears, the page stops telling a machine whether the product is in stock.
- **The [GTIN](/glossary/gtin/) properties** (`gtin`, `gtin8`, `gtin12`, `gtin13`, `gtin14`). Google wants them in numeric form, not as a URL.[^google-merchant-listing] If a theme moves them to another property or changes their format, run them through the [GTIN validator](/tools/gtin-validator/).
- **`@id`.** A node that refers to another with nothing but its `@id` is a reference to a node defined elsewhere.[^w3c-jsonld11] If a node's `@id` changes, the references that pointed to the old one stop leading anywhere. In the diff it looks like this: inside `@graph`, the whole node shows up as removed under the old `@id` and added under the new one.
- **An extra [Product](/glossary/product-schema/).** If the after has two Product nodes for the same page, one from the theme and one from an app, both describe the same product, and Google asks that the markup be a true representation of the page.[^google-sd-policies] If they say different things, at least one of them isn't.

## What the diff can't tell you

- **What Google saw.** It compares what you paste. What Google found the last time it indexed the page is in the URL Inspection tool in [Search Console](/glossary/google-search-console/), which also shows the code of the crawled page.[^gsc-url-inspection]
- **Whether either version is correct.** An after identical to the before can be just as wrong. For what's missing against what Google asks for, there's the [structured data coverage](/tools/data-coverage/) tool; for what the markup says against what the shopper sees, [the guide to auditing a product page](/guides/audit-product-page-structured-data/); and the difference between checking markup and checking what's live is in [validate vs. verify](/comparisons/validate-vs-verify/).
- **What's on the other end of a reference.** The diff compares the structure of each version as written; it doesn't follow an `@id` to the node it points to.
- **Markup that isn't JSON-LD.** It doesn't read [microdata](/glossary/microdata/) or [RDFa](/glossary/rdfa/).

## What we tested

Tested on: browser and version, date.

| Pair of versions                                   | Expected result | The diff's result | Match? |
| -------------------------------------------------- | --------------- | ----------------- | ------ |
| Same keys, different order and whitespace          |                 |                   |        |
| Node moved in `@graph`, same `@id`                 |                 |                   |        |
| One property removed, one added, one value changed |                 |                   |        |
| Changed `@id`                                      |                 |                   |        |
| Real product page, before and after                |                 |                   |        |
