# @id in JSON-LD: What the Identifier Is and How to Choose It

> What the @id identifier in JSON-LD is, how it ties your schema nodes together, why it should not change and how to avoid two products where there is one.

URL: https://clione.ai/glossary/id-json-ld/
Lang: en

In the [JSON-LD](/glossary/json-ld/) block of many [product pages](/glossary/product-page/) there is a line like `"@id": "https://www.example.com/calella-linen-shirt#product"`. It looks like a link and almost never gets opened: **it is a name**. It is not the product code or its [SKU](/glossary/sku/), nor the `identifier` property of [Schema.org](/glossary/schema-org/), nor the list of profiles in [`sameAs`](/glossary/sameas/). It is the keyword the format itself uses to tell one node from another within the page's [structured data](/glossary/structured-data/). It matters to you because it is what ties the offer to the store that sells it, and what decides whether your theme's block and an app's block describe one product or two.

## How it works

The W3C's JSON-LD 1.1 specification defines `@id` as the keyword that **uniquely identifies the nodes described in the document**, with an IRI or with a blank node identifier.[^w3c-json-ld11] It also explains what for: to be able to refer to a node from outside, it is important that it has an identifier, and in linked data the ideal is that opening that identifier returns a description of the node.[^w3c-json-ld11]

An IRI looks like a URL, but it is not the same thing. The specification makes it clear: **a URL locates a resource on the web and an IRI identifies it**. It is good practice for it to be openable, though that is not always practical, and the specification gives as an example a `urn:uuid:` identifier that leads nowhere.[^w3c-json-ld11] On a store, the IRI is usually the page's URL with a fragment after it (`#product`, `#organization`, `#website`), which names each thing without inventing new addresses.

An `@id` can be written as a relative reference, for example `"../"`, and is then resolved against the document's base address. The specification warns about the cost: **if the document moves, the identifier moves with it**.[^w3c-json-ld11] That is why on a store they are written in full.

With a name, a node can already be cited. The specification calls an object that **carries only `@id`** a node reference: it describes nothing, it points to a node described elsewhere in the document.[^w3c-json-ld11] That is what `"seller": {"@id": "https://www.example.com/#organization"}` does inside an offer: it says who sells without repeating the company's data.

Without an `@id`, the node is valid but anonymous. JSON-LD does not require every node to be identified; the ones without an IRI are blank nodes, and if they carry a local identifier (it starts with `_:`), it only holds inside its own document: **from another document they cannot be cited**.[^w3c-json-ld11]

And what affects a [product page](/glossary/product-page/) the most: when JSON-LD is extracted from an HTML page as linked data, **all its `<script type="application/ld+json">` blocks are processed and merged into a single dataset**.[^w3c-json-ld11] When that set is flattened, all the properties of each node are gathered into one map.[^w3c-json-ld11] Two blocks that describe a node with the same `@id` end up as one node with the properties of both; two blocks without an `@id`, as two distinct nodes.

Google asks for it in its general guidelines. When several elements on a page stand apart and are better understood together, such as a recipe and its video, you should use `@id` on both; if you do not link them, **Search may not know they go together**, and in its example that stops it from showing the video as part of the recipe's rich result.[^google-sd-policies] The example is about recipes, but the rule sits in the general guidelines, the ones that apply to all [rich results](/glossary/rich-results/).[^google-sd-policies] [`@graph`](/glossary/graph/) gathers the nodes into one block; `@id` is what connects them.

## On a store

**Fictional example.** The product page of a Calella shirt, from an invented store, with two blocks: the one the theme brings and the one an app adds. Trimmed to the essentials:

```html
<!-- Theme block -->
<script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Product",
    "name": "Calella linen shirt, blue",
    "offers": { "@type": "Offer", "price": "39.90", "priceCurrency": "EUR" }
  }
</script>

<!-- App block -->
<script type="application/ld+json">
  {
    "@context": "https://schema.org",
    "@type": "Product",
    "@id": "https://www.example.com/calella-linen-shirt#product",
    "name": "Calella linen shirt, blue",
    "brand": { "@id": "https://www.example.com/#organization" }
  }
</script>
```

Read together, they are **two products**: an anonymous one with a price and another with a name of its own and a brand, but no price. If the theme also wrote `"@id": "https://www.example.com/calella-linen-shirt#product"`, they would be one, with both things.[^w3c-json-ld11] The case is not rare: the [Product](/glossary/product-schema/) block that Cornerstone, BigCommerce's default theme, ships in version 6.22.0, **carries no `@id`**.[^cornerstone-repo] On a page published with Clione, its Product node carries a stable `@id` and coexists with the theme's instead of duplicating it.

The other everyday use is for the [entity](/glossary/entity/) that repeats across the whole site. The store is the same on the home page, on every category and on every product page, so its [Organization](/glossary/organization-schema/) node should be named the same everywhere: `https://www.example.com/#organization`. Each offer cites it as the seller and the [WebSite](/glossary/website-schema/) node as the publisher, without describing it again.


Believing the `@id` has to be a page that exists, and writing it as the product page's bare URL. It does not have to open: the specification recommends it as good practice and allows identifiers that lead nowhere.[^w3c-json-ld11] What does matter is that it is **unique**. If the product and the page that describes it (a web page node) both use the product page's URL with no fragment, when read together they melt into a single node with two types, because all the properties of the same identifier are gathered into one map.[^w3c-json-ld11]


## How to check it

1. **Open the page source of a product page** and search for `@id`. Write down the one on each node: product, offer, organization, site. Any node without one is anonymous.[^w3c-json-ld11]
2. **Follow every reference.** Any object that carries only an `@id` has to point to a node that exists on the page with that same value, letter for letter.[^w3c-json-ld11]
3. **Count the product nodes.** If there are two, see whether they share an `@id`. If not, they are two products to anyone reading the page.[^w3c-json-ld11]
4. **Compare the organization's `@id` on three pages**: the home page, a category and a product page. It should be the same.
5. **Run the URL through the [Rich Results Test](/glossary/rich-results-test/)** and compare the items it detects with the nodes you counted; if two that should go together come out separately, an `@id` is missing to link them.[^google-sd-policies]

## Related concept: sameAs

Both serve to identify, and they look in opposite directions. **`@id` is the name you give a node inside your own markup**, and the JSON-LD format defines it.[^w3c-json-ld11] `sameAs` is a Schema.org property that points outward, to pages on other sites that say who that entity is: the [sameAs](/glossary/sameas/) entry explains which ones to include. A well-made organization node usually carries both: its `@id` so your own nodes can cite it, and its `sameAs` so the rest of the world can recognize it.

To keep going, the [structured data reading path](/learn/structured-data/) puts the rest of the terms in order, and the [`@graph`](/glossary/graph/) entry shows how several nodes are combined with their `@id`s in a single block.
