# Structured data coverage of a product page

> Paste your product page's JSON-LD and see which of the Product and Offer properties Google asks for it has and which are missing. A free tool.

URL: https://clione.ai/tools/data-coverage/
Lang: en

This tool measures the [structured data](/glossary/structured-data/) coverage of a [product page](/glossary/product-page/): how many of the [Product](/glossary/product-schema/) and [Offer](/glossary/offer-schema/) properties Google lists for [merchant listings](/glossary/merchant-listings/) its [JSON-LD](/glossary/json-ld/) carries, and which ones are missing. It's for anyone who runs a store, or runs one for a client from an agency, and wants to know in a minute whether a page's markup has the minimum and how much of the recommended set. **It counts presence, not correctness**: it tells you whether a property has a value, not whether that value is true.

It all happens in your browser. The tool doesn't download your store or send what you paste anywhere: it reads the text you give it and nothing else.

## How to use it

1. **Open the live product page**, not your platform's admin, and look at its source: "View page source" in the right-click menu, or `view-source:` in front of the URL. Select all and copy it.
2. **Paste it into the box.** The whole page source works, and so does just the contents of one JSON-LD block. If what you paste starts with `<`, the tool treats it as HTML and reads every `<script type="application/ld+json">` it finds; if not, it treats it as a single JSON block.
3. **Press Check.** If you'd like to see a result first, "Load an example" fills the box with a fictitious product page: a linen shirt with the required properties, the brand, the [GTIN](/glossary/gtin/) and the availability. It comes out at 5 of 5 required and 3 of 21 recommended.
4. **Read one block per product.** If the page has several Product nodes, each gets its own count and its own table, up to twenty.

If the source has no JSON-LD block and other tools do show structured data for your page, JavaScript is most likely adding it when the page loads. In that case, copy the rendered page (developer tools, Elements, right-click the `<html>` element, Copy outerHTML) and paste that here. What changes between the two versions, and why it matters to a [crawler](/glossary/web-crawler/), is in the guide [what an AI crawler sees in your store](/guides/what-an-ai-crawler-sees/) and in the [What an agent sees](/tools/what-an-agent-sees/) tool.

## How to read the result

**Each product's heading** is "Product 1", "Product 2" and so on, followed by the node's `name`. The tool looks for Product nodes anywhere in what you paste: on their own, inside an [`@graph`](/glossary/graph/), or as variants inside a [ProductGroup](/glossary/productgroup/) with `hasVariant`, which is how Google asks you to group [product variants](/glossary/product-variants/).[^google-product-variants] If a property points to another node by its [`@id` identifier](/glossary/id-json-ld/), for example `"offers": {"@id": "#offer"}`, the tool follows the reference to the node that defines it, as long as that node is in what you pasted.

**The count line** reads "Required: 5 of 5. Recommended: 3 of 21.", or whatever your numbers are. There are five required properties: three on the product and two on the offer. There are twenty-one recommended ones, and the full list is in the reference table under the tool, "What the check looks for".

**The table** has one row per property, with its level and a "Found" column. A "No" on a required property is marked as a failure; on a recommended one, as a warning. A property counts as present if it has any value at all: an empty string (`""`), a `null` or an empty list count as missing. That's what happens when a theme prints `"gtin13": ""` because the product's field was never filled in.

**Messages without a table** tell you why there's no count: there's no JSON-LD in what you pasted; there is JSON-LD but no Product node, and without one nothing on the page describes the product to a machine; or a block can't be read, and the tool shows you the JSON parser's error, which is usually an extra comma or an unclosed quote. The other blocks are still read.

### Two warnings that sit above the table

There are two cases where an offer that is present still doesn't work for merchant listings, and the tool flags each with its own warning:

- **The offer is an [AggregateOffer](/glossary/aggregateoffer/).** [Schema.org](/glossary/schema-org/) defines it for a product with several offers, for example the same pair of shoes sold by different merchants.[^schemaorg-aggregateoffer] Product snippets accept an Offer or an AggregateOffer, but **merchant listings require an Offer**, because whoever marks up the page has to be the one selling the product.[^google-merchant-listing] An AggregateOffer usually carries `lowPrice` and `highPrice` instead of `price`, so the price row also comes out as "No".
- **The price is missing or zero.** Unlike product snippets, merchant listings require **a price above zero**.[^google-merchant-listing] The tool warns you if the price isn't there, if it's zero or if it isn't a number, like a price written with its currency sign inside it. Schema.org wants the currency separately, in `priceCurrency`, and a period as the decimal separator.[^schemaorg-offer] The tool accepts a decimal comma so you don't get a warning you don't need, but the correct form is `"29.90"`.

If `offers` is a list of offers, the tool only looks at the first one.

## The Product and Offer properties it counts

The list comes from Google's documentation for merchant listings, which separates what is required from what is recommended.[^google-merchant-listing]

| Node    | Required                  | Recommended, as the tool counts them                                                                                                                                                                                                |
| ------- | ------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| Product | `name`, `image`, `offers` | `description`, `brand`, `gtin` (or `gtin8`, `gtin12`, `gtin13`, `gtin14`, `isbn`), `mpn`, `sku`, `category`, `color`, `size`, `material`, `pattern`, `audience`, `aggregateRating`, `review`, `inProductGroupWithID`, `isVariantOf` |
| Offer   | `price`, `priceCurrency`  | `availability`, `itemCondition`, `hasMerchantReturnPolicy`, `shippingDetails`, `priceValidUntil`, `url`                                                                                                                             |

Three details from the same source. The price and the currency can go inside `priceSpecification` instead of directly on the offer, and the tool accepts both forms; if they're in both places, Google uses `offers.price`. The currency is a three-letter ISO 4217 code.[^google-merchant-listing] For product snippets Google only recommends it, but for merchant listings it's required.[^google-product-snippet] And for the brand, Google asks for its name, `brand.name`, and only one; the tool accepts the `brand` row with any value.[^google-merchant-listing]

Some of Google's recommended properties the tool deliberately leaves out, because they only apply to some catalogs and would pull down every store's score:

- **`hasAdultConsideration`**, for adult products. Note: **if you sell products of that kind, Google says you must use it** to label them, even though it's listed as recommended.[^google-merchant-listing] The tool doesn't check for it.
- **`hasCertification`**, for certifications such as energy efficiency labels.[^google-merchant-listing]
- **`subjectOf`**, for a 3D model of the product.[^google-merchant-listing]

It also leaves out `validFrom` and `validThrough`, the dates a price starts and ends, which Google also recommends on the offer.[^google-merchant-listing]

## Recommended is not a to-do list

Google asks that structured data be a true representation of the page's content, and that you don't mark up what the reader can't see.[^google-sd-policies] That decides how to read the recommended column: **fill in a recommended property if the page shows it**. If your page shows no ratings, the "No" next to `aggregateRating` is the right answer, and the fix is not to invent an average for the markup. The same goes for the size of a product that doesn't come in sizes.

What Google does say is that the more recommended properties you provide, the higher the quality of the result for the user.[^google-sd-policies] So the column is for finding what your page already shows and the markup doesn't say: a GTIN that's in your admin and the theme doesn't publish, an availability the page displays and the offer doesn't carry, a [return policy](/glossary/return-policy/) that exists but isn't marked up.

## What this tool can't tell you

- **Whether the values are true.** A price from two sales ago counts as present. Comparing the markup with what the shopper sees, property by property, is the step no tool does, and it's explained in [the guide to auditing a product page](/guides/audit-product-page-structured-data/).
- **Whether each value's format is valid.** It doesn't check dates, currency codes, availability values or check digits. For GTINs there's the [GTIN validator](/tools/gtin-validator/).
- **What Google saw.** The tool reads what you paste. What Google found the last time it indexed the page, including [rich results](/glossary/rich-results/), 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]
- **What a variant inherits.** Google lets you put the properties all variants share, such as the brand or the reviews, on the ProductGroup.[^google-product-variants] The tool counts each Product separately, so a variant without its own `brand` comes out as "No" even if the group has one.
- **Markup that isn't JSON-LD.** It doesn't read [microdata](/glossary/microdata/) or [RDFa](/glossary/rdfa/).
- **Whether Google will show it.** Having the required properties makes a page eligible for a rich result, not guaranteed one: Google doesn't promise it even when the markup is correct.[^google-sd-policies] The difference between markup that is valid and markup that is live is in [validate vs. verify](/comparisons/validate-vs-verify/).

If a page's coverage dropped after a theme change or a new app, the [JSON-LD diff](/tools/json-ld-diff/) shows you which property disappeared.

## What we tested

Tested on: three product pages, the platform and theme of each, date.

| Page | Platform and theme | Required | Recommended | Warnings | [Rich Results Test](/glossary/rich-results-test/) |
| ---- | ------------------ | -------- | ----------- | -------- | ------------------------------------------------- |
| 1    |                    |          |             |          |                                                   |
| 2    |                    |          |             |          |                                                   |
| 3    |                    |          |             |          |                                                   |
