AnswerLine Start free

Google AI Mode

Google AI Mode shopping results

The shopping cards and videos inside AI Mode answers.

`shoppingCards` carries the products in the answer and `videos` its video cards. `inlineProducts` and `ads` come back empty today.

`include.expandProducts` is not available yet: a request that sets it is refused with a 400 and not charged.

Returned in result

Field
shoppingCards
inlineProducts
videos
ads

Request

curl -X POST "https://api.answerline.dev/v1/monitor/aimode" \
  -H "Authorization: Bearer $API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"prompt":"Family-friendly hotels in Lisbon","country":"PT","hl":"en"}'

What AI Mode shopping results are

AI Mode shopping results are the commercial blocks Google’s AI Mode places inside a conversational answer: a carousel of product cards, product cards embedded in the answer text, a sponsored section, and video cards. This API returns them as shoppingCards, inlineProducts, ads and videos.

They show which merchants hold the carousel and inline product positions for a category query, the price band and who is discounting (from numeric price.value and oldPrice.value), which stores buy the sponsored section, and which channels’ videos appear next to the products.

Field reference

result.shoppingCards[]

Field Type Meaning
title string Product title.
price.value number Numeric price.
price.currency string Currency symbol.
price.raw string Raw price string as displayed, for example "$129.99".
oldPrice.value, .currency, .raw number, string, string Original price before discount, same shape as price.
store string Merchant or store name.
rating number Product rating.
reviews string Review count, as a string.
thumbnail string Product image.
productLink string Direct product URL.
snippet string Product description snippet.
snippet_links[] array of {text, link, redirectLink} Links inside the snippet; redirectLink only when Google served a redirect.
position integer Position in the shopping carousel, 0-indexed.

result.inlineProducts[]

Field Type Meaning
title string Product title.
position integer 1-indexed rank in display order.
price.value, price.currency number, string Numeric price and currency symbol.
oldPrice.value, oldPrice.currency number, string Original price before discount.
store string Merchant or store name.
thumbnail string Product image URL.
productLink string Direct product URL.

result.ads

Field Type Meaning
title string Section title for the ads.
ads[].title string Ad product title.
ads[].url string Ad click-through URL.
ads[].position integer Position index of the ad.
ads[].price.value, ads[].price.currency number, string Numeric price and currency symbol.
ads[].store string Merchant or store name.
ads[].rating number Product rating.
ads[].reviews string Review count, as a string.
ads[].redirectLink string Google’s /goto redirect, present only when Google served one.

result.videos[]

Field Type Meaning
title string, required Video title.
link string, required Canonical watch URL, timestamp parameters stripped.
platform string Hosting platform.
channel string Channel or uploader name.
duration string Visible duration label, mm:ss or hh:mm:ss.
thumbnail string Public thumbnail URL.
redirectLink string Google’s /goto redirect, present only when Google served one.

Annotated excerpt

Values are illustrative; field names and types follow the POST /v1/monitor/aimode result schema.

{
  "success": true,
  "result": {
    "text": "For small apartments, a compact standing desk with a 48-inch top...",
    "shoppingCards": [
      {
        "title": "Example Lift Desk 48\"",
        "price": { "value": 279.0, "currency": "$", "raw": "$279.00" },
        "oldPrice": { "value": 329.0, "currency": "$", "raw": "$329.00" },
        "store": "Example Home",
        "rating": 4.5,
        "reviews": "1.2K",                   // string, not an integer
        "productLink": "https://www.example-home.com/desks/lift-48",
        "snippet": "Dual motor, memory presets...",
        "position": 0                        // 0-indexed carousel slot
      }
    ],
    "inlineProducts": [
      {
        "title": "Sample Compact Desk",
        "position": 1,                       // 1-indexed
        "price": { "value": 199.99, "currency": "$" },
        "store": "Sample Furniture",
        "productLink": "https://www.sample-furniture.com/compact-desk"
      }
    ],
    // An object: section title plus the ads in it.
    "ads": {
      "title": "Sponsored",
      "ads": [
        {
          "title": "Example Pro Standing Desk",
          "url": "https://www.example-desks.com/pro",
          "position": 1,
          "price": { "value": 349.0, "currency": "$" },
          "store": "Example Desks",
          "redirectLink": "https://www.google.com/goto?url=example"
        }
      ]
    },
    "videos": [
      {
        "title": "Standing desks for tiny apartments",
        "link": "https://www.youtube.com/watch?v=example",
        "platform": "YouTube",
        "channel": "Example Workspace",
        "duration": "9:41"
      }
    ]
  }
}

Cost and include flag

shoppingCards, inlineProducts, ads and videos need no flag. An AI Mode request costs $0.00206 on every tier.

include.expandProducts, merchant offers for the products in the answer, is not available yet: a request that sets it is refused with a 400 and not charged. include.googleGoto is deprecated and ignored.

Example: store share of product slots and advertiser share

The script samples a set of product queries and reports each store’s share of all product slots (carousel plus inline), its share of first slots, the share of its slots shown with an old price, and each store’s share of ad slots.

import os
import time
from collections import Counter
from datetime import date

import requests

API = "https://api.answerline.dev"
HEADERS = {"Authorization": f"Bearer {os.environ['API_KEY']}"}
PROMPTS = ["best standing desk for a small apartment", "standing desk under $300"]
SAMPLES = 4
DAY = date.today().isoformat()


def run_tasks(tasks):
    resp = requests.post(f"{API}/v1/async/task/batch", headers=HEADERS, json=tasks, timeout=60)
    resp.raise_for_status()
    pending = {item["task"]["id"] for item in resp.json()["results"] if item["success"]}
    results = []
    while pending:
        time.sleep(10)
        for task_id in list(pending):
            body = requests.get(f"{API}/v1/async/task/{task_id}", headers=HEADERS, timeout=30).json()
            status = body["task"]["status"]
            if status in ("COMPLETED", "FAILED"):
                pending.discard(task_id)
                if status == "COMPLETED":
                    results.append(body["response"]["result"])
    return results


tasks = [
    {
        "taskType": "AIMODE",
        "payload": {"prompt": prompt, "country": "US", "hl": "en"},
        "idempotencyKey": f"desks-shop-{p}-s{s}-{DAY}",
    }
    for p, prompt in enumerate(PROMPTS)
    for s in range(SAMPLES)
]
answers = run_tasks(tasks)

slots, first, discounted, ads = Counter(), Counter(), Counter(), Counter()
with_products = with_ads = 0
for result in answers:
    # Normalise both arrays to 1-based ranks.
    products = [(c.get("position", 0) + 1, c) for c in result.get("shoppingCards", [])]
    products += [(i.get("position", 0), i) for i in result.get("inlineProducts", [])]
    with_products += bool(products)
    for rank, item in products:
        store = item.get("store") or "?"
        slots[store] += 1
        first[store] += rank == 1
        discounted[store] += bool((item.get("oldPrice") or {}).get("value"))
    ad_items = (result.get("ads") or {}).get("ads", [])
    with_ads += bool(ad_items)
    ads.update(ad.get("store") or "?" for ad in ad_items)

n = len(answers) or 1
total_slots, total_ads = sum(slots.values()) or 1, sum(ads.values()) or 1
print(f"{len(answers)} answers; products in {with_products / n:.0%}, ads in {with_ads / n:.0%}")
for store, count in slots.most_common(10):
    print(f"{store:28} slots {count / total_slots:5.0%}  first {first[store]:3}  discounted {discounted[store] / count:5.0%}")
for store, count in ads.most_common(10):
    print(f"ad  {store:24} {count / total_ads:5.0%}")

Pitfalls

shoppingCards[].position starts at 0 and inlineProducts[].position at 1. Normalize once, at ingestion.

reviews on shopping cards and ads is a string such as 1.2K. Convert it before doing arithmetic, and keep the original text.

currency is a symbol, and $ is shared by several currencies. Pair it with the request’s country when comparing markets.

ads is an object: read result["ads"]["ads"], and handle a missing ads key.

A product can appear in the carousel and inline. Deduplicate on productLink when counting distinct products; keep both when counting slots.

Product and ad blocks vary between runs, so compare periods on several samples each (AI answer volatility).

Questions

What is the difference between shoppingCards and inlineProducts in AI Mode?

shoppingCards are the product cards in the shopping carousel, with price, old price, store, rating, reviews, snippet and snippet links. inlineProducts are product cards found within the answer text, with title, price, old price, store, thumbnail and product link.

Are AI Mode product positions 0-based or 1-based?

shoppingCards[].position is 0-indexed within the carousel. inlineProducts[].position is 1-indexed in display order. Normalize both before storing ranks.

Can I get merchant offers with include.expandProducts?

Not available yet: a request that sets it is refused with a 400 and not charged.

Is the AI Mode ads field an array?

No. ads is an object with a section title and an ads array. Each ad has title, url, position, price, store, rating, reviews and, when Google served a redirect, redirectLink.

Do shopping cards, videos and ads cost extra in AI Mode?

No. They are part of the AI Mode result at $2.06 per 1,000 on every tier. The endpoint has no add-ons.

More Google AI Mode data

All Google AI Mode fields · API reference