> ## Documentation Index
> Fetch the complete documentation index at: https://cloro.dev/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Google AI Mode product results schema

> Get the merchant offers behind a Google AI Mode product with its productResultToken: direct URLs, prices, installments, stock, and delivery badges.

Product results are the merchant offers behind a product in a [Google AI Mode](/docs/api-reference/endpoint/monitor-aimode) response: merchant URL, price, installment terms, and stock, delivery and returns badges. [Shopping cards](/docs/api-reference/endpoint/aimode/shopping-cards) and [inline products](/docs/api-reference/endpoint/aimode/inline-products) carry only a headline price and a link to Google's product viewer. Each one that links to the viewer also has a `productResultToken`, with no flag and at no extra cost:

```json theme={null}
{
  "title": "Sony WH-CH720N Noise Cancelling Headphones",
  "position": 1,
  "price": { "value": 149.99, "currency": "$", "raw": "$149.99" },
  "store": "Amazon",
  "productResultToken": "nuzK-QgAV8BqrZdwQJYZopzdoFhpvKr-N2_YDZevwzg"
}
```

Send the token to [`POST /v1/monitor/google/product`](/docs/api-reference/endpoint/google/product) within five minutes to get the offers inside the viewer. That page has the request, the price, the token rules and the errors.

<Frame caption="Product viewer opened from an AI Mode product">
  <img src="https://mintcdn.com/cloro/xw1u3hOrJqeOEWTG/images/aimode/product-results.webp?fit=max&auto=format&n=xw1u3hOrJqeOEWTG&q=85&s=0f8d89800040f213be8d59aefe12e3a9" alt="Product viewer opened from an AI Mode product" width="1400" height="807" data-path="images/aimode/product-results.webp" />
</Frame>

## Join the product blocks

Shopping cards and inline products have a `productDocid`, which is Google's ID for the product. When a card and an inline product in one response show the same product, the two have the same `productDocid`. The value is not unique in a block: when Google shows a product in two card groups, the two cards have the same `productDocid`, so one inline product can match more than one card.

A product result has the `productDocid` of the card or inline product that it came from. Use it to match the result of a product request to the entry whose token you sent.

Google can give the same product a different `productDocid` in another response. Use it to join blocks in one response, not to track a product over time. A card or inline product has no `productDocid` when the link from Google has none.

## Product result structure

Each entry describes one product cluster and its merchant offers.

| Field | Type | Description |
| - | - | - |
| `title` | string | Product cluster title, as Google displayed it |
| `stores` | array | Merchant offers. See [store structure](#store-structure) |
| `aboutTheProduct` | object | `description` (Google's prose blurb) and `features` (bullets, when shown) |
| `specifications` | object | Spec tables grouped by category. See [specifications](#specifications) |
| `images` | array | `mainUrl` and `thumbnailUrl` per image, often identical |

Only `title` is guaranteed (Google Search entries also always carry `stores`) — anything Google's panel omits is left out of the object rather than sent as `null`. Panels can also carry `rating`, `reviews`, `variants`, `relatedProducts` and `userReviews`, emitted under those names when present, though most carry none of them.

### Specifications

A category name mapped to a flat set of spec key/value pairs:

```json theme={null}
{
  "specifications": {
    "general": {
      "Brand": "Sennheiser",
      "Noise cancellation": "Yes"
    }
  }
}
```

<Warning>
  Category names and spec keys arrive in the **response language** — a `country: "MX"` request returns `{"general": {"Marca": "Sennheiser"}}`. Iterate the object; don't read a hard-coded key like `specifications.general.Brand`.
</Warning>

### Store structure

| Field | Type | Description |
| - | - | - |
| `name` | string | Merchant name (e.g. `"Amazon"`) |
| `link` | string | Merchant product URL, passed through from Google verbatim |
| `price` | object | See [price shape](#price-shape). Omitted entirely when the displayed text can't be parsed |
| `installments` | string | Installment terms as displayed (e.g. `"for 24 mo, $0 now, $798.96 total"`) |
| `description` | string | Merchant's listing title, naming the exact SKU sold (e.g. `"iPhone 17 256GB White - Apple"`) — unlike `title`, which names the product overall |
| `buyingOptions` | array | Merchant badges in display order — stock status, rating, delivery promise, returns window. Google varies these per merchant and locale, so they stay an unparsed list of strings |
| `logo` | string | Merchant logo URL |
| `shipping` | string | Shipping cost or promise as displayed |
| `condition` | string | Item condition (e.g. `"New"`, `"Refurbished"`) |
| `rating` | number | Merchant rating |
| `reviews` | string | Merchant review count, abbreviated (e.g. `"384"`, `"2.3k"`) |
| `redirectLink` | string | Google's `/goto` redirect for `link`, when Google served one. See [redirect links](/docs/api-reference/endpoint/google/resolve-goto) |

Expect the first six on most offers and the rest only occasionally. Everything beyond `name` is optional and omitted when absent — Google shows different combinations per merchant, so an "Out of stock" listing may have no price or link at all.

<Warning>
  `link` is not validated against the cluster. Google occasionally serves a merchant URL for an unrelated SKU, so an offer's link can point at a different product than its `description` names. Verify against `description` if link correctness matters.
</Warning>

### Price shape

| Field | Type | Description |
| - | - | - |
| `value` | number | Parsed numeric price; always present when `price` is emitted. On installment offers this is the monthly payment |
| `currency` | string | ISO 4217 code (e.g. `"USD"`, `"BRL"`, `"MXN"`, `"AED"`, `"JPY"`), or the displayed token verbatim when cloro can't map it. See [currency codes](#currency-codes) |
| `raw` | string | Visible price text verbatim (e.g. `"$149.99"`) |

<Warning>
  `currency` here is an **ISO code** (`"USD"`), while [shopping cards](/docs/api-reference/endpoint/aimode/shopping-cards#price-and-oldprice) carry the symbol as displayed (`"$"`) and [inline products](/docs/api-reference/endpoint/aimode/inline-products#price-and-oldprice) carry either, depending on the data Google supplies. Normalize before comparing across surfaces.
</Warning>

### Currency codes

cloro maps the currency token Google displays next to the price to its ISO 4217 code. Multi-character and word tokens are recognized, so `"R$ 5.597,99"` returns `"BRL"`, `"MXN 19,499.00"` returns `"MXN"`, and `"3,399.00 د.إ"` returns `"AED"`. Yen written as `¥`, `￥` or `円` returns `"JPY"`.

A bare `$` doesn't name a market on its own, because Google writes US, Canadian and Australian offers the same way. On [AI Mode](/docs/api-reference/endpoint/aimode/product-results), cloro resolves a bare `$` from the request `country`: `CA` returns `"CAD"`, `AU` returns `"AUD"`, `NZ` returns `"NZD"`, `SG` returns `"SGD"`, `HK` returns `"HKD"`, and any other country returns `"USD"`. On [Google Search](/docs/api-reference/endpoint/google/product-results), a bare `$` always returns `"USD"`.

An explicit token always takes priority over the request country. A `country: "CA"` request that gets an offer displayed as `"R$ 5.597,99"` still returns `"BRL"`.

## Response example

The product request returns one entry in `productResults`:

```json theme={null}
{
  "success": true,
  "result": {
    "productResults": [
      {
        "title": "Sony WH-CH720N Noise Cancelling Headphones",
        "productDocid": "3625873292990915110",
        "aboutTheProduct": {
          "description": "Wireless noise-canceling headphones with up to 35-hour battery life and multipoint connection."
        },
        "specifications": {
          "general": {
            "Brand": "Sony",
            "Noise cancellation": "Yes",
            "Wireless technology type": "Bluetooth"
          }
        },
        "images": [
          {
            "mainUrl": "https://encrypted-tbn3.gstatic.com/shopping?q=tbn:ANd9Gc...",
            "thumbnailUrl": "https://encrypted-tbn3.gstatic.com/shopping?q=tbn:ANd9Gc..."
          }
        ],
        "stores": [
          {
            "name": "Amazon",
            "link": "https://www.amazon.com/sony-wh-ch720n",
            "price": {
              "value": 149.99,
              "currency": "USD",
              "raw": "$149.99"
            },
            "description": "Sony WH-CH720N Wireless Noise Canceling Headphones, Black",
            "shipping": "Free delivery by Thu, Aug 14",
            "condition": "New",
            "rating": 4.6,
            "reviews": "2.3k",
            "buyingOptions": [
              "In stock online",
              "4.6/5",
              "Free delivery",
              "30-day returns"
            ]
          },
          {
            "name": "Best Buy",
            "link": "https://www.bestbuy.com/site/sony-wh-ch720n",
            "price": {
              "value": 33.33,
              "currency": "USD",
              "raw": "$33.33"
            },
            "installments": "for 6 mo, $0 now, $199.98 total",
            "description": "Sony - WH-CH720N Wireless Noise Cancelling Headphones - Black",
            "buyingOptions": [
              "In stock online",
              "Free shipping"
            ]
          }
        ]
      }
    ]
  }
}
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.