Skroutz API & Scraper
The Skroutz API turns Greece's price-comparison site into clean JSON, in three actions - search, product/detail and product/offers.
🤖 Using an AI assistant? Copy this link into ChatGPT / Claude / Cursor — it reads every endpoint and parameter instantly and tells you if this API fits your use case.
product/offers is why the engine exists, and it is also the cheapest of the three: ONE upstream request, a 231 KB median, 1.4 s, and it returns every Greek merchant selling that product in one go - measured at 49 shops on a De'Longhi descaler and 48 on an iPhone 17 Pro Max. Each row carries the shop's Skroutz id, name, storefront link, star rating and how many ratings it rests on, the shop's town and country, the price as a number, the shipping fee, the total including shipping, the delivery estimate, the stock line and the shop's own listing title. Verification on 2026-09-06 covered 13 products across 8 Skroutz categories and 332 offers: price, seller name, seller id, seller URL, seller location, offer URL, shipping cost and delivery estimate were all filled on 332 of 332, and every one of the 332 prices matched an independent second extraction of the same page - 0 mismatches. search returns the product grid with the id you feed to product/offers, and product/detail returns the full Greek record: title, brand, MPN, model, colour, description, gallery, the customer rating with its per-star breakdown, and the complete technical specification grouped as Skroutz groups it. Prices are EUR. No Skroutz account, no browser - one ReefAPI key and the standard { ok, data, meta, error } envelope.
The price on a Skroutz product page is the FEATURED offer, not the cheapest one
This is the single most important thing to know before you build against Skroutz, and it is why price_min is deliberately null on product/detail. Skroutz prints one price on a product page and on a listing card: the offer it features. Checked against the same product's own merchant table on all 13 verification products on 2026-09-06, that price equalled the cheapest offer on 6 and sat ABOVE it on 7. It is always one of the real offer prices - it is honest data - but calling it a price floor would be a lie by field name.
| Skroutz product | Price on the product page | Cheapest merchant offer | Where the featured offer ranked |
|---|---|---|---|
| Bosch Mymoment TKA2M113 filter coffee maker | 41.52 EUR | 37.79 EUR | 16th of 29 offers - the worst case measured |
| Apple iPhone 17 Pro Max | 1,370.00 EUR | 1,362.40 EUR | 2nd of 48 |
| LG Smart 32-inch Full HD TV | 192.90 EUR | 191.52 EUR | 3rd of 33 |
| New Balance 530 | 109.00 EUR | 108.99 EUR | 2nd of 43 |
| Nike Air Force 1 '07 | 108.00 EUR | 107.96 EUR | 2nd of 39 |
| Samsung Smart 43-inch 4K QLED | 286.00 EUR | 285.86 EUR | 2nd of 29 |
| Ulefone Armor 28 Ultra 5G | 944.90 EUR | 944.88 EUR | 2nd of 36 |
So product/detail returns that number as price and returns price_min, price_max and offer_count as null, pointing at product/offers - which is the only surface where the real band and the real count exist. product/offers returns both, and its count matched the shop count Skroutz prints on its own merchant table on 10 of the 10 products where Skroutz prints one (14/14, 9/9, 29/29, 29/29, 33/33, 36/36, 39/39, 43/43, 48/48, 49/49). That parity is what establishes there is no hidden pagination to chase.
Real request and response JSON
Captured from the indexed primary action, search, on .
{
"method": "POST",
"url": "https://api.reefapi.com/skroutz/v1/search",
"headers": {
"x-api-key": "$REEF_KEY",
"content-type": "application/json"
},
"body": {
"query": "teka gfh 73"
}
}{
"ok": true,
"meta": {
"api": "skroutz",
"endpoint": "search",
"mode": "live",
"latency_ms": 1253.7,
"record_count": 3,
"bytes": 121993,
"cache_hit": false,
"pagination": {
"page": 1,
"has_more": false,
"page_size": 3,
"total": 3
}
},
"data": {
"results": [
{
"product_id": "809",
"title": "Teka GFH 73 Μηχανισμός Απορρόφησης 73cm Inox",
"url": "https://www.skroutz.gr/s/809/Teka-GFH-73-Michanismos-Aporrofisis-73cm-Inox.html",
"image": "https://a.scdn.gr/images/sku_main_images/000000/809/large_[redacted-phone]_teka_gfh_73_michanismos_aporrofisis_73cm_inox.jpeg",
"price": 130,
"price_display": "130,00 €",
"price_from": 130,
"price_to": null,
"variant_family": false,
"price_before_discount": null,
"currency": "EUR",
"rating": null,
"review_count": null,
"rating_scale": null,
"category": "Απορροφητήρες Κουζίνας",
"category_url": "https://www.skroutz.gr/c/408/aporrofitires_kouzinas.html",
"key_specs": "Απορροφητική Ισχύς: Max 329m³/h, με Πλενόμενο Φίλτρο",
"delivery": null,
"promoted": true
},
{
"product_id": "40592764",
"title": "Teka Ανταλλακτικό Φίλτρο Ενεργού Άνθρακα 12x12cm",
"url": "https://www.skroutz.gr/s/40592764/Teka-61801346-Antallaktiko-Filtro-Energou-Anthraka-Aporrofitira-Symvato-me-Teka-12x12cm.html",
"image": "https://d.scdn.gr/images/sku_main_images/040592/40592764/large_[redacted-phone]_teka_cnl_1c_antallaktiko_filtro_energou_anthraka_aporrofitira_symvato_me_teka_61801346.jpeg",
"price": 13,
"price_display": "13,00 €",
"price_from": 13,
"price_to": null,
"variant_family": false,
"price_before_discount": null,
"currency": "EUR",
"rating": 1,
"review_count": 1,
"rating_scale": null,
"category": "Αξεσουάρ Απορροφητήρων",
"category_url": "https://www.skroutz.gr/c/4202/axesouar-aporrofitiron.html",
"key_specs": "Συμβατότητα: Teka",
"delivery": "Παράδοση έως Τετ, 09 Σεπ",
"promoted": false
},
{
"product_id": "53083779",
"title": "Wessper Ανταλλακτικό Φίλτρο Ενεργού Άνθρακα",
"url": "https://www.skroutz.gr/s/53083779/Wessper-OP-5575-Antallaktiko-Filtro-Energou-Anthraka-Aporrofitira-Symvato-me-Teka.html",
"image": "https://b.scdn.gr/images/sku_main_images/053083/53083779/large_[redacted-phone]_wessper_op_5575_antallaktiko_filtro_energou_anthraka_aporrofitira_symvato_me_teka_[redacted-phone].jpeg",
"price": 12.9,
"price_display": "12,90 €",
"price_from": 12.9,
"price_to": null,
"variant_family": false,
"price_before_discount": null,
"currency": "EUR",
"rating": null,
"review_count": null,
"rating_scale": null,
"category": "Αξεσουάρ Απορροφητήρων",
"category_url": "https://www.skroutz.gr/c/4202/axesouar-aporrofitiron.html",
"key_specs": "Συμβατότητα: Teka",
"delivery": "Παράδοση έως Τετ, 09 Σεπ",
"promoted": false
}
],
"count": 3,
"duplicate_cards_dropped": 1,
"total_results": 3,
"search_mode": "keyword",
"resolved_title": null,
"resolved_url": "https://www.skroutz.gr/search?keyphrase=teka+gfh+73",
"query": "teka gfh 73",
"page": 1
}
}What the Skroutz API does
| Action | Description | Concrete use case | Key params |
|---|---|---|---|
| search | Search skroutz.gr by keyword and get the matching products: Skroutz product id, title, image, the price skroutz prints on the card (the offer it FEATURES, which is not always the cheapest one — measured 120,00 € on a card whose cheapest merchant offer was 108,99 €; null when the card shows a variant range instead, with the endpoints in price_from/price_to), the customer rating and review count, the category and skroutz's own key-spec summary. Use the returned `product_id` with `product/offers` to get every Greek shop's price for that product. | Pricing teams call search to search skroutz.gr by keyword and get the matching products. | query, page, max_rotations |
| product/detail | The full Skroutz product record by `product_id` (or product URL): title, brand, description, image gallery, manufacturer part number, model and colour, the price skroutz features on the page, the customer rating with its review count and per-star breakdown, the category, and the complete technical specification grouped exactly as skroutz groups it. | Marketplace operators call product/detail to get the full Skroutz product record by `product_id` (or product URL). | product_id, max_rotations |
| product/offers | Every Greek merchant offer for one product — the price comparison itself, in a single request. For the given `product_id` you get one row per shop: the shop with its Skroutz id, name, storefront link, star rating and how many reviews it rests on, its town, the price (numeric and formatted), the price before a running coupon and the discount, the shipping fee and the total, the promised delivery date, declared stock, and the merchant's own listing title. Rows are ordered cheapest first. | Catalog enrichment teams call product/offers to get every Greek merchant offer for one product. | product_id, sort, include_product, max_rotations |
Call search from your stack
curl -X POST https://api.reefapi.com/skroutz/v1/search \
-H "x-api-key: $REEF_KEY" \
-H "content-type: application/json" \
-d '{"query":"teka gfh 73"}'import requests
r = requests.post(
"https://api.reefapi.com/skroutz/v1/search",
headers={"x-api-key": REEF_KEY},
json={
"query": "teka gfh 73"
},
)
print(r.json()["data"])const res = await fetch("https://api.reefapi.com/skroutz/v1/search", {
method: "POST",
headers: {
"x-api-key": process.env.REEF_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
"query": "teka gfh 73"
}),
});
const { ok, data, meta, error } = await res.json();Ask your MCP-connected assistant: call reefapi.skroutz.search with {"query":"teka gfh 73"}.Who uses this API and why
- Greek price-monitoring teams call product/offers to get every merchant's price, shipping fee, total and delivery date for one product in a single request.
- Repricing tools read price_min and price_max from product/offers rather than the product page, because the page price was above the cheapest offer on 7 of 13 measured products.
- Marketplace sellers check where their own Skroutz offer ranks among up to 49 competitors, with each shop's star rating and rating count attached.
- Catalog teams call product/detail for the Greek title, brand, MPN, model, colour and the full spec table grouped exactly as Skroutz groups it.
Questions developers ask before integrating
How many Greek shops does one product/offers call return, and what does it cost?
As many as Skroutz lists, in a single upstream request - there is no pagination on the merchant table. Measured on 2026-09-06: 49 shops on a De'Longhi descaler (382 KB, 1.5 s), 48 on an iPhone 17 Pro Max (361 KB, 1.4 s), 43 on a New Balance 530, 36 on a Ulefone Armor 28 Ultra, 14 on the Teka GFH 73 reference product (102 KB, 0.96 s). A single-merchant product is 21 KB and 0.63 s. Median across the 13 products was 231 KB and 1,425 ms. That makes offers the CHEAPEST of the three actions on bytes - a product page is 429 KB median - which is unusual for a price-comparison site and is the reason it is priced the same as the other two rather than above them.
Is the price on a search row or a product page the cheapest price?
No. It is the offer Skroutz features, and it was above the cheapest merchant offer on 7 of the 13 verification products - once by 10 percent, at rank 16 of 29. On a listing card the same rule holds: a card reading 120,00 EUR sat on a product whose cheapest merchant offer was 108,99 EUR. If you need a floor, call product/offers and read price_min there; that action returns the real band and its cheapest and most expensive rows. product/detail returns price_min, price_max and offer_count as explicit nulls so you cannot mistake the featured price for a band.
Why is price null on some search rows?
Because that card is a variant family and Skroutz printed a RANGE instead of a price - "285,86 EUR - 1.999,00 EUR" for a TV sold in 43 to 98 inches. Measured on the television category page: 33 of 48 cards were in that state. A first-number-wins parser would return 33 confident wrong prices there, so the engine returns price as null, puts the two endpoints in price_from and price_to, sets variant_family to true, and always returns price_display with exactly the string Skroutz printed. Between price and price_to, every row on every page measured was accounted for: 48/48 TVs, 52/52 perfumes, 57/57 laptops, 55/55 washing machines.
Does the merchant price include a coupon discount?
Yes, and this one is a trap in the raw page. Each merchant row carries a data attribute with a pre-coupon price, and on a row with a running coupon that number is wrong: the rendered price was 759,05 EUR, the struck-through price 799,00 EUR and the coupon 39,95 EUR. Reading the attribute would ship a price 39.95 EUR too high while returning ok:true. The engine reads the rendered final price instead and returns price_before_discount and discount alongside it. 3 of the 332 measured offer rows were in that state - rare, and exactly the rows a customer would notice.
Why does a search sometimes return a category page instead of search results?
Because Skroutz answers broad keywords with one of its own pages - "laptop" becomes its laptops category, "samsung" becomes its Samsung brand page - and it drops the page number on the way, so asking for page 2 of a redirected keyword returns page 1 again. The engine detects that and re-requests from the resolved URL, so paging works either way; it costs one upstream request when Skroutz stays on its search route and two when it redirects. The response tells you which happened: search_mode reads keyword or resolved, with resolved_title and resolved_url. A keyword can also resolve onto an editorial article, which carries no product cards at all - that comes back as an honest count of 0 with the article URL, not as an error.
How reliable is the parsed price - has it been checked against the page?
Twice, independently. A second extractor written as raw regex over each merchant block, sharing no code with the engine's parser, agreed on 332 of 332 offer rows. The only two rows where the two disagreed at all were merchant NAMES, and there the engine was the more correct one - it decodes HTML entities, so it returns "Woman's Fashion" and "Web & IT" where the naive extractor returns the escaped text. A recursive scan of every string in all 26 verification payloads found 0 raw HTML tags and 0 HTML entities.
Is a shop rating of zero a real rating?
There is never a zero. 252 of 332 measured offers carried a shop rating; the other 80 came from shops Skroutz has genuinely not rated, and those return null for both the rating and the rating count, never 0.0. The invariant was checked directly - 0 rows had a null rating sitting next to a non-null rating count. Note also that a shop's rating and a product's rating are two different numbers and are returned in two different places: on one verification product the item had a review_count of 6 while its single seller had a rating_count of 3.
What does Skroutz NOT publish?
A rating scale, first of all: there is no maximum-rating value anywhere in the page or its structured data, so rating_scale is null on every action rather than an assumed 5. What you get instead is the per-star histogram itself, so you can read the buckets first-hand. Also absent: a price band or shop count on the product page (both live on product/offers), a link into the merchant's own site - the only link Skroutz exposes is its own click-through - an exact stock number when the shop declares a band like "5+ pieces" (the text is returned, the number stays null), a per-size price, since Skroutz prices the product rather than the size, and a shop rating for an unrated shop. Skroutz also has no stable search page size; it returns 48 to 60 rows depending on the page it resolved to, so read count.
What is the Skroutz API?
Skroutz API is a ReefAPI endpoint group for greek price comparison: every greek shop's price for one product. It returns live JSON through POST requests under /skroutz/v1.
Is the Skroutz API free to try?
Yes. ReefAPI starts with 1,000 free credits, no card required. Skroutz calls use the same shared credit balance as every other ReefAPI engine.
Do I need a Skroutz login or account?
No login to Skroutz is needed for the API response. You call ReefAPI with your x-api-key header, and the playground can run live examples before you create a production key.
How fresh is the Skroutz data?
The page example is captured from a live search call, and production requests fetch live data through ReefAPI rather than a static sample.
How many credits does the Skroutz API use?
Skroutz actions currently cost 1 credit per successful call. Failed or blocked calls are free, and all APIs draw from one credit pool.
Can I call Skroutz from an AI assistant or MCP client?
Yes. Connect ReefAPI once through MCP and your assistant can call skroutz actions with the same key, credit pool and JSON envelope used by normal REST requests.