# Kaspi.kz Product Search Scraper — Prices, Sellers & Ratings (`yadroo/kaspi-kz-products`) Actor

Kaspi.kz marketplace products for price monitoring, assortment research and AI agents: search or browse any category in 320 cities, filter by brand, merchant, price and rating. Price, installment, rating, reviews, merchant offers with min/max price, optional specs.

- **URL**: https://apify.com/yadroo/kaspi-kz-products.md
- **Developed by:** [Samat Makatov](https://apify.com/yadroo) (community)
- **Categories:** E-commerce, Automation, Lead generation
- **Stats:** 8 total users, 1 monthly users, 94.2% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.70 / 1,000 result items

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

Structured product data from **kaspi.kz**, Kazakhstan's largest marketplace: search by text or browse any of 1 700+ catalogue categories in any of 320 cities, filter by brand, merchant, price, rating and freshness, and get price, bonus, installment terms, rating and review counts for every product. Optional add-ons return the **merchant offers** (how many sellers, min/max price, cheapest sellers with rating and delivery speed), the **rating breakdown** with latest reviews, and the **full specification table** from the product page. Built for price monitoring, assortment and competitor research, sellers entering Kaspi, and AI shopping agents.

**One run can cover a whole market:** several queries and categories × many cities (presets for the 10 biggest cities, all 20 regional centres, a whole region or all 320 cities); a list of **your own product links** checked in every city; your **shop's position** among all sellers (rank, gap to the cheapest competitor); and **change tracking** between scheduled runs (new, cheaper, pricier, out of stock, removed) so a daily schedule outputs only what changed.

Uses the site's own JSON endpoints — no browser, no API key. kaspi.kz blocks datacenter IPs, so on the Apify platform the run goes through Apify **residential proxy (Kazakhstan)**, which is on by default.

### Use cases

- **Price monitoring of your SKUs** — paste product links into `productUrls`, pick cities, schedule daily with `trackChanges` + `onlyChanges`: you get only products whose price or number of sellers moved.
- **Seller repricing input** — `myMerchantId` shows, for every product and city, your price, your rank among all sellers and how much cheaper the cheapest competitor is. With `merchantId` set to the same id it covers your whole storefront.
- **Regional price comparison** — one query in `cityIds: ["@regional-centers"]` → the same products in 20 cities with price, delivery speed and sellers per city; every row has `region`.
- **Price monitoring by search** — track the cheapest offer and number of sellers every day (`queries` / `categories` + `brand`, `includeOffers: true`).
- **Competitor / merchant intelligence** — list everything a given merchant sells (`merchantId`) with prices and ratings.
- **Assortment research before entering Kaspi** — browse a category sorted by rating, see how many products, reviews and sellers each niche has (`saveFacets: true` gives the full facet counts).
- **New-arrival alerts** — `sort: "newest"` + `sinceDays: 1` on a category, scheduled daily; `maxPages` sets how deep the run looks for them (see **Limits**).
- **Product content & specs** — `detail: true` for the specification table, description and breadcrumbs (catalogue enrichment, AI agents).

### Input

Search needs at least one of `query` / `queries` / `category` / `categories`; product monitoring needs `productUrls`. All other fields are optional.

| Field | Type | Default | Allowed values / notes |
|---|---|---|---|
| `mode` | string | `search` | `search`, `products` (the `productUrls` in every city), `cities` / `categories` (reference lists, no scraping; `query` filters them). With only `productUrls` filled the run switches to `products` by itself. Any other value is refused by Apify before the run starts. |
| `queries` | string\[] | `[]` | Extra search texts; merged with `query`. |
| `categories` | string\[] | `[]` | Extra category codes; merged with `category`. Every query × category × city is one search (max 2 000 per run). |
| `productUrls` | string\[] | `[]` | kaspi product links or numeric ids. One row per product × city: city price, availability (`available`), rating, sellers with `includeOffers`. Products not sold in a city come back with `available: false`. |
| `cityIds` | string\[] | `[]` | Several cities: ids, codes, names, or presets `@top-10`, `@regional-centers`, `@region:<code>`, `@all` (see **Reference → Regions**). Overrides `cityId`. |
| `myMerchantId` | string | – | Your merchant id → `myPrice`, `myRank`, `sellersCount`, `cheapestCompetitorPrice`, `cheapestMerchantName`, `priceGapToCheapest`, `priceGapPct`, `isCheapest`, `myDeliveryDays` per product and city. The id is the `offers[].merchantId` value kaspi.kz shows — a number (`234005`) or a word (`Gadgetcity`); case and spaces do not matter. Products you do not sell keep the competitor columns and leave the `my*` ones empty. |
| `trackChanges` | boolean | `false` | Compare with the previous run of the same `monitorKey`; adds `changeType`, `previousPrice`, `priceChange`, `priceChangePct`, `previousOffersCount`, `offersCountChange`, `firstSeenAt`, `previousSeenAt`. |
| `monitorKey` | string | `default` | Separate history per monitor (stored in your account as key-value store `kaspi-monitor-<key>`). |
| `onlyChanges` | boolean | `false` | With `trackChanges`: skip unchanged products (they are not saved and not charged). The first run saves the baseline and outputs everything. |
| `includeRemoved` | boolean | `true` | With `trackChanges`: a `removed` row for products that disappeared — only when every search was read to its end and nothing failed. |
| `maxTotalItems` | integer | `10000` | Cap on dataset rows (= charged rows) for the whole run, `removed` rows included. Unchanged products skipped by `onlyChanges` do not count. |
| `maxConcurrency` | integer | `3` | 1–10 searches / product lookups at the same time. 6 is a good value for big multi-city runs (see **Limits**). |
| `query` | string | – | Free-text search as on kaspi.kz (Russian or English). |
| `category` | string | – | Category code or Russian title, e.g. `Smartphones`, `Notebooks`, `TVs`, `Tires`, `Шины`. See **Reference → Categories**. A near miss (`Smartfones`, `Notebook`) is corrected to the closest known code — the correction appears in the log and in the run status message. Codes we do not know are passed through with a warning. |
| `cityId` | string | `750000000` | kaspi city id, URL code (`almaty`, `nur-sultan`) or city name (Russian/English). See **Reference → Cities**. |
| `brand` | string\[] | `[]` | Manufacturer names as on kaspi.kz (`Apple`, `Samsung`). Several = OR. Server-side (`:manufacturerName:`). |
| `merchantId` | string | – | Only products of this merchant (`:allMerchants:`). Ids appear in `offers[].merchantId`. |
| `facets` | object | – | Any other kaspi facet `{code: value | [values]}`, e.g. `{"Smartphones*Internal memory size": "256 ГБ"}`. Discover codes with `saveFacets: true`. |
| `priceFrom` / `priceTo` | integer | – | Tenge, client-side. With `sort: cheapest` / `expensive` paging stops early. |
| `minRating` | number | – | 0–5, client-side. |
| `minReviews` | integer | – | Client-side. |
| `officialPartnerOnly` | boolean | `false` | Best offer from an official brand partner (client-side). |
| `sinceDays` | integer | – | Products first listed within N days (`createdAt`, client-side). Best with `sort: newest`. kaspi's "newest" order is often shuffled (see **Limits**): when it is, the scan reads `maxPages` pages and keeps every fresh product it finds, so `maxPages` decides how deep the run digs. |
| `sort` | string | `relevance` | `relevance`, `newest`, `cheapest`, `expensive`, `rating`, or the legacy values `priceAsc`, `priceDesc`. Any other value is refused by Apify before the run starts. |
| `maxItems` | integer | `50` | 1–1000 **per search** (query × category × city). kaspi returns 12 products per request. |
| `maxPages` | integer | `100` | 1–200 safety cap (matters when client-side filters reject most products). |
| `includeOffers` | boolean | `false` | +1 request/product: `offersCount`, `minOfferPrice`, `maxOfferPrice`, cheapest `offers[]`, `deliveryFacets`. |
| `offersLimit` | integer | `5` | 1–50 offers kept per product. |
| `includeReviewsSummary` | boolean | `false` | +1 request/product: rating distribution, positive/negative/with-photo counts, 3 latest reviews. |
| `detail` | boolean | `false` | +1 page/product: `specifications`, `specificationGroups`, `description`, `breadcrumbs`, gallery size, discount. |
| `saveFacets` | boolean | `false` | Save total, sort options, every facet with counts and the category tree to key-value store record `SEARCH_FACETS`. |
| `dedupe` | boolean | `true` | One row per product × city: skip products repeated across pages and found again by another query or category in the same city. `false` keeps every search's own row. |
| `fields` | string\[] | `[]` | Keep only these columns, in this order (empty = all), e.g. `["title", "price", "cityName", "url"]`. `id` and `cityId` (plus `changeType` with `trackChanges`) are always kept and come first unless you list them; mode `cities` always keeps `id`, `categories` keeps `code`. Case, spaces and `_` do not matter; a near miss with one candidate (`pric`) is read as it and an unknown name is ignored — both are named in the run status and `SUMMARY`. If none of the names exists, the run fails with the list of valid names (see **Output**). |
| `proxy` | object | Apify RESIDENTIAL, country KZ | Required on the Apify platform — kaspi.kz blocks datacenter IPs. |

Server-side vs client-side: kaspi's search API accepts category, brand, merchant and facet filters, but not arbitrary price/rating ranges — those are applied after download and the log tells you so. Nothing is silently ignored: unknown categories and cities produce warnings, and if kaspi applies a different category than requested the run warns.

### Reference

Run `{"mode": "cities"}` or `{"mode": "categories"}` to get these lists as a dataset (CSV/Excel/JSON) — every city with its region, every category with its parent and catalogue URL. `cities` returns all 320 rows, `categories` the 20 roots; add `query` to keep the rows where a word of any field starts with that text (`{"mode": "categories", "query": "tires"}` → every tyre category; `"шины"` → the tyre categories with «Шины» in the Russian title, not «Стиральные машины»). The complete lists are always saved, free of charge, to key-value store records `CITIES` and `CATEGORIES`.

#### Regions and city presets (`cityIds`)

| Preset | Cities |
|---|---|
| `@top-10` | Almaty, Astana, Shymkent, Karaganda, Aktobe, Taraz, Pavlodar, Oskemen, Semey, Atyrau |
| `@regional-centers` | 20: Astana, Almaty, Shymkent + Kokshetau, Aktobe, Taldykorgan, Atyrau, Oral, Taraz, Karaganda, Zhezkazgan, Kostanay, Kyzylorda, Aktau, Turkestan, Pavlodar, Petropavl, Oskemen, Semey, Konaev |
| `@region:<code>` | Every kaspi city of one region (codes below) |
| `@all` | All 320 cities (combine with a small `maxItems`) |

Every row carries `region`. kaspi city ids are KATO codes, whose first two digits name the region in the pre-2022 division, so Zhetysu is inside 19, Ulytau inside 35 and Abai inside 63:

| Code | Region | Code | Region |
|---|---|---|---|
| `71` | Астана (city) | `35` | Карагандинская обл. и Улытау |
| `75` | Алматы (city) | `39` | Костанайская обл. |
| `79` | Шымкент (city) | `43` | Кызылординская обл. |
| `11` | Акмолинская обл. | `47` | Мангистауская обл. |
| `15` | Актюбинская обл. | `51` | Туркестанская обл. |
| `19` | Алматинская обл. и Жетысу | `55` | Павлодарская обл. |
| `23` | Атырауская обл. | `59` | Северо-Казахстанская обл. |
| `27` | Западно-Казахстанская обл. | `63` | Восточно-Казахстанская обл. и Абай |
| `31` | Жамбылская обл. | | |

#### Cities (`cityId`, `cityIds`)

Prices, stock and delivery differ by city. The most common ones:

| City | id | URL code |
|---|---|---|
| Алматы (Almaty) | `750000000` | `almaty` |
| Астана (Astana) | `710000000` | `nur-sultan` |
| Шымкент (Shymkent) | `511010000` | `shymkent` |
| Караганда (Karaganda) | `351010000` | `karaganda` |
| Актобе (Aktobe) | `151010000` | `aktobe` |
| Тараз (Taraz) | `311010000` | `taraz` |
| Павлодар (Pavlodar) | `551010000` | `pavlodar` |
| Усть-Каменогорск (Ust-Kamenogorsk) | `631010000` | `ust-kamenogorsk` |
| Семей (Semey) | `632810000` | `semey` |
| Атырау (Atyrau) | `231010000` | `atyrau` |
| Костанай (Kostanai) | `391010000` | `kostanai` |
| Кызылорда (Kyzylorda) | `431010000` | `kyzylorda` |
| Уральск (Uralsk) | `271010000` | `uralsk` |
| Петропавловск (Petropavlovsk) | `591010000` | `petropavlovsk` |
| Актау (Aktau) | `471010000` | `aktau` |
| Туркестан (Turkestan) | `512610000` | `turkestan` |
| Кокшетау (Kokshetau) | `111010000` | `kokshetau` |
| Талдыкорган (Taldykorgan) | `191010000` | `taldykorgan` |
| Экибастуз (Ekibastuz) | `552210000` | `ekibastuz` |
| Темиртау (Temirtau) | `352410000` | `temirtau` |
| Конаев (Капшагай) (Kapshagay) | `191610000` | `kapshagay` |
| Жезказган (Zhezkazgan) | `351810000` | `zhezkazgan` |

<details><summary>All 320 kaspi.kz cities</summary>

Абай (Алмат.обл) `195253200` · Абай (Караганд.обл) `353220100` · Абай (Турк.Обл.) `515433100` · Ават (Алм.Обл) `194033100` · Агадырь `356431100` · Айет `396430100` · Айтеке Би `434430100` · Айша-Биби (Жамб.Обл) `314033100` · Акжал (Кар.обл) `356435100` · Аккистау `234230100` · Акколь `113220100` · Акмол (Малиновка) `116630100` · Аксай `273620100` · Аксу (Павлод.обл) `551610000` · Аксу-Аюлы `356430100` · Аксукент `515230100` · Актау `471010000` · Актау (Караганд.обл.) `352431100` · Актобе `151010000` · Актогай (Абай.обл) `633441100` · Актогай (Кар.обл) `353630100` · Акшукур `475233100` · Алатау (Жетыген) `196837100` · Алга (Актюб.обл) `153220100` · Алдаберген `196433100` · Алмалы (Атырау. обл) `235637100` · Алматы `750000000` · Алтай `634820100` · Амангельды (Кост.обл.) `393430100` · Аманкарагай `393631100` · Аральск `433220100` · Аркабай `196253200` · Аркалык `391610000` · Аршалы `113430100` · Арысь `511610000` · Аса (Жамб.обл.) `314030100` · Астана `710000000` · Астраханка `113630100` · Асыката `514443100` · Атакент (Турк.обл.) `514459100` · Атбасар `113820100` · Атырау `231010000` · Аулиеколь `393630100` · Аухатты `314833100` · Аягоз `633420100` · Бадамша `154030100` · Байдибек бия `194043100` · Байконыр `431910000` · Байсеит (Алм.обл) `194071200` · Байсерке (Дмитриевка) `196847100` · Байтерек (Новоалексеевка) `194067100` · Бактыбай Жолбарысулы `196435100` · Балкашино `116430100` · Балпык Би `194830100` · Балхаш `351610000` · Батыр `475042100` · Бауржан Момышулы (Жамб.Обл.) `314230100` · Баутино `475235100` · Баянаул `553630100` · Бейнеу `473630100` · Белбулак `196235100` · Белоусовка `634037100` · Береке `195233100` · Бесагаш `196243100` · Бескарагай (Бурас) `633600000` · Бесколь `595030100` · Бозайгыр `116837100` · Боровской `395630100` · Бородулиха `633830100` · Ботакара `354030100` · Булаево `593620100` · Бурабай (Боровое) `117035100` · Бурыл `313635100` · Владимировка `395439100` · Габиден Мустафин (Караганд.обл.) `354081100` · Глубокое `634030100` · Гульдала `196249100` · Денисовка `394030100` · Державинск `115420100` · Деркуль `271000200` · Доскей `354031100` · Доссор `235235100` · Екпинды `196849200` · Енбекши (Талгарский район) `196255400` · Ерейментау `114600000` · Еркинкала `231045100` · Есик `194020100` · Есиль `114820100` · Жайнак (Комсомол) `196839200` · Жайрем `352035100` · Жаксы `115230100` · Жалагаш `433630100` · Жалтыр `113640100` · Жамбыл (Жамбыл.обл.) `314836100` · Жанаарка `354430100` · Жанакорган `434030100` · Жаналык `196247500` · Жанаозен `471810000` · Жанатас `316020100` · Жанашар `194047100` · Жангала `274030100` · Жансугуров `193230100` · Жапек Батыра `196833200` · Жаркент `195620100` · Жезказган `351810000` · Жезкент `633845100` · Железинка `554230100` · Жетыбай `474239100` · Жетысай `514420100` · Жибек Жолы (Акмол.обл.) `113433100` · Жибек Жолы (Шамалган) `195237100` · Жибек-Жолы (Туркестан.обл) `515247200` · Житикара `394420100` · Жолымбет (Акмол.обл.) `116839100` · Жосалы `434630100` · Заречное (Алм.обл.) `191633100` · Зачаганск `271035100` · Зеренда `115630100` · Индербор `234030100` · Иргели `195247100` · Иртышск `554630100` · Исаево `195233400` · Кабанбай (Алмат.Обл) `193459100` · Кабанбай батыр (Акмол. Обл) `116665100` · Казыгурт `514030100` · Кайнар (Жамбыл.обл.) `314853200` · Калбатау `634430100` · Калкаман (Павл.обл) `551655100` · Камысты `394830100` · Кандыагаш `154820100` · Карабалык `395030100` · Карабулак  (Турк. Обл.) `615253100` · Карабулак (Алм.Обл.) `196253400` · Карабулак (Талдыкорган) `196430100` · Караганда `351010000` · Каражал `352010000` · Каражар (Акмол.Обл) `116648700` · Караой `196843100` · Караоткель `116648100` · Карасу (Кост.обл) `395230100` · Каратау `316220100` · Карауылкельды (Байганин) `153630100` · Каргалы (Фабричный) `194279100` · Каркаралинск `354820100` · Карнак `512039100` · Каскелен `195220100` · Касыма Кайсенова `636230100` · Катарколь `117057100` · Качар `392435100` · Кашыр (Теренколь) `554830100` · Кеген `195830100` · Кеменгер `556049100` · Кенен `314837100` · Кенжеколь `551043100` · Кенкияк `155639100` · Кентау `612010000` · Кобда `154230100` · Коккайнар (Илийский район) `196833300` · Кокозек `195233500` · Кокпекты (Абай.обл.) `635030100` · Коксай `195247400` · Коксайек `515847100` · Кокшетау `111010000` · Кольди `195255400` · Конаев (Капшагай) `191610000` · Кордай `314851205` · Костанай `391010000` · Косшы `116651100` · Коянды `116645100` · Красный Яр `633851100` · Кулан `315030100` · Кульсары `233620100` · Курмангазы (Ганюшкино) `231035300` · Курминское `353263100` · Курчатов `632210000` · Курчум `635230100` · Курык `474230100` · Кушмурун `393633100` · Кушокы (Караганд.обл.) `354061100` · Кызылагаш (Жетысу. обл) `193265100` · Кызылорда `431010000` · Кызылту `196253500` · Ленгер `515820100` · Ленинский `551045100` · Лисаковск `392010000` · Майкаин `553655100` · Маканчи `636473100` · Макат `235230100` · Макинск `114020100` · Мамбет (Жетысу. обл) `194847100` · Мамлютка `595220100` · Мангистау `475030100` · Маржанбулак `153247100` · Мартук `154630100` · Масанчи (Жамбыл.обл.) `314847100` · Махамбет `235630100` · Мерей `195255500` · Мерке `315430100` · Мойылды `551047100` · Мойынкум `315630100` · Молодёжный `355657100` · Мукур `234847100` · Мухаметжан Туймебаева `196833100` · Мынбаево `194257100` · Мырзакент `514481100` · Мырзатай `313646100` · Нарынкол `195855100` · Новая Бухтарма `634835100` · Новоишимское (СКО) `596630100` · Новопокровка (Абай. обл) `633859100` · Нура (Караганд.обл.) `355230100` · Орангай `512649100` · Осакаровка `355630100` · Отар `314851100` · Отеген батыр `196830100` · Павлодар `551010000` · Павлодарское `551041100` · Панфилово `196253100` · Петровка (Караганд.обл.) `354067100` · Петропавловск `591010000` · Подстепное `276253100` · Прапорщиково `634049100` · Пресновка `594630100` · Приозeрск `352110000` · Райымбек `195253100` · Риддер `156420100` · Родина `116661100` · Рудный `392410000` · Сагиз `234853100` · Саймасай `194075100` · Саксаульский `433257100` · Самарское `635063100` · Сарань `352210000` · Сарканд `196020100` · Сарыагаш `515420100` · Сарыбулак (Жамбыл.обл.) `314853100` · Сарыжаз (Алм.обл) `195859100` · Сарыкемер `313630100` · Сарыколь `396230100` · Сарыозек `194630100` · Сатпаев `352310000` · Саудакент `316033100` · Саумалколь `593230100` · Семей `632810000` · Сергеевка `595620100` · Серебрянск `634821100` · Смирново `595830100` · Солнечный (Павл.обл.) `552253100` · Сортобе `314854100` · Станционный (Акмол.обл.) `111037100` · Староикан `512635100` · Степногорск `111810000` · Степняк (Акмол.обл.) `114520100` · Таврическое `636269100` · Тайтобе `111600100` · Тайынша `596020100` · Талапкер (Акмол.Обл) `116672100` · Талгар `196220100` · Талдыкорган `191010000` · Талкайран `231053300` · Тараз `311010000` · Тасбогет `433259700` · Таскала (ЗКО) `276030100` · Текели `192610000` · Темирлановка `514630100` · Темиртау `352410000` · Теренозек `434830100` · Тобыл (Затобольск) `395430100` · Толе би (Жамбыл. обл) `316630100` · Топар `353285100` · Торткуль `514483400` · Туздыбастау `196245100` · Туймекент `313653100` · Турар Рыскулов `516030100` · Тургызба `233635100` · Туркестан `512610000` · Тущыкудык `234245100` · Тюлькубас `516063100` · Уварово `634049400` · Узунколь `396630100` · Узынагаш `194230100` · Уральск `271010000` · Урджар `636430100` · Усть-Каменогорск `631010000` · Ушарал `353641300` · Уштобе `195020100` · Федоровка (Кост.Обл) `396830100` · Форт-Шевченко `475220100` · Хамита Ергалиева `234243100` · Хромтау `156020100` · Чапаев (ЗКО) `273230100` · Чапаево `196855100` · Черемшанка `634069100` · Чунджа `196630100` · Шалкар (Актюб.обл) `634643300` · Шамалган (Ушконыр) `195259100` · Шар (Чарск) `634421100` · Шарбакты `555259100` · Шардара `616420100` · Шахан `352835100` · Шахтинск `352810000` · Шаян `513630100` · Шелек `194083100` · Шемонаиха `636820100` · Шенгельды `191637100` · Шетпе `474630100` · Шидерты `552257100` · Шиели `117055900` · Шолаккорган `515630100` · Шортанды `116830100` · Шу `316621100` · Шубаркудук `155630000` · Шубарсу `514657100` · Шульбинск `632865100` · Шымкент `511010000` · Щучинск `117020100` · Экибастуз `552210000` · Эмба `154823100` · Юбилейное(Карг.Обл) `353249100` · Явленка `594230100`

</details>

#### Categories (`category`)

20 root categories and 1732 sub-categories are built in (level 2 and 3 of the kaspi.kz catalogue). Codes are case-insensitive; Russian titles work too. Any code from a catalogue URL `https://kaspi.kz/shop/c/<code>/` can be passed.

| Root code | Title | Sub-category codes (examples) |
|---|---|---|
| `Smartphones and gadgets` | Телефоны и гаджеты | `Phone accessories`, `Phone cases`, `Smartphones screen protection`, `Phone holders`, `Wireless chargers`, `Cables and adapters`, `Power banks`, `Cases for chargers and cables`, `Cooling systems for smartphones`, `Smartphone displays`, `Cell phone batteries`, `Stickers for phones`, `Smart lenses for smartphones`, `Magnifying screens for smartphones`, … (49 total) |
| `Computers` | Компьютеры | `Peripherals`, `Mice`, `Other peripherals`, `Keyboards`, `Computer cables and adapters`, `Mouse pads`, `USB Flash drives`, `Monitors`, `Memory cards`, `UPS`, `Storage devices`, `Webcams`, `Controllers for streaming`, `Notebooks and accessories`, … (83 total) |
| `Home equipment` | Бытовая техника | `Kitchen appliances`, `Stoves and grills`, `Mixers blenders and choppers`, `Other kitchen appliances`, `Kettles`, `Making desserts`, `Coffee machines and coffee makers`, `Food processors and grinders`, `Table stoves`, `Accessories for small kitchen appliances`, `Pumps for water`, `Multicooker and cooking equipment`, `Juicers`, `Toasters`, … (68 total) |
| `TV_Audio` | ТВ, Аудио, Видео | `Headphones`, `Audio`, `Portable audio`, `Professional audio`, `Headphone accessories`, `Home Audio and Hi-Fi`, `Cables and connectivity`, `Smart speakers`, `Microphone and speaker accessories`, `Photo_Video`, `Batteries and accumulators`, `Tripods`, `Ring lights`, `Studio light`, … (91 total) |
| `Car goods` | Автотовары | `Replacement parts`, `Engine`, `Autoeletrics`, `Car chassis`, `Car body parts`, `Car filters`, `Cooling system`, `Brake system`, `Transmission`, `Car interior parts`, `Steering`, `Fuel supply system`, `Car exhaust system`, `Air Intake Systems`, … (121 total) |
| `Beauty care` | Красота и здоровье | `Skin care`, `Creams`, `Makeup removers`, `Cotton pads and stems`, `Lotions`, `Facial masks`, `Makeup remover`, `Lip care products`, `Scrubs and peelings`, `Patches`, `Cosmetic tweezers`, `Matting napkins`, `Hair care`, `Hair accessories`, … (145 total) |
| `Child goods` | Детские товары | `Toys`, `Educational toys`, `Stuffed toys`, `Toy sets`, `Construction`, `Play vehicles`, `Dolls and accessories`, `Stress relief toys`, `Play mats for kids`, `Toy weapons and blasters`, `Remote control toys and accessories`, `Toy figures`, `Outdoor games`, `Toy robots and transformers`, … (57 total) |
| `Pharmacy` | Аптека | `Medications`, `Cold and flu`, `Stomach intestines liver`, `Inflammation and infections`, `Cardiovascular system`, `Obstetrics and gynecology`, `Antimicrobial drugs`, `Healing creams`, `Allergy`, `Boost immunity`, `Neurology`, `Vision`, `Disinfectants`, `Endocrinology`, … (117 total) |
| `Furniture` | Мебель | `Bedroom`, `Wardrobes`, `Beds`, `Bedroom mattresses`, `Bedroom sets`, `Bedroom dressers`, `Camping cots`, `Nightstands`, `Dressing tables`, `Living room`, `Sofas`, `Coffee tables`, `TV stands`, `Poufs`, … (72 total) |
| `Construction and repair` | Строительство, ремонт | `Power tools`, `Tooling equipment`, `Electrical tools`, `Measurement tools`, `Electric and gasoline saws`, `Spray guns`, `Tool storage`, `Welding equipment`, `Electric soldering irons and accessories`, `Nail and staple guns`, `Power tool sets`, `Pneumatic tools`, `Radio components`, `Plumbing`, … (112 total) |
| `Sports and outdoors` | Спорт, туризм | `Camping and hiking`, `Hiking`, `Camping`, `Camping lanterns and accessories`, `Tents and awnings`, `Camping knives and multitools`, `Camping burners heaters`, `Backpacks and bags`, `Optics`, `Metal detectors and accessories`, `Chargers for tourism`, `Fitness`, `Hand strengtheners`, `Fitness equipments`, … (155 total) |
| `Pet goods` | Товары для животных | `Cat goods`, `Wet cat food`, `Dry cat food`, `Toys for cats`, `Cat snacks`, `Cat scratching pads`, `Hygiene and care for animals`, `Cat litter`, `Shampoos and conditioners for animals`, `Pet underpads`, `Pet odour eliminators`, `Animal repellent sprays`, `Poop bags for pets`, `Pet serums and oils`, … (100 total) |
| `Leisure` | Досуг, книги | `Hobbies and crafts`, `Painting goods`, `Crafting goods`, `Modelling goods`, `Goods for sewing and embroidery`, `Scrapbooking goods`, `Knitting goods`, `Collecting and modeling`, `Decoupage goods`, `Books`, `Schoolbooks and study guides`, `Kids books`, `Fiction`, `Self-help literature`, … (65 total) |
| `Home` | Товары для дома и дачи | `Household goods`, `Home paper products`, `Cleaning tools`, `Bathroom and toilet accessories`, `Clothing care`, `Packaging materials`, `Shoes care`, `Accessories for kitchen sinks`, `Household bags`, `Household ropes`, `Lighters`, `Kitchenware`, `Kitchen accessories`, `Utensils for cooking`, … (81 total) |
| `Fashion` | Одежда | `Women fashion`, `Women underwear`, `Women t-shirts`, `Women leisurewear`, `Women outerwear`, `Women cardigans`, `Women suits and sport suits`, `Women pants`, `Women blouses and shirts`, `Women dresses`, `Women tanks and camis`, `Women skirts`, `Women sport suits`, `Women swimwear`, … (98 total) |
| `Shoes` | Обувь | `Women shoes`, `Women trainers`, `Women fashion slippers`, `Women flip flops`, `Women dress shoes`, `Women knee boots`, `Women boots`, `Women sandals`, `Women ballet pumps`, `Women moccasins`, `Women mules`, `Women ankle boots`, `Women safety shoes`, `Women dance shoes`, … (67 total) |
| `Fashion accessories` | Аксессуары | `Travel gear`, `Fashion handbags`, `Backpacks`, `Travel duffels`, `Wallets`, `Suitcases`, `Travel accessories`, `Passport holders`, `Suitcase covers`, `Hats and scarves`, `Fashion hats and caps`, `Fashion scarves`, `Fashion gloves and mittens`, `Watches`, … (37 total) |
| `Jewelry and Bijouterie` | Украшения | `Earrings bijouterie and jewelry`, `Imitation earrings`, `Earrings`, `Rings bijouterie and jewelry`, `Rings`, `Imitation rings`, `Bracelets bijouterie and jewelry`, `Bracelets`, `Imitation bracelets`, `Necklaces bijouterie and jewelry`, `Necklaces`, `Imitation necklaces`, `Jewelry and bijouterie sets`, `Jewelry sets`, … (43 total) |
| `Gifts and party supplies` | Подарки, товары для праздников | `New year decor`, `Electric string lights`, `New Year trees`, `Tree ornaments`, `New year decorations`, `Tinsel rain`, `Illuminated decorations`, `Hooks and accessories for garlands`, `New Year wreaths`, `Fir needle decorations`, `Artificial snow`, `Fireworks`, `Holiday decorations`, `Party balloons`, … (57 total) |
| `Office and school supplies` | Канцелярские товары | `Paper products`, `Exercise notebooks`, `Office paper`, `Paper notebooks`, `Envelope mailers`, `Memo sheets`, `Account books and journals`, `Posters`, `Drawing and copying paper`, `Document forms`, `Calendars`, `Flipchart pads`, `Writing Supplies`, `Pens and pen supplies`, … (114 total) |

#### Sort (`sort`)

| Value | kaspi.kz `sort` | Meaning |
|---|---|---|
| `relevance` | `(none)` | Popular (site default) |
| `newest` | `created-desc` | Newest first |
| `cheapest` | `price-asc` | Cheapest first |
| `expensive` | `price-desc` | Most expensive first |
| `rating` | `rating` | Highest rating |
| `priceAsc` | `price-asc` | Cheapest first (alias) |
| `priceDesc` | `price-desc` | Most expensive first (alias) |

#### Delivery speed (`deliveryDuration`, `offers[].deliveryDuration`)

`EXPRESS`, `TODAY`, `TOMORROW`, `TILL_2_DAYS`, `TILL_5_DAYS`, `TILL_7_DAYS`, `OTHER`

### Examples

**Your products in every regional centre, only what changed since yesterday** (schedule daily)

```json
{ "productUrls": ["https://kaspi.kz/shop/p/apple-iphone-15-128gb-nanosim-esim-chernyi-113137790/", "176684789"], "cityIds": ["@regional-centers"], "includeOffers": true, "trackChanges": true, "monitorKey": "my-skus", "onlyChanges": true }
```

**My shop vs competitors — rank and gap to the cheapest seller for my whole storefront in Almaty and Astana**

```json
{ "category": "Smartphones and gadgets", "merchantId": "234005", "myMerchantId": "234005", "cityIds": ["almaty", "astana"], "maxItems": 200 }
```

**Regional price comparison — three models in the 10 biggest cities**

```json
{ "queries": ["iphone 16 128", "galaxy s25", "redmi note 14"], "category": "Smartphones", "cityIds": ["@top-10"], "sort": "cheapest", "maxItems": 5 }
```

**Reference lists — all tyre categories, all cities of Karaganda region**

```json
{ "mode": "categories", "query": "tires" }
```

```json
{ "mode": "cities", "query": "Караганд" }
```

**Daily price monitor — iPhone 17 Pro in Almaty with sellers**

```json
{ "query": "iphone 17 pro", "category": "Smartphones", "brand": ["Apple"], "cityId": "almaty", "sort": "cheapest", "includeOffers": true, "offersLimit": 10, "maxItems": 30 }
```

**Niche research — best-rated robot vacuums with review breakdown**

```json
{ "query": "робот пылесос", "sort": "rating", "minReviews": 50, "includeReviewsSummary": true, "saveFacets": true, "maxItems": 100 }
```

**Competitor catalogue — everything one merchant sells in Astana**

```json
{ "category": "Smartphones and gadgets", "merchantId": "441010", "cityId": "710000000", "maxItems": 500 }
```

**New arrivals alert — tyres added in the last 3 days**

```json
{ "category": "Tires", "sort": "newest", "sinceDays": 3, "maxItems": 60, "maxPages": 15 }
```

New products are scattered over kaspi's "newest" pages, so `maxPages` decides how deep the run digs (≈ 2–5 s per page): 15 pages ≈ 1 minute.

**Catalogue enrichment — Samsung smartphones from 100 000 ₸ with full specs**

```json
{ "category": "Smartphones", "brand": ["Samsung"], "priceFrom": 100000, "sort": "cheapest", "detail": true, "maxItems": 50 }
```

### Output

One dataset item per product (per product × city in multi-city runs). Rows are saved as each search page or product lookup is done, a few seconds apart, so rows of different searches and cities can interleave — sort by `cityId`, `query` and `position` when you need a fixed order. `fields` keeps only the columns you list. Every run also writes key-value store record `SUMMARY` (rows delivered, why the run stopped, failed or skipped searches, filter counts, input notes). Dataset views: **Overview**, **Merchant offers**, **Ratings**, **Price changes**, **My seller position**, **Reference**. Example (trimmed; `includeOffers`, `includeReviewsSummary` and `detail` on; real run, Astana):

```json
{
  "id": "169791776",
  "title": "Samsung Galaxy A07 6 ГБ/128 ГБ черный + сетевое зарядное устройство Samsung EP-T2510NBEGRU",
  "brand": "Samsung",
  "url": "https://kaspi.kz/shop/p/samsung-galaxy-a07-6-gb-128-gb-chernyi-setevoe-zarjadnoe-ustroistvo-samsung-ep-t2510n…-169791776/?c=710000000",
  "price": 104990, "salePrice": 104990, "priceMinusBonus": 101841, "bonusKzt": 3149, "currency": "KZT",
  "creditMonthlyPrice": 8750, "installmentMonths": 12, "loanAvailable": true,
  "rating": 5, "reviewsCount": 12,
  "categoryPath": ["Телефоны и гаджеты", "Смартфоны"], "categoryCode": "Smartphones",
  "createdAt": "2026-06-20T09:24:57.359Z", "deliveryDuration": "TODAY", "isBrandOfficialPartner": false,
  "bestMerchantId": "10637013", "image": "https://resources.cdn-kaspi.kz/img/m/p/p38/pe1/152760318.jpg?format=preview-large",
  "position": 31, "searchTotal": 907, "cityId": "710000000", "cityName": "Астана", "category": "Smartphones",
  "fetchedAt": "2026-09-13T08:11:53.744Z",
  "offersCount": 3, "minOfferPrice": 104990, "maxOfferPrice": 115000,
  "offers": [{ "merchantId": "10637013", "merchantName": "iNOVА", "price": 104990, "merchantRating": 4.9, "merchantReviews": 237, "deliveryDuration": "TILL_2_DAYS", "kaspiDelivery": true }],
  "ratingDistribution": { "1": 0, "2": 0, "3": 0, "4": 0, "5": 21 }, "reviewsTotal": 21, "reviewsNegative": 0, "reviewsWithPhotos": 7,
  "latestReviews": [{ "date": "06.09.2026", "rating": 5, "text": "Телефон уақытылы жеткізілді…" }],
  "specifications": { "4G (LTE)": "да", "Операционная система": "Android 15", "Тип SIM-карты": "dual nano SIM" },
  "breadcrumbs": ["Kaspi Магазин", "Телефоны и гаджеты", "Смартфоны"], "maxQuantity": 3
}
```

| Field | Description |
|---|---|
| `id`, `url`, `title`, `brand` | kaspi product id, product URL (with city), title, manufacturer |
| `price`, `salePrice`, `priceMinusBonus`, `bonusKzt`, `currency` | Best price in ₸ for the city, sale price, price after Kaspi bonus, bonus amount |
| `creditMonthlyPrice`, `installmentMonths`, `loanAvailable` | Kaspi installment / credit terms |
| `rating`, `reviewsCount` | Average rating 0–5 and number of reviews |
| `categoryPath`, `categoryCode`, `categoryId` | Category breadcrumb (Russian), code, id |
| `createdAt` | When the product card first appeared on kaspi.kz |
| `deliveryDuration` | Fastest delivery option of the best offer (see Reference) |
| `isBrandOfficialPartner`, `hasVariants`, `stickers` | Official partner flag, colour/size variants, promo stickers |
| `bestMerchantId`, `majorMerchants` | Merchant behind the shown price; large merchants selling it |
| `image`, `images`, `unit` | Preview images, unit of sale |
| `position`, `searchTotal` | Rank in the result list; total products matching the search (market size) |
| `cityId`, `cityName`, `region`, `query`, `category`, `fetchedAt` | Echo of the search scope (region of the city) and fetch timestamp |
| `available` | `false` when a product from `productUrls` is not sold / not delivered in that city (price fields are then null) |
| `offersCount`, `minOfferPrice`, `maxOfferPrice`, `fastestDeliveryDays`, `offers[]`, `deliveryFacets` | With `includeOffers` — sellers, spread, fastest delivery, cheapest offers (merchant id/name, price, rating, reviews, delivery speed/date, `deliveryDays`, `deliveryCost`, `freeDeliveryFrom`, `postomat`) |
| `myPrice`, `myRank`, `sellersCount`, `cheapestPrice`, `cheapestMerchantName`, `cheapestCompetitorPrice`, `priceGapToCheapest`, `priceGapPct`, `isCheapest`, `myDeliveryDays` | With `myMerchantId` — your position among **all** sellers in that city (ties share a rank; nulls when you do not sell the product) |
| `changeType`, `previousPrice`, `priceChange`, `priceChangePct`, `previousOffersCount`, `offersCountChange`, `firstSeenAt`, `previousSeenAt` | With `trackChanges` — `changeType` is `new`, `priceUp`, `priceDown`, `unchanged`, `outOfStock`, `backInStock` or `removed`; the run summary is in key-value store record `CHANGES` |
| `ratingGlobal`, `ratingDistribution`, `reviewsTotal`, `reviewsWithComments`, `reviewsPositive`, `reviewsNegative`, `reviewsWithPhotos`, `latestReviews[]` | With `includeReviewsSummary` |
| `specifications`, `specificationGroups`, `description`, `breadcrumbs`, `galleryCount`, `discount`, `priceBeforeDiscount`, `maxQuantity`, `aiGeneratedDescription` | With `detail` |
| `offersError`, `reviewsError`, `detailError` | Present only when that add-on request failed for the product, or was not made because the run was stopping (spending limit, run timeout) — the item is still saved |
| `unavailableReason` | Products mode: why a product is `available: false` in that city |

### Use it from code / agents

```bash
curl -X POST "https://api.apify.com/v2/acts/yadroo~kaspi-kz-products/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"query":"iphone 17 pro","cityId":"almaty","sort":"cheapest","maxItems":20}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/kaspi-kz-products').call({ category: 'Tires', sort: 'newest', sinceDays: 3 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/kaspi-kz-products").call(run_input={"query": "робот пылесос", "includeOffers": True, "maxItems": 50})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

MCP: add `https://mcp.apify.com` to Claude / Cursor / any MCP client and call the `yadroo/kaspi-kz-products` tool with the same JSON input.

### Pricing

Pay per event: **$0.005 per run start + $0.001 per dataset row** on the Free plan; Bronze $0.0009, Silver $0.0008, Gold and above $0.0007 per row. The start event is the same on every plan. Platform usage and the residential proxy traffic are included in the price.

Every dataset row counts as one result: a product (one per city in multi-city runs), a `products`-mode row with `available: false` for a product that is not sold in a city, a `removed` row of change tracking, and a city or category row of the reference modes. Unchanged products skipped by `onlyChanges` are not saved and not charged; the full reference lists in key-value store records `CITIES` and `CATEGORIES` are free.

Typical runs (Free plan): 50 products ≈ $0.055; 500-product category snapshot ≈ $0.505. `includeOffers`, `includeReviewsSummary` and `detail` do not change the per-row price but add one request per product each, so the run takes longer.

Your **maximum cost per run** is respected: the run stops reading when the rows on their way would exceed it, keeps every row already saved and ends with the status "Stopped at your spending limit: N rows delivered".

### Limits & FAQ

- **Proxy** — kaspi.kz rejects datacenter IPs. Keep the default residential proxy (country KZ). A 403 or a non-JSON answer is asked again through another IP, then fails that search with a clear message instead of returning empty data. With your own proxy URLs (`proxyUrls`) the requests rotate over all of them.
- **Request pace and robots.txt** — product, offer and review data come from kaspi.kz's JSON endpoints under `/yml/`, which its robots.txt does not disallow. The same robots.txt asks for 10 s between requests (`Crawl-delay: 10`); this actor does not keep that delay — it runs 3 requests at a time by default (up to 10 with `maxConcurrency`), each through a rotating residential IP, with short pauses between pages and backoff on 429/5xx.
- **Rate limits (measured 23.09.2026 through Apify residential proxy, KZ)** — the proxy, not kaspi, is the bottleneck (~4 s per request). One product in all 320 cities: 468 s at `maxConcurrency` 3, 2.8 % of requests retried. 112 cities: 72 s at 6 (no retries), 59 s at 10 (5 % retried). Search in all 320 cities at 6: 339 s. 1 080 products with sellers (1 223 requests) at 6: 17 min, 3.5 % retried. No 403 blocks in any test. 429/5xx are retried with backoff; under load kaspi occasionally answers without the product card, so a product-mode miss is re-checked after 2 s before it is reported as not sold (`unavailableReason`).
- **Depth** — up to 1000 products per search (12 per page), up to 2 000 searches or product × city lookups and `maxTotalItems` rows per run. Split large categories by brand or sub-category.
- **Long runs and the timeout** — rows are saved as they are read, not at the end. Near the run timeout the actor stops starting new requests (15 % of the timeout before it, at most 90 s), saves what it has read and ends SUCCEEDED with "Stopped before the run timeout: N rows saved"; raise the timeout or split the job for the rest. At the default 3 parallel requests one hour holds roughly 2 000 product × city lookups (about half that with `includeOffers`) or 10 000 search rows; `maxConcurrency` 6 is about twice as fast.
- **Batches are fault-tolerant** — searches run 3 at a time by default; if one city or category fails (e.g. an unknown code), the others are still saved, the status message says how many failed and the reasons are in key-value store record `ERRORS`. The run fails only when every search failed and nothing was saved.
- **Change tracking is honest** — a product is reported `removed` only when every search in the run was read to its end, nothing failed and the run was not cut short by your spending limit, the timeout or `maxTotalItems`; a search cut by `maxItems` would otherwise make products look removed. The history remembers only rows that were saved: a change that did not fit under your spending limit is reported again by the next run. Use `productUrls` for exact SKU monitoring.
- **Price and rating filters** are client-side (kaspi's API does not support ranges); combine with the matching sort so paging stops early. When client-side filters drop products, the run status message says how many and why — a run that ends with 0 products always explains itself.
- **"Newest" is not sorted by date** — kaspi's `created-desc` returns the recently listed products in shuffled order: measured on `Tires` (44 335 products, 27.09.2026) all 15 pages held the same age spread and the five products younger than 3 days sat at positions 35, 79, 81, 133 and 136. So `sinceDays` never stops at the first old pages when the order is shuffled (the log says when it is); it reads until `maxItems` or `maxPages`, whichever comes first. Give a big category enough pages — 15 pages ≈ 180 products ≈ 1 minute — and `maxItems` keeps the cost down; on a search that really comes back newest-first the scan still stops as soon as the window is behind it.
- **Errors are readable** — invalid input (no `query` and no `category`, `priceFrom` > `priceTo`, `fields` without a single known column) and a blocked proxy end the run with the reason in the run's status message, not just in the log. An off-list `mode` or `sort` value is refused by Apify before the run starts, with the list of allowed values.
- **`detail` mode** keeps what it has: if kaspi starts refusing product pages mid-run, the products are still saved (with `detailError`) instead of failing the whole run. A product page is about 80 KB against about 1 KB of search data per product (measured 02.10.2026), so detail runs are slower: 30 smartphones took 74 s with `detail` and 11 s without, at the default 3 parallel requests.
- **Freshness** — live data at run time; prices differ by city and change during the day.
- **`myMerchantId` shows your assortment as it is** — a search returns every product that matches, including the ones your shop does not sell (bundles, Dual-SIM variants, colours you dropped), so the `my*` columns are empty for those rows while `sellersCount`, `cheapestPrice` and `cheapestMerchantName` still describe the market. The status message says how many of the rows you sell, and a run where your id matches no offer at all warns that the id may be mistyped. Add `merchantId` with the same id to list only your own storefront.
- **Phone numbers of merchants** are not published by kaspi.kz and are not collected.
- **Reviews and specs are fetched once per product** in multi-city runs (they do not depend on the city); prices, sellers and delivery are per city.

***

Made by **Yadroo**. Sibling actors: [krisha-kz](https://apify.com/yadroo/krisha-kz) (real estate), [kolesa-kz](https://apify.com/yadroo/kolesa-kz) (cars), [hh-kz-vacancies](https://apify.com/yadroo/hh-kz-vacancies) (jobs), [autoscout24-cars](https://apify.com/yadroo/autoscout24-cars) (EU cars).

# Actor input Schema

## `mode` (type: `string`):

`search` — products matching query/category in each city. `products` — the exact products from `productUrls` in each city (price, availability, sellers). `cities` / `categories` — reference lists for picking `cityIds` / `categories` values, no scraping: `cities` gives all 320 cities with regions, `categories` the 20 root categories; `query` keeps the rows where a word starts with that text (e.g. "tires", "Караганд"), and the full lists are always saved free to key-value store records CITIES / CATEGORIES. With only `productUrls` filled the run switches to `products` by itself.

## `query` (type: `string`):

Free-text search as typed into the kaspi.kz search box (Russian or English, brand + model works best). Leave empty to browse a whole `category`.

## `queries` (type: `array`):

Several searches in one run (each is combined with every category and city). Example: \["iphone 16", "galaxy s25", "redmi note 14"].

## `category` (type: `string`):

kaspi.kz category code (the English code in the catalogue URL https://kaspi.kz/shop/c/<code>/), e.g. "Smartphones", "Notebooks", "TVs", "Tires", "Home equipment", "Beauty care". Case-insensitive; Russian titles are accepted ("Смартфоны", "Шины"). 20 root categories and 1 732 sub-categories are built in (README → Reference). Unknown codes are passed through with a warning.

## `categories` (type: `array`):

Several category codes in one run, e.g. \["TVs", "Refrigerators", "Шины"]. Run mode `categories` once to get every valid code.

## `productUrls` (type: `array`):

kaspi.kz product links (https://kaspi.kz/shop/p/apple-iphone-15-128gb-…-113137790/) or numeric ids. Each product is looked up in every city of `cityIds` — one row per product × city with the city's price, availability, rating and (with includeOffers) sellers. Up to 2 000 product × city pairs per run.

## `cityId` (type: `string`):

Delivery city — prices and availability are city-specific. Accepts the kaspi city id (750000000 Almaty, 710000000 Astana, 511010000 Shymkent, 351010000 Karaganda, 151010000 Aktobe…), the URL code ("almaty", "nur-sultan", "shymkent") or the city name in Russian/English. All 320 cities are in README → Reference.

## `cityIds` (type: `array`):

Several cities in one run — ids, codes or names ("Алматы", "astana", "511010000") and presets: `@top-10` (10 biggest cities), `@regional-centers` (20: Astana, Almaty, Shymkent + every regional capital), `@region:35` (all kaspi cities of one region by KATO code, see README → Regions), `@all` (all 320). Overrides `cityId`. Every row carries cityId, cityName and region.

## `myMerchantId` (type: `string`):

For Kaspi sellers: your merchant id (Kaspi seller cabinet → profile, or `offers[].merchantId` in this actor's output). Every product then gets myPrice, myRank among all sellers in that city (1 = cheapest), sellersCount, cheapestCompetitorPrice, priceGapToCheapest (₸ and %), isCheapest. Combine with `merchantId` (same id) to check your whole storefront. Fetches all sellers per product (+1–5 requests).

## `brand` (type: `array`):

Manufacturer names exactly as shown on kaspi.kz ("Apple", "Samsung", "Xiaomi"). Several = OR. Maps to `:manufacturerName:<brand>`.

## `merchantId` (type: `string`):

Only products sold by this merchant (kaspi merchant id such as "441010" — visible in the site URL after choosing a seller in the «Продавцы» filter, or in this actor's `offers[].merchantId` output). Maps to `:allMerchants:<id>`.

## `priceFrom` (type: `integer`):

Minimum product price in tenge (client-side).

## `priceTo` (type: `integer`):

Maximum product price in tenge (client-side). Combine with `sort: cheapest` so the run stops as soon as prices exceed the limit.

## `minRating` (type: `number`):

Keep only products rated at least this (0–5, client-side).

## `minReviews` (type: `integer`):

Keep only products with at least this many reviews (client-side).

## `officialPartnerOnly` (type: `boolean`):

Keep only products whose best offer comes from an official brand partner (client-side).

## `sinceDays` (type: `integer`):

Keep only products first listed on kaspi.kz within the last N days (uses `createdTime`; client-side). Use with `sort: newest` for cheap new-arrival monitoring.

## `facets` (type: `object`):

Any additional kaspi facet as {code: value | \[values]}, copied from the site's `q=` URL parameter, e.g. {"Smartphones*Internal memory size": "256 ГБ", "Smartphones*Colour": \["черный", "белый"]}. Run once with `saveFacets: true` to see every facet code and value available for your search.

## `trackChanges` (type: `boolean`):

Remember every product × city under `monitorKey` (a named key-value store in your account) and add changeType (new / priceUp / priceDown / unchanged / outOfStock / backInStock / removed), previousPrice, priceChange, priceChangePct, offersCountChange, firstSeenAt. The first run saves the baseline. A summary goes to key-value store → CHANGES.

## `monitorKey` (type: `string`):

Name of this monitor — use a different key for each schedule/task so their histories do not mix (e.g. "iphones-almaty", "my-shop"). Stored as key-value store `kaspi-monitor-<key>`.

## `onlyChanges` (type: `boolean`):

With trackChanges: save only new, cheaper, pricier, out-of-stock, back-in-stock and removed products — unchanged ones are skipped (and not charged). Ideal for alerts.

## `includeRemoved` (type: `boolean`):

With trackChanges: add a row (changeType "removed") for each product seen last time but gone now. Only reported when every search in the run was read to its end (not cut by maxItems/maxPages) and nothing failed, so a capped search never looks like a sell-out.

## `sort` (type: `string`):

Result order as on kaspi.kz. Legacy values priceAsc/priceDesc are still accepted.

## `maxItems` (type: `integer`):

Stop each search (query × category × city) after this many products. kaspi.kz returns 12 products per request, so 1000 items ≈ 84 requests.

## `maxTotalItems` (type: `integer`):

Cap on dataset rows (each one is charged) for the whole run, across all searches / products / cities and change-tracking `removed` rows. Unchanged products skipped by onlyChanges do not count.

## `maxPages` (type: `integer`):

Safety cap on search pages (12 products each). Matters when client-side filters reject most products.

## `includeOffers` (type: `boolean`):

For each product also fetch the offer list: number of sellers, min/max offer price and the cheapest `offersLimit` merchants with rating, review count and delivery speed (+1 request per product).

## `offersLimit` (type: `integer`):

How many cheapest merchant offers to keep per product when `includeOffers` is on.

## `includeReviewsSummary` (type: `boolean`):

Fetch the rating breakdown (1–5 star counts, positive/negative/with-photo totals) and the 3 latest review texts (+1 request per product).

## `detail` (type: `boolean`):

Open each product page and add the full specification table, description text, breadcrumbs and gallery size (+1 HTML request per product, ~1 s each).

## `saveFacets` (type: `boolean`):

Store the search metadata (total, sort options, all facets with counts, category tree) to the key-value store record SEARCH\_FACETS — useful to discover valid brand/facet values.

## `dedupe` (type: `boolean`):

Skip products already seen in this run (kaspi sometimes repeats items across pages).

## `maxConcurrency` (type: `integer`):

How many searches / product lookups run at the same time. 3 is safe; higher is faster on big multi-city runs but kaspi.kz answers bursts with 429 (retried automatically) — see README → Limits for measured numbers.

## `fields` (type: `array`):

Keep only these columns, in this order (empty = every column), e.g. \["title", "price", "cityName", "url"]. Names as in README → Output. `id` and `cityId` (plus `changeType` with trackChanges) are always kept and come first unless you list them; mode "cities" always keeps `id`, mode "categories" `code`. Case, spaces and '\_' do not matter; a near miss with one candidate ("pric") is read as it and an unknown name is ignored — both are reported in the run status. If none of the names exists, the run fails with the list of valid names.

## `proxy` (type: `object`):

kaspi.kz blocks datacenter IPs, so Apify RESIDENTIAL proxy (Kazakhstan) is on by default. Switch off only when running from a whitelisted/local network.

## Actor input object example

```json
{
  "mode": "search",
  "query": "iphone 15",
  "queries": [],
  "categories": [],
  "productUrls": [],
  "cityId": "750000000",
  "cityIds": [],
  "brand": [],
  "officialPartnerOnly": false,
  "trackChanges": false,
  "monitorKey": "default",
  "onlyChanges": false,
  "includeRemoved": true,
  "sort": "relevance",
  "maxItems": 50,
  "maxTotalItems": 10000,
  "maxPages": 100,
  "includeOffers": false,
  "offersLimit": 5,
  "includeReviewsSummary": false,
  "detail": false,
  "saveFacets": false,
  "dedupe": true,
  "maxConcurrency": 3,
  "fields": [],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "KZ"
  }
}
```

# Actor output Schema

## `products` (type: `string`):

No description

## `overview` (type: `string`):

No description

## `summary` (type: `string`):

No description

## `facets` (type: `string`):

No description

## `changes` (type: `string`):

No description

## `errors` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "query": "iphone 15",
    "queries": [],
    "categories": [],
    "productUrls": [],
    "cityIds": [],
    "brand": [],
    "fields": [],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "KZ"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yadroo/kaspi-kz-products").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "query": "iphone 15",
    "queries": [],
    "categories": [],
    "productUrls": [],
    "cityIds": [],
    "brand": [],
    "fields": [],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "KZ",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("yadroo/kaspi-kz-products").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "query": "iphone 15",
  "queries": [],
  "categories": [],
  "productUrls": [],
  "cityIds": [],
  "brand": [],
  "fields": [],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "KZ"
  }
}' |
apify call yadroo/kaspi-kz-products --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yadroo/kaspi-kz-products"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/pgAEcoygkDCOyTHRw/builds/My0LJTAYWZowamTfH/openapi.json
