Lessons From Building a Price Tracker on a Shopping Search API
Published 2026-07-07 · SameOS Tools
I run a project that collects product prices every hour through a shopping search API (an interface that lets a program fetch shopping search results as data) and publishes them as a price board. The API docs make it look like "search, save the lowest price, done" - but in practice most of the work is a fight for data quality. Here is what a few weeks of operation taught me.
Why You Should Not Sort by Lowest Price
The first lesson was the sort option. Sorting by lowest price fills the top results with coupons, accessories, and spare parts instead of the actual product. It is far more stable to fetch by relevance and filter prices in your own code. A simple rule - discard anything outside 40%-200% of a reference price (a representative price set per item in advance) - removes most accessory pollution.
Validating product titles is also essential. Searching for "V15" brings in "V15s"; searching for "5070" brings in "5070 Ti". I extract model tokens from the item name, compare them against result titles, and reject titles where a variant suffix (Ti, PRO, Ultra, and so on) indicates a different model. Contamination dropped sharply.
Sold-Out Listings Pollute the Lowest Price
The sneakiest problem was sold-out listings. Some sellers never remove them, so a price nobody can actually pay keeps showing as the catalog minimum. My rule: if the lowest price sits isolated, far below the next supported price, treat it as suspect and replace it with a price level that multiple sellers support. Real sales survive because several shops drop together; only lone ghost prices get filtered.
Practical example code
// 1) Reference-price band: removes accessory and spare-part pollution
function in_band(int $price, int $base): bool {
return $price >= (int)($base * 0.4)
&& $price <= (int)($base * 2.0);
}
// 2) Detect an isolated lowest price: replace sold-out ghost prices
// If the lowest price sits 8%+ below the next listing,
// it is likely a price nobody can actually pay
function pick_trusted(array $prices): int {
sort($prices);
if (count($prices) >= 3 && $prices[1] > $prices[0] * 1.08) {
return $prices[1]; // the price multiple shops support
}
return $prices[0];
}
// 3) Block model-variant contamination (e.g. 5070 vs 5070 Ti)
function is_variant(string $title, string $core): bool {
$suffix = '(?:ti|super|ultra|pro|max|plus|lite|s)';
return (bool)preg_match(
'/' . preg_quote($core, '/') . '\s*' . $suffix . '(?![a-z])/iu',
$title
);
}
The price board running these rules in production is sisemap.com. Collection scheduling runs on cron (a Linux scheduler that runs commands at set times) - common scheduling mistakes are covered in a separate article.