Google Shopping via Scavio (v2)
Search Google Shopping for products, open a full product detail page, and page through every store selling it — all as structured JSON. Three endpoints, each 1 credit.
When to trigger
Use this skill when the user asks to:
- Find products across retailers with price or sale filters
- Compare prices for a product across many stores
- Get specs, ratings, variants, or seller options for a product
- Build a price-comparison or shopping-research workflow
Setup
Get a free API key at scavio.dev (50 free credits to get started, no card required):
export SCAVIO_API_KEY=sk_live_your_key
If you do not have a key yet
An agent running this skill without SCAVIO_API_KEY set will get 401 on every
call below. The whole path from nothing to a working key is self-serve:
- Sign up at dashboard.scavio.dev - email or Google, no card required.
- A key is created for the account automatically at signup. It is on the dashboard under API Keys, ready to copy.
- A new account starts with 50 credits. Endpoints in this skill cost 1 credit each unless the table below says otherwise.
When the balance runs out the API answers 402 with a JSON body carrying
billing_url. Topping up needs no code change - the same key keeps working.
The smallest purchase is 2,500 credits for $25, and monthly plans work out
cheaper per credit if the usage is steady rather than one-off.
Endpoints
| Endpoint | Credits | Description |
|---|---|---|
POST https://api.scavio.dev/api/v2/google/shopping |
1 | Search products, returns shopping_results[] |
POST https://api.scavio.dev/api/v2/google/shopping/product |
1 | Full product detail page |
POST https://api.scavio.dev/api/v2/google/shopping/product/stores |
1 | Page through all stores selling a product |
Authorization: Bearer $SCAVIO_API_KEY
Workflow
- Search: call
/shoppingwith aquery. Filter withmin_price,max_price,on_sale,free_shipping, orsort_by. Each result carries acatalog_id(durable) orproduct_id. - Product page: call
/shopping/productwith acatalog_id(pass the samequery) for full specs, variants, and top stores inproduct_results. - All stores: if the product lists more sellers than returned, call
/shopping/product/storeswith thecatalog_idand thenext_page_tokenfrom the previous response to page through every store.
Shopping Search Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
string | required | Search query (1-500 chars) |
device |
string | -- | desktop or mobile |
start |
number | -- | Result offset (follow pagination.next) |
min_price |
number | -- | Minimum price filter |
max_price |
number | -- | Maximum price filter |
sort_by |
number | 0 |
0 relevance, 1 price ascending, 2 price descending |
free_shipping |
boolean | -- | Only free-shipping offers |
on_sale |
boolean | -- | Only on-sale offers |
shoprs |
string | -- | Opaque filter token from filters[] / carousel_filters[] |
hl |
string | -- | UI language |
gl |
string | -- | Geo country |
google_domain |
string | google.com |
Regional Google domain |
location |
string | -- | Canonical location name (auto-UULE) |
uule |
string | -- | Pre-encoded UULE |
Product Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
catalog_id |
string | -- | Durable catalog id (pass with query) |
query |
string | -- | Required when catalog_id is set |
product_id |
string | -- | Product id alternative |
immersive_product_page_token |
string | -- | Page token from a listing |
page_token |
string | -- | Alias for immersive_product_page_token |
device |
string | -- | desktop, mobile, or tablet |
sort_by |
string | -- | Seller sort: base_price, total_price, promotion, seller_rating |
load_all_stores |
boolean | -- | Load all stores inline |
more_stores |
boolean | -- | Include additional stores |
hl |
string | -- | UI language |
gl |
string | -- | Geo country |
google_domain |
string | google.com |
Regional Google domain |
location |
string | -- | Canonical location name |
uule |
string | -- | Pre-encoded UULE |
Product Stores Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
catalog_id |
string | required | Same catalog_id used on the product call |
next_page_token |
string | required | Continuation cursor from a prior response |
Example
import requests
BASE = "https://api.scavio.dev"
# Your key from https://scavio.dev. Load it from your environment or secret
# store in real code - keep it out of source control.
API_KEY = "sk_your_key_here"
HEADERS = {"Authorization": f"Bearer {API_KEY}"}
# 1. Search products, cheapest first, under $1500
search = requests.post(f"{BASE}/api/v2/google/shopping", headers=HEADERS,
json={"query": "16 inch laptop", "sort_by": 1, "max_price": 1500}).json()
item = search["shopping_results"][0]
print(item["title"], item.get("price"), item.get("source"))
# 2. Full product page (catalog_id needs the query alongside it)
product = requests.post(f"{BASE}/api/v2/google/shopping/product", headers=HEADERS,
json={"catalog_id": item["catalog_id"], "query": "16 inch laptop"}).json()
# 3. Page through every store selling it
token = product["product_results"].get("stores_pagination", {}).get("next_page_token")
if token:
stores = requests.post(f"{BASE}/api/v2/google/shopping/product/stores", headers=HEADERS,
json={"catalog_id": item["catalog_id"], "next_page_token": token}).json()
for s in stores["product_results"]["stores"]:
print(s.get("name"), s.get("total_price"))
Responses
Search returns shopping_results[] (plus filters and pagination); product returns product_results; stores returns product_results.stores[]. Each also includes response_time, credits_used, credits_remaining, and cached.
{
"shopping_results": [
{
"position": 1,
"title": "Example 16\" Laptop",
"price": "$1,299.00",
"extracted_price": 1299,
"source": "Example Store",
"rating": 4.5,
"reviews": 210,
"catalog_id": "1234567890"
}
],
"response_time": 1420,
"credits_used": 1,
"credits_remaining": 997,
"cached": false
}
Guardrails
- Each call costs 1 credit. Inform the user before paginating through many stores.
- Never fabricate product titles, prices, sellers, or ratings. Only return API data.
- The product call needs
catalog_id+querytogether; the stores call needscatalog_id+next_page_token— always run/shoppingfirst to obtain thecatalog_id. - Prices are strings as displayed; use
extracted_pricewhen present for numeric comparisons.
Failure handling
400means an invalid parameter (e.g.catalog_idwithoutquery) — fix and retry.401means the API key is invalid or missing. CheckSCAVIO_API_KEY.429means rate or usage limit exceeded. Wait before retrying. See rate limits.502/503mean upstream is temporarily unavailable. Wait a few seconds before retrying.- If search returns no results, loosen the price filters or broaden the query.
- If
SCAVIO_API_KEYis not set, prompt the user to export it before continuing.
