AnswerLine Start free

Google AI Mode

Google AI Mode shopping results

The product cards, sponsored products and videos inside AI Mode answers, with prices and stores.

shoppingCards carries the products in the answer, ads the sponsored products with their store and price, and videos its video cards. inlineProducts comes back empty: Google shows an inline product mention without a name or price.

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, ads and videos. inlineProducts is in the contract and comes back empty: Google shows an inline product mention without a name or price.

They show which merchants hold the carousel 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[]

Empty on the answers served today. The contract’s fields:

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": [],                    // empty on the answers served today
    // 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, 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 fill more than one slot in an answer. Deduplicate on productLink when counting distinct products; keep every slot 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 is the contract field for products inside the answer text; it comes back empty, because Google shows an inline product mention without a name or price.

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