Monitoring e-commerce products across platforms reveals pricing gaps, out-of-stock windows, and competitor positioning that single-platform tools miss. Sellers, brands, and price intelligence teams need a unified view of how a product appears on Google Shopping, Amazon, and other marketplaces. The Scavio search API supports multiple platform targets in a single integration, returning structured price, title, seller, and availability data. This tutorial builds a cross-platform product monitor that polls each platform, normalizes the results into a single comparison table, and flags changes between runs.
Prerequisites
- Python 3.8 or higher installed
- requests library installed (pip install requests)
- A Scavio API key from scavio.dev
- Product names or ASINs you want to track
Walkthrough
Step 1: Define the product watchlist with platform queries
Create a list of products, each with a name and platform-specific search queries. This allows the same product to be tracked on Google Shopping and Amazon with the most relevant query for each.
PRODUCTS = [
{
'name': 'Sony WH-1000XM5',
'queries': {
'google_shopping': 'Sony WH-1000XM5 headphones',
'amazon': 'B09XS7JWHH'
}
},
{
'name': 'Apple AirPods Pro 2',
'queries': {
'google_shopping': 'Apple AirPods Pro 2nd generation',
'amazon': 'B0D1XD1ZV3'
}
}
]Step 2: Fetch product data from each platform
Write a function that calls the Scavio API with the appropriate platform parameter. Google Shopping results come from the shopping_results key, while Amazon results come from product or organic_results.
import requests
import os
API_KEY = os.environ.get('SCAVIO_API_KEY', 'your_scavio_api_key')
ENDPOINT = 'https://api.scavio.dev/api/v1/search'
def fetch_platform(query: str, platform: str) -> dict:
payload = {'query': query, 'country_code': 'us'}
if platform == 'google_shopping':
payload['search_type'] = 'shopping'
elif platform == 'amazon':
payload['platform'] = 'amazon'
response = requests.post(
ENDPOINT,
headers={'x-api-key': API_KEY},
json=payload
)
response.raise_for_status()
return response.json()Step 3: Normalize results into a common format
Extract price, title, seller, and availability from each platform response into a uniform dict. This makes cross-platform comparison straightforward.
def normalize_google_shopping(data: dict) -> list[dict]:
results = []
for item in data.get('shopping_results', [])[:5]:
results.append({
'platform': 'google_shopping',
'title': item.get('title', ''),
'price': item.get('price', ''),
'seller': item.get('source', ''),
'link': item.get('link', '')
})
return results
def normalize_amazon(data: dict) -> list[dict]:
product = data.get('product', {})
if product:
return [{
'platform': 'amazon',
'title': product.get('title', ''),
'price': product.get('price', ''),
'seller': 'Amazon',
'link': product.get('link', '')
}]
return []Step 4: Compare against previous run and report changes
Load the last saved prices from a JSON file, compare against current results, and print any price or availability changes. Save the updated data for the next run.
import json
from pathlib import Path
HISTORY_FILE = Path('product_monitor_history.json')
def detect_changes(product_name: str, current: list[dict], history: dict) -> None:
prev = history.get(product_name, [])
prev_map = {(r['platform'], r['seller']): r['price'] for r in prev}
for item in current:
key = (item['platform'], item['seller'])
old_price = prev_map.get(key)
if old_price and old_price != item['price']:
print(f' PRICE CHANGE [{item["platform"]}] {item["seller"]}: {old_price} -> {item["price"]}')
elif not old_price:
print(f' NEW LISTING [{item["platform"]}] {item["seller"]}: {item["price"]}')Step 5: Run the full monitor and save results
Iterate through all products, fetch from each platform, normalize, compare, and persist. Run this script on a cron schedule for continuous monitoring.
def run_monitor():
history = json.loads(HISTORY_FILE.read_text()) if HISTORY_FILE.exists() else {}
new_history = {}
for product in PRODUCTS:
print(f'Checking: {product["name"]}')
all_results = []
for platform, query in product['queries'].items():
data = fetch_platform(query, platform)
if platform == 'google_shopping':
all_results.extend(normalize_google_shopping(data))
elif platform == 'amazon':
all_results.extend(normalize_amazon(data))
detect_changes(product['name'], all_results, history)
new_history[product['name']] = all_results
HISTORY_FILE.write_text(json.dumps(new_history, indent=2))
print(f'Saved {len(new_history)} products to history')
run_monitor()Python Example
import os
import json
import requests
from pathlib import Path
API_KEY = os.environ.get('SCAVIO_API_KEY', 'your_scavio_api_key')
ENDPOINT = 'https://api.scavio.dev/api/v1/search'
HISTORY_FILE = Path('product_monitor_history.json')
PRODUCTS = [
{
'name': 'Sony WH-1000XM5',
'queries': {
'google_shopping': 'Sony WH-1000XM5 headphones',
'amazon': 'B09XS7JWHH'
}
},
{
'name': 'Apple AirPods Pro 2',
'queries': {
'google_shopping': 'Apple AirPods Pro 2nd generation',
'amazon': 'B0D1XD1ZV3'
}
}
]
def fetch_platform(query: str, platform: str) -> dict:
payload = {'query': query, 'country_code': 'us'}
if platform == 'google_shopping':
payload['search_type'] = 'shopping'
elif platform == 'amazon':
payload['platform'] = 'amazon'
response = requests.post(
ENDPOINT,
headers={'x-api-key': API_KEY},
json=payload
)
response.raise_for_status()
return response.json()
def normalize_google_shopping(data: dict) -> list[dict]:
results = []
for item in data.get('shopping_results', [])[:5]:
results.append({
'platform': 'google_shopping',
'title': item.get('title', ''),
'price': item.get('price', ''),
'seller': item.get('source', ''),
'link': item.get('link', '')
})
return results
def normalize_amazon(data: dict) -> list[dict]:
product = data.get('product', {})
if product:
return [{
'platform': 'amazon',
'title': product.get('title', ''),
'price': product.get('price', ''),
'seller': 'Amazon',
'link': product.get('link', '')
}]
return []
def detect_changes(name: str, current: list[dict], history: dict) -> None:
prev = history.get(name, [])
prev_map = {(r['platform'], r['seller']): r['price'] for r in prev}
for item in current:
key = (item['platform'], item['seller'])
old_price = prev_map.get(key)
if old_price and old_price != item['price']:
print(f' PRICE CHANGE [{item["platform"]}] {item["seller"]}: {old_price} -> {item["price"]}')
elif not old_price:
print(f' NEW LISTING [{item["platform"]}] {item["seller"]}: {item["price"]}')
def run_monitor():
history = json.loads(HISTORY_FILE.read_text()) if HISTORY_FILE.exists() else {}
new_history = {}
for product in PRODUCTS:
print(f'Checking: {product["name"]}')
all_results = []
for platform, query in product['queries'].items():
data = fetch_platform(query, platform)
if platform == 'google_shopping':
all_results.extend(normalize_google_shopping(data))
elif platform == 'amazon':
all_results.extend(normalize_amazon(data))
detect_changes(product['name'], all_results, history)
new_history[product['name']] = all_results
HISTORY_FILE.write_text(json.dumps(new_history, indent=2))
print(f'Saved {len(new_history)} products to history')
if __name__ == '__main__':
run_monitor()JavaScript Example
const API_KEY = process.env.SCAVIO_API_KEY || 'your_scavio_api_key';
const ENDPOINT = 'https://api.scavio.dev/api/v1/search';
const fs = require('fs');
const HISTORY_FILE = 'product_monitor_history.json';
const PRODUCTS = [
{
name: 'Sony WH-1000XM5',
queries: { google_shopping: 'Sony WH-1000XM5 headphones', amazon: 'B09XS7JWHH' }
},
{
name: 'Apple AirPods Pro 2',
queries: { google_shopping: 'Apple AirPods Pro 2nd generation', amazon: 'B0D1XD1ZV3' }
}
];
async function fetchPlatform(query, platform) {
const payload = { query, country_code: 'us' };
if (platform === 'google_shopping') payload.search_type = 'shopping';
else if (platform === 'amazon') payload.platform = 'amazon';
const response = await fetch(ENDPOINT, {
method: 'POST',
headers: { 'x-api-key': API_KEY, 'Content-Type': 'application/json' },
body: JSON.stringify(payload)
});
if (!response.ok) throw new Error('HTTP ' + response.status);
return response.json();
}
function normalizeGoogleShopping(data) {
return (data.shopping_results || []).slice(0, 5).map(item => ({
platform: 'google_shopping',
title: item.title || '',
price: item.price || '',
seller: item.source || '',
link: item.link || ''
}));
}
function normalizeAmazon(data) {
const product = data.product || {};
if (product.title) {
return [{ platform: 'amazon', title: product.title, price: product.price || '', seller: 'Amazon', link: product.link || '' }];
}
return [];
}
async function main() {
const history = fs.existsSync(HISTORY_FILE) ? JSON.parse(fs.readFileSync(HISTORY_FILE, 'utf-8')) : {};
const newHistory = {};
for (const product of PRODUCTS) {
console.log('Checking: ' + product.name);
const allResults = [];
for (const [platform, query] of Object.entries(product.queries)) {
const data = await fetchPlatform(query, platform);
if (platform === 'google_shopping') allResults.push(...normalizeGoogleShopping(data));
else if (platform === 'amazon') allResults.push(...normalizeAmazon(data));
}
const prev = history[product.name] || [];
const prevMap = Object.fromEntries(prev.map(r => [r.platform + '|' + r.seller, r.price]));
allResults.forEach(item => {
const key = item.platform + '|' + item.seller;
const oldPrice = prevMap[key];
if (oldPrice && oldPrice !== item.price) console.log(' PRICE CHANGE [' + item.platform + '] ' + item.seller + ': ' + oldPrice + ' -> ' + item.price);
else if (!oldPrice) console.log(' NEW LISTING [' + item.platform + '] ' + item.seller + ': ' + item.price);
});
newHistory[product.name] = allResults;
}
fs.writeFileSync(HISTORY_FILE, JSON.stringify(newHistory, null, 2));
console.log('Saved ' + Object.keys(newHistory).length + ' products to history');
}
main().catch(console.error);Expected Output
Checking: Sony WH-1000XM5
NEW LISTING [google_shopping] Best Buy: $348.00
NEW LISTING [google_shopping] Amazon.com: $328.00
NEW LISTING [amazon] Amazon: $328.00
Checking: Apple AirPods Pro 2
NEW LISTING [google_shopping] Apple: $249.00
NEW LISTING [amazon] Amazon: $189.99
Saved 2 products to history