# Product Graph: How Product, Offer and Brand Link Together

> What a product page's product graph is: the Product, Offer, Organization, Brand and Review nodes linked by @id, and how to check that they are connected.

URL: https://clione.ai/glossary/product-graph/
Lang: en

A [product page](/glossary/product-page/) is not described by a single node of [structured data](/glossary/structured-data/). There is the product, but also the offer with its price, the store that sells it, the brand that makes it and the opinions of the people who have bought it. We call that set the product graph and, above all, **the links that join it**. It is not a term from any specification or a [Schema.org](/glossary/schema-org/) type: it is a way of looking at a page's markup as what it is, a network of related things. Nor is it Google's [Knowledge Graph](/glossary/knowledge-graph/), which is the search engine's database about the world. It matters because a product with a price but no seller, or with a brand written as loose text, says less than you think.

## How it works

The W3C's [JSON-LD](/glossary/json-ld/) specification describes its data as **a labeled, directed graph**: nodes are resources, and properties are the edges that join them.[^w3c-json-ld11] Each node can carry an identifier with `@id`, and another node can cite it with a reference, an object that carries only that `@id`.[^w3c-json-ld11] The specification distinguishes two ways of relating nodes: **[embedding](/glossary/embeddings/)** one inside a property of another, which creates a parent-child relationship, or **referencing** it by its identifier.[^w3c-json-ld11]

In a store, the nodes and their links come from the Schema.org vocabulary. These are the ones that form a product's graph:

| From                                 | Property                  | To                                                                                 | What the link says                                                                 |
| ------------------------------------ | ------------------------- | ---------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------- |
| [Product](/glossary/product-schema/) | `offers`                  | [Offer](/glossary/offer-schema/)                                                   | That an offer exists to sell or provide that product.[^schemaorg-product]          |
| Offer                                | `seller`                  | [Organization](/glossary/organization-schema/) or Person                           | Who sells, rents or provides the product.[^schemaorg-offer]                        |
| Product                              | `brand`                   | [Brand](/glossary/brand-schema/) or [Organization](/glossary/organization-schema/) | The brand or brands associated with the product.[^schemaorg-product]               |
| Product                              | `review`                  | [Review](/glossary/review-schema/)                                                 | A review of the product.[^schemaorg-product]                                       |
| Product                              | `aggregateRating`         | [AggregateRating](/glossary/aggregaterating/)                                      | The overall rating, computed from a set of reviews or ratings.[^schemaorg-product] |
| Offer                                | `hasMerchantReturnPolicy` | [MerchantReturnPolicy](/glossary/merchantreturnpolicy/)                            | The [return policy](/glossary/return-policy/) that applies.[^schemaorg-offer]      |
| Offer                                | `shippingDetails`         | [OfferShippingDetails](/glossary/offershippingdetails/)                            | The shipping conditions and options for that offer.[^schemaorg-offer]              |
| Product                              | `isVariantOf`             | [ProductGroup](/glossary/productgroup/)                                            | The base product this variant derives from.[^schemaorg-product]                    |

Two nodes being on the same page does not join them. Google explains that it understands multiple elements on a page whether they are nested, with a main element and the others grouped under it, or separate; and for those better understood together it asks you to **use `@id` on both** to indicate the relationship.[^google-sd-policies] That is why, in a well-built graph, what only makes sense inside the product is nested (its offer, its reviews), and what repeats across the whole site, like the store, is described once with a stable `@id` and cited from wherever it is needed.

### What Google does with it

Google has two features for products: product snippets, for pages where you cannot buy directly, and [merchant listings](/glossary/merchant-listings/), for pages where the customer can buy the product from you. If a page carries the required properties for merchant listings, it can also be eligible for product snippets, and **the more properties you add, the more enhancements it can be eligible for**.[^google-product] Google also recommends that the store's return policy and its loyalty program go in a nested Organization node.[^google-product] In other words: part of the graph does not hang off the product, but off the store.

## In a store

A **fictional example**: a lamp's product page in an invented store, with the complete graph cut down to the essentials.

```json
{
  "@context": "https://schema.org",
  "@graph": [
    {
      "@type": "Organization",
      "@id": "https://www.example.com/#organization",
      "name": "Arnes Lighting",
      "url": "https://www.example.com/"
    },
    {
      "@type": "Product",
      "@id": "https://www.example.com/oria-table-lamp#product",
      "name": "Oria table lamp",
      "brand": { "@type": "Brand", "name": "Oria Studio" },
      "aggregateRating": {
        "@type": "AggregateRating",
        "ratingValue": "4.6",
        "reviewCount": "38"
      },
      "offers": {
        "@type": "Offer",
        "price": "89.00",
        "priceCurrency": "USD",
        "availability": "https://schema.org/InStock",
        "seller": { "@id": "https://www.example.com/#organization" }
      }
    }
  ]
}
```

Drawn out, the graph looks like this:

```text
Product (#product)
  +-- brand ----------> Brand "Oria Studio"
  +-- aggregateRating -> AggregateRating 4.6 (38 reviews)
  +-- offers ---------> Offer 89.00 USD
                          +-- seller --> Organization (#organization)
```

It reads top to bottom. The product has its `@id`, so another page, or the same page, can cite it. The brand, the rating and the offer are nested because they only make sense inside this product. The store, on the other hand, is described once, outside the product, and the offer cites it by its `@id`: that link is what says **who sells**. Take out the `seller` and the markup no longer says who sells; change one letter of the `@id` and the reference points to a node that does not exist. With the [`@id` identifier](/glossary/id-json-ld/) well chosen, the same store node serves all the product pages.

A page published with Clione carries a single `@graph` with Organization, [WebSite](/glossary/website-schema/), BreadcrumbList and [Product](/glossary/product-schema/), with one offer per product, and its Product node has a stable `@id` that coexists with the theme's own instead of duplicating it.


Believing that, because the product is on your site, the markup already says you sell it. It does not: the JSON-LD specification treats each relationship as a property that has to be written,[^w3c-json-ld11] and the one that says who sells an offer is `seller`.[^schemaorg-offer] A Product and an Organization on the same page, without that reference, are two unrelated nodes, and Google warns that you should link with `@id` what is better understood together.[^google-sd-policies]


## How to check it

1. **Open a product page's source code and find the Product node.** Note its `@id`; if it has none, the product is anonymous and nobody can cite it.[^w3c-json-ld11]
2. **Follow `offers`.** There has to be an Offer, and its `seller` has to point to an `@id` that exists on the page, letter for letter.
3. **Look at `brand`.** The brand should be a Brand or Organization node with its name,[^schemaorg-product] and match the brand shown on the page.
4. **Check that the reviews and rating in the markup are visible on the page.** Google asks you not to mark up what the visitor does not see.[^google-sd-policies]
5. **Draw it on paper.** One box per node and one arrow per property. Any node with no arrow in or out is an island.

## Related concept: @graph

The [`@graph`](/glossary/graph/) is a JSON-LD keyword: the list that gathers several nodes in one block, under a single context. The product graph is something else: **the network of links around a product, however it is written**. You can write a complete product graph without `@graph`, with all the nodes nested inside the Product, and you can have a `@graph` with four nodes that form no graph, because the specification allows a top-level `@graph` to contain nodes that are not connected.[^w3c-json-ld11] **The `@graph` says which nodes exist; the product graph, how they relate.**

To go further, the guide to [auditing a product page's structured data](/guides/audit-product-page-structured-data/) applies these checks step by step, and the [structured data reading path](/learn/structured-data/) orders the rest of the types.
