# Kolesa.kz Scraper — Kazakhstan Car Listings (`yadroo/kolesa-kz`) Actor

Car ads from kolesa.kz, the largest auto classifieds in Kazakhstan: filter by make/model, city or region, year, price, mileage, body, fuel, gearbox, drive, color, customs status, dealers/private, credit.

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

## Pricing

from $2.10 / 1,000 listings

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 car ads from **kolesa.kz**, the largest auto classifieds site in Kazakhstan: any make and model, in any city, region, or listed from abroad. All main kolesa.kz filters are supported (year, price, monthly credit payment, mileage, engine volume, body, fuel, gearbox, drive, color, customs status, dealers, damaged cars…). Each item has price ₸, year, mileage, engine, publish date and view count. `detail: true` adds kolesa.kz's own **average market price** for the model, so you can see how far each car is priced above or below the market.

No browser, no API key — plain HTTP. kolesa.kz limits how fast one IP may read it, so big runs are slow by default; an optional **fast mode** (turn on a proxy) reads with up to 8 IPs at once at the same per-IP pace — see [Speed and pricing](#speed-and-pricing).

### Use cases

- **Dealer sourcing** — cars priced well below market: `detail: true`, then keep items with `priceVsAvgPct` < −15.
- **Price monitoring** — daily snapshot of one model in one city (`make`, `model`, `city`, year range) to track median price and supply.
- **New-listing alerts** — `sinceHours: 2` + your filters, scheduled hourly, pushed to Telegram/Slack via Apify integrations.
- **Import analytics** — `customsCleared: false` or a country slug (`ujnaya-koreya`, `rossiya`) to see what's coming into the market, and at what prices.
- **Credit / leasing marketing** — `inCredit: true` + `monthlyPaymentTo` to see what's offered for a given monthly budget.
- **Insurance & valuation** — year × mileage × price datasets for residual-value models.

### Input

All fields are optional. Location fields mirror the kolesa.kz URL: `https://kolesa.kz/cars/{make}/{model}/{city}/`.

| Field | Type | Default | Allowed values / notes |
|---|---|---|---|
| `make` | string | – (prefill `toyota`) | Brand slug from the kolesa.kz URL: `toyota`, `hyundai`, `kia`, `lexus`, `bmw`, `mercedes-benz`, `volkswagen`, `chevrolet`, `nissan`, `land-rover`, `vaz` (Lada), `chery`, `haval`, `geely`… Names are slugified (`Mercedes-Benz` → `mercedes-benz`, `Lada` → `vaz`, `Тойота` → `toyota`); typos are auto-corrected against kolesa.kz's own make list (`Toyta` → `toyota`, `Volkswagon` → `volkswagen`). Empty = all brands. |
| `model` | string | – | Model slug: `camry`, `land-cruiser-prado`, `rav-4`, `x5`, `elantra`… Requires `make` — kolesa.kz searches models only inside a brand (`/cars/{make}/{model}/`), so a model without a make fails with a clear message instead of returning every car. Typos are auto-corrected against the make's model list on kolesa.kz (`camri` → `camry`, `land cruser prado` → `land-cruiser-prado`, `Королла` → `corolla`, `prado` → `land-cruiser-prado`); no close model → the run fails listing the valid slugs. |
| `generation` | string | – | Generation code or name as shown on the ad page (`XV70`, `NX4`, `VIII`). kolesa.kz has no URL filter for it, so it works only with `detail: true`: every ad is opened and kept only if its «Поколение» matches. Tip: narrow with `yearFrom`/`yearTo` first. |
| `city` | string | – (prefill `almaty`) | **Empty = all Kazakhstan** — an API, schedule or MCP run without `city` searches the whole country (the form only pre-fills `almaty`). City, region or country slug — see **Reference**. Russian names accepted. |
| `yearFrom` / `yearTo` | integer | – | Model year. |
| `priceFrom` / `priceTo` | integer | – | ₸. |
| `monthlyPaymentFrom` / `monthlyPaymentTo` | integer | – | ₸ per month (kolesa.kz financing). |
| `mileageTo` | integer | – | km. |
| `volumeFrom` / `volumeTo` | number | – | Engine volume, litres (`1.6`, `2.5`). |
| `body` | string\[] | – | `sedan`, `wagon`, `hatchback`, `limousine`, `coupe`, `roadster`, `cabriolet`, `suv`, `crossover`, `microvan`, `minivan`, `minibus`, `van`, `pickup`, `targa`, `fastback`, `liftback`, `hardtop` |
| `fuel` | string\[] | – | `petrol`, `diesel`, `lpgPetrol`, `lpg`, `hybrid`, `electric` |
| `transmission` | string\[] | – | `manual`, `automaticAny`, `automatic`, `tiptronic`, `cvt`, `robot` |
| `steeringWheel` | string | – | `left`, `right` |
| `drive` | string\[] | – | `front`, `all`, `rear` |
| `color` | string\[] | – | `white`, `black`, `grey`, `silver`, `blue`, `lightBlue`, `red`, `green`, `brown`, `beige`, `gold`, `yellow`, `orange`, `burgundy`, `cherry`, `bronze`, `purple`, `lilac`, `pink`, `turquoise`, `chameleon` |
| `metallic` | boolean | `false` | Metallic paint only. |
| `condition` | string | – | `new`, `used`. Sent as kolesa's own path segment (`/cars/avtomobili-s-probegom/…`, `/cars/novye-avtomobili/…`) so year, price and paging keep working. |
| `availability` | string | – | `inStock`, `onOrder` |
| `bodyGroup` | string | – | `cars`, `suvPickup`, `minivanBus` |
| `markCountry` | string | – | Brand origin: `europe`, `uk`, `germany`, `italy`, `spain`, `france`, `czech`, `sweden`, `china`, `korea`, `russia`, `usa`, `japan`, `other` |
| `customsCleared` | boolean | `false` | Only cars cleared through Kazakhstan customs. |
| `withPhoto` | boolean | `false` | |
| `carHistory` | boolean | `false` | Only ads with a car history report. |
| `damaged` | boolean | `false` | Only cars needing repair / after accidents. |
| `dealersOnly` | boolean | `false` | |
| `inCredit` | boolean | `false` | Only cars available on credit. |
| `keywords` | string | – | Free-text search in the ad text (`_txt_`), e.g. `"один хозяин"`. |
| `extraParams` | object | `{}` | Any other query parameter copied from a kolesa.kz URL. |
| `sort` | string | `newest` | `newest`, `oldest`, `cheapest`, `expensive`, `yearDesc`, `yearThenPrice`. Paid promoted ads (`promoted` not empty) are pinned above the results regardless of sort — filter on `promoted` if you need a strict order. |
| `sinceHours` | integer | – | Keep only ads published in the last N hours (day precision on cards). With `sort: newest` pagination stops at the first fully-old page. |
| `maxItems` | integer | `40` | 1–5000, ~20 ads per page. |
| `maxPages` | integer | `50` | 1–300 safety cap. Raise it together with `maxItems` (5000 items ≈ 250 pages). |
| `detail` | boolean | `false` | Open every ad: generation, drive, steering, color, customs, options, full description, exact timestamps, `avgPrice`, `priceVsAvgPct`, seller type. +1 request per ad, about 4 ads a minute after a short first burst (see FAQ → IP limit); in fast mode up to 8 IPs do that at once. |
| `detailDelaySecs` | number | – (1.5 s) | Minimum seconds between two ad pages in detail mode, 1–60. The Actor paces itself anyway; set 20–30 only if your detail runs still report a block. |
| `includeViews` | boolean | `true` | Attach view counters (1 batch request per search page; per 25 ads in detail mode). |
| `includeVip` | boolean | `true` | Include ads from kolesa's paid VIP carousel. The carousel ignores your year/price/… filters, so each VIP card is checked against them and dropped if it does not match or cannot be verified (see FAQ). Kept VIP ads ignore the sort order: one is saved when the search reaches its regular card (fuller data), or after the search with its ad page opened. |
| `dedupe` | boolean | `true` | Drop repeated ids. `false` keeps an ad again when kolesa.kz shows it on a later page (each sighting is a row of its own, charged once). |
| `proxyConfiguration` | object | off | **Off = the normal run.** On = fast mode: Apify Proxy, group RESIDENTIAL → up to 8 IPs at once at the fast-mode price (a small datacenter pool gives fewer: two slots never share one IP); your own proxy URLs (`http://user:pass@host:port`, one per IP, up to 10 at once) → as many IPs as URLs at the normal price. Every IP keeps the normal pace. See [Speed and pricing](#speed-and-pricing). |

The list fields (`body`, `fuel`, `transmission`, `steeringWheel`, `drive`, `color`, `condition`, `availability`, `bodyGroup`, `markCountry`, `sort`) accept exactly the values above: Apify refuses any other value before the run starts. kolesa.kz answers 404 for an unknown **make** and silently returns every car of the make for an unknown **model**. This actor checks what kolesa.kz actually applied and **auto-corrects** obvious typos against the site's own make/model lists (https://kolesa.kz/cars/ and /cars/<make>/), then searches again — the correction is logged as a warning, shown in the status message and stored in the `SUMMARY` record. A make or model with no close match fails the run with the list of valid slugs instead of returning the wrong cars.

### Reference

#### Cities (`city`)

| Slug | City | Slug | City |
|---|---|---|---|
| `almaty` | Алматы | `astana` | Астана |
| `shymkent` | Шымкент | `karaganda` | Караганда |
| `aktobe` | Актобе | `aktau` | Актау |
| `atyrau` | Атырау | `kostanai` | Костанай |
| `kyzylorda` | Кызылорда | `pavlodar` | Павлодар |
| `petropavlovsk` | Петропавловск | `semei` | Семей |
| `taldykorgan` | Талдыкорган | `taraz` | Тараз |
| `turkestan` | Туркестан | `uralsk` | Уральск |
| `ust-kamenogorsk` | Усть-Каменогорск | `kokshetau` | Кокшетау |
| `janaozen` | Жанаозен | `jezkazgan` | Жезказган |
| `ekibastuz` | Экибастуз | `temirtau` | Темиртау |

Smaller towns seen in kolesa.kz data: `ayagoz`, `novaya-shulba`, `zhezkent`, `aksuat`, `urdjar`, `atbasar`, `makinsk`, `astraxanka`, `stepnogorsk`, `shuchinsk`, `xromtau`, `shubarkuduk`, `kaskelen`, `uzynagash`, `irgeli`, `bayserke`, `kyrmangazy`, `kulsary`, `maxambet`, `altay`, `ridder`, `shemonaixa`, `merke`, `shu`, `buryl`, `janatas`, `kordai`, `asa`. Any other slug that appears in a kolesa.kz URL also works; a wrong one fails with a `404`.

#### Regions (whole oblast)

`region-abaiskaya-oblast`, `region-akmolinskaya-oblast`, `region-aktubinskaya-oblast`, `region-almatinskaya-oblast`, `region-atyrauskaya-oblast`, `region-vostochnokazakhstanskaya-oblast`, `region-zhambilskaya-oblast`, `region-zhetysuskaya-oblast`, `region-zapadnokazakshstabskaya-oblast` (sic, as on the site), `region-karagandinskaya-oblast`, `region-kostanayskaya-oblast`, `region-kyzylordinskaya-oblast`, `region-mangistauskaya-oblast`, `region-pavlodarskaya-oblast`, `region-severokazakhstanskaya-oblast`, `region-yuzhnokazahstanskaya-oblast` (Turkestan region), `region-ulytauskaya-oblast`.

#### Countries (cars listed abroad)

`rossiya`, `kyrgyzstan`, `uzbekistan`, `belarus`, `armenia`, `gruziya`, `azerbaidzhan`, `tadzhikistan`, `turkmenistan`, `mongolija`, `kitay`, `ujnaya-koreya`, `japoniya`, `oaje`, `ssha`, `germany`, `poland`, `litva`, `latvia`, `estonia`, `turcija`, `israel`, `ukraina`, `avstrija`, `belgija`, `bolgarija`, `spain`, `italiya`, `malajzija`, `niderlandy`, `slovakia`, `thailand`, `frantsiya`, `shveitsariya`, `shvetsiya`, `velikobritaniya`.

These pages are served by kolesa.kz but are nearly empty at the moment (checked 2026-09-27: 0 ads from South Korea,
Russia or Germany, 1 from China) — such a run ends successfully with 0 items and says so in the status message.

#### Makes and models

There are too many to list. Open kolesa.kz, pick the make/model and copy the slugs from the URL, e.g. `https://kolesa.kz/cars/toyota/land-cruiser-prado/` → `make: "toyota"`, `model: "land-cruiser-prado"`.

#### Filter → kolesa.kz parameter map

| Input | Parameter | Codes |
|---|---|---|
| `yearFrom/To`, `priceFrom/To` | `year[from/to]`, `price[from/to]` | |
| `monthlyPaymentFrom/To` | `month-pay[from/to]` | ₸ |
| `mileageTo` | `auto-run[to]` | km |
| `volumeFrom/To` | `auto-car-volume[from/to]` | l |
| `body` | `auto-car-body` | sedan 11, wagon 12, hatchback 13, coupe 14, cabriolet 15, limousine 16, microvan 17, van 18, roadster 19, suv 21, pickup 22, crossover 23, minivan 31, minibus 32, targa 33, fastback 34, liftback 35, hardtop 36 |
| `fuel` | `auto-fuel` | petrol 1, diesel 2, lpgPetrol 3, lpg 4, hybrid 5, electric 6 |
| `transmission` | `auto-car-transm` | manual 1, automatic 2, tiptronic 3, cvt 4, robot 5; automaticAny = 2 + 3 + 4 + 5 (kolesa.kz's own `2345` shorthand exists only as a single-value parameter) |
| `steeringWheel` | `auto-sweel` | left 1, right 2 |
| `drive` | `car-dwheel` | front 1, all 2, rear 3 |
| `color` | `auto-color` (+ `auto-color_m`) | white 1, silver 2, green 3, red 4, grey 5, black 6, blue 7, gold 8, bronze 9, beige 11, lightBlue 12, brown 13, purple 14, yellow 15, orange 16, lilac 17, chameleon 18, pink 20, cherry 21, burgundy 22, turquoise 23 |
| `condition` | path segment (form field `auto-emergency`) | used → `/cars/avtomobili-s-probegom/…`, new → `/cars/novye-avtomobili/…`. The query form `?auto-emergency=1` is redirected by kolesa.kz to that path **without your other filters** — `extraParams: {"auto-emergency": …}` is moved to the path too. |
| `availability` | `auto-car-order` | inStock 1, onOrder 2 |
| `bodyGroup` | `auto-car-grbody` | cars 1, suvPickup 2, minivanBus 3 |
| `markCountry` | `mark-country` | see input table |
| `customsCleared`, `withPhoto` | `auto-custom=2`, `_sys-hasphoto=2` | |
| `carHistory`, `damaged`, `dealersOnly`, `inCredit` | `car-history`, `need-repair`, `is-dealer`, `in-credit` | 1 |
| `keywords` | `_txt_` | |
| `sort` | `sort_by` | newest (default), `add_date-asc`, `price-asc`, `price-desc`, `year-desc`, `year.price-desc.asc` |

Several values of one multi-select field are OR-combined and sent one parameter per value, the way the site's own form
does it (`auto-car-body[]=11&auto-car-body[]=21`). kolesa.kz answers 200 but ignores the whole filter when the values are
comma-joined, so a comma pasted into `extraParams` (`{"auto-fuel": "1,5"}`) is rewritten to that form with a warning.

### Examples

**Market snapshot — used Camry 2018–2021 in Almaty**

```json
{ "make": "toyota", "model": "camry", "city": "almaty", "yearFrom": 2018, "yearTo": 2021, "condition": "used", "maxItems": 300 }
```

**Dealer sourcing — underpriced crossovers, full detail with market average**

```json
{ "make": "hyundai", "model": "tucson", "city": "astana", "yearFrom": 2018, "customsCleared": true, "detail": true, "maxItems": 60 }
```

**Hourly alert — fresh automatic SUVs under 12 M ₸ anywhere in Kazakhstan**

```json
{ "make": "", "city": "", "body": ["suv", "crossover"], "transmission": ["automaticAny"], "priceTo": 12000000, "sinceHours": 2, "maxItems": 100 }
```

**Credit budget — what ≤150 000 ₸/month buys in Shymkent**

```json
{ "make": "", "city": "shymkent", "inCredit": true, "monthlyPaymentTo": 150000, "sort": "yearDesc", "maxItems": 100 }
```

**Import research — Korean-market cars listed from South Korea**

```json
{ "make": "kia", "city": "ujnaya-koreya", "fuel": ["petrol", "hybrid"], "maxItems": 100 }
```

### Output

One dataset item per ad. Example (trimmed, `detail: true`):

```json
{
  "id": "229997621", "url": "https://kolesa.kz/a/show/229997621",
  "title": "Hyundai Tucson", "make": "Hyundai", "model": "Tucson",
  "price": 7500000, "currency": "KZT", "monthlyPayment": null, "year": 2025,
  "condition": "used", "body": "кроссовер", "engineVolume": 2.5, "fuel": "бензин", "transmission": "автомат", "mileageKm": 67000,
  "description": "2025 г., Б/у кроссовер, 2.5 л, бензин, КПП автомат, с пробегом 67 000 км, …",
  "labels": [], "city": "Астана", "citySlug": "astana", "promoted": [], "isVip": false, "vip": false, "fromVipBlock": false,
  "image": "https://kolesa-photos.kcdn.online/webp/66/…/4-160x120.webp", "photosCount": 5,
  "publishedAt": "2026-09-06", "views": 718, "searchTotal": 256, "fetchedAt": "2026-09-13T07:55:45.272Z",
  "generation": "2020 - н.в. 4 поколение (NX4)", "drive": "Полный привод", "steeringWheel": "Слева",
  "customsCleared": true, "publishedAtExact": "2026-09-06T13:04:27+05:00", "updatedAt": "2026-09-07T11:02:39+05:00",
  "avgPrice": 16265000, "priceVsAvgPct": -53.9, "availability": "В наличии",
  "sellerType": "private", "sellerId": 30928420, "phonePrefix": "+7 776", "isCreditAvailable": false, "region": "KZ-AKM",
  "parameters": { "Кузов": "Кроссовер", "Пробег": "67 000 км", "Растаможен в Казахстане": "Да" }, "options": []
}
```

| Field | Description |
|---|---|
| `id`, `url` | kolesa.kz ad id and URL |
| `title`, `make`, `model` | As shown on the card |
| `price`, `currency`, `monthlyPayment` | ₸; credit payment when the card shows one |
| `year`, `condition`, `body`, `engineVolume`, `fuel`, `transmission`, `mileageKm` | Parsed from the card summary (Russian values as on the site) |
| `description`, `labels` | Card text and badges |
| `city`, `citySlug` | City shown on the card; slug you searched |
| `promoted`, `isVip`, `fromVipBlock` | Paid placements (`hot`, `top`, `vip`). `isVip` = the ad has the paid VIP service (also on its regular card); `fromVipBlock` = the row came from the VIP carousel and its regular card was not reached (the VIP card has no mileage or body, so the actor opens that ad's page to fill them — one extra request per such row). `vip` = same as `isVip`, kept for older integrations |
| `image`, `photosCount` | First photo, number of photos |
| `publishedAt` | `YYYY-MM-DD` in Kazakhstan time (UTC+5, as the site shows it; exact date from the ad page in detail mode) |
| `views` | Live view counter (`includeViews`) |
| `searchTotal` | Number of ads kolesa.kz reports for the search |
| `fetchedAt` | ISO timestamp |
| detail only | `parameters`, `options`, `descriptionFull`, `generation`, `drive`, `steeringWheel`, `color`, `customsCleared`, `publishedAtExact`, `updatedAt`, `avgPrice`, `priceVsAvgPct`, `availability`, `sellerType` (`private`/`dealer`/`company`), `sellerId`, `phonePrefix`, `isCreditAvailable`, `isDealerVerified`, `region`, `cityFull`; `detailError` if that page failed |

Full phone numbers are behind a click-to-reveal on kolesa.kz and are **not** collected.

The key-value store record `SUMMARY` describes the run: `searched` (make, model, city and the search URL actually used), `typed` (make/model as given), `corrections` (auto-corrected typos), `warnings` (including any filter kolesa.kz dropped in a redirect), `searchTotal`, `saved` / `delivered` (rows stored and charged), `stoppedBy` (`limit` = your spending limit, `timeout` = the run timeout, `aborted`, or `null`), `status` (the final status message), `speed` and `vipCarousel` (VIP cards kept, filled from the results, dropped as not matching, with examples).

### Use it from code / agents

```bash
curl -X POST "https://api.apify.com/v2/acts/yadroo~kolesa-kz/run-sync-get-dataset-items?token=$APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"make":"toyota","model":"camry","city":"almaty","yearFrom":2018,"maxItems":50}'
```

```js
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('yadroo/kolesa-kz').call({ make: 'lexus', model: 'rx', detail: true, maxItems: 40 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
```

```python
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor("yadroo/kolesa-kz").call(run_input={"make": "kia", "city": "astana", "sinceHours": 24})
items = client.dataset(run["defaultDatasetId"]).list_items().items
```

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

### Speed and pricing

kolesa.kz cuts off an IP that reads too fast (see FAQ → IP limit), so the normal run reads at about 4 requests a minute after a short burst. Fast mode keeps exactly that pace **on every IP** and reads with several IPs at once. Pick the mode with the `proxyConfiguration` input:

| Mode | How | 150 ads, `detail: true` | 500 ads, `detail: true` | 500 ads, no detail | Price per ad |
|---|---|---|---|---|---|
| **Normal** (default) | proxy off | ≈ 40 min | ≈ 2.3 hours | ≈ 13 min | **$0.003** |
| **Fast, Apify Proxy** | proxy on → Apify Proxy, group RESIDENTIAL (up to 8 IPs) | **1.4 min** (measured) | **14 min** (measured) | ≈ 2 min (estimated) | **$0.004** |
| **Fast, your proxies** | proxy on → your proxy URLs, one per IP | like Apify Proxy with 8 or more URLs; one URL = normal speed | | | **$0.003** |

Measured in the Apify cloud on 2026-10-02 with `city: aktobe`, `keywords: обмен` (build 0.1.22): 500 ads with detail in 14 min (3 blocked IPs replaced on the way), 150 ads with detail in 82 s, 150 ads without detail in 26 s; every row had its detail fields. Normal-mode times follow from the measured pace (FAQ → Recommended batch size).

- **One price per ad in each mode.** A fast run on Apify Proxy charges the *fast-mode listing* event **instead of** the normal *listing* event, not on top of it; the extra $0.001 pays for the proxy traffic (≈ 24 KB per ad with detail, ≈ 4 KB without, measured). With your own proxies the traffic is yours, so the normal price stays. Run start: $0.005 in every mode.
- **Same pace per IP.** Each IP has its own request budget — a burst of ~20 requests, then 4 a minute — so kolesa.kz never sees more from one IP than from a normal run; 8 IPs at once means at most ~32 requests a minute after the first burst. An IP kolesa.kz refuses or stops answering is replaced by a new one (up to 3 times per IP slot); an ad that fails on 3 IPs keeps its card data with `detailError`.
- **Which proxy.** Apify Proxy group RESIDENTIAL worked in every test and gives 8 distinct IPs. Before a slot uses an IP, the run reads that IP (Apify's own echo endpoint, not kolesa.kz): two slots never share one, because one IP would then get twice the per-IP pace. A small datacenter pool (the Free plan has 5 IPs) therefore runs with fewer slots; its IPs are also shared with other users, so more of them may already be blocked — the run replaces those. Your own proxies: `http://` or `https://` URLs (SOCKS is not supported), one URL per IP; a "rotating" gateway URL counts as one IP and gets one IP's pace.
- `SUMMARY.speed` shows the mode, IPs used, IPs replaced because another slot had them (`sharedIpsReplaced`) and the charged event.
- **Plan discounts.** Bronze −10 %, Silver −20 %, Gold and above −30 % on the per-ad price (both events); the run start is the same on every plan; platform usage is included.

Typical runs (normal mode): 40 ads ≈ $0.125; a 300-ad model snapshot ≈ $0.905; an hourly 20-ad alert ≈ $0.065 per run. Fast mode on Apify Proxy: 500 ads with detail ≈ $2.005. `detail: true` costs the same per ad as a run without it.

### Limits & FAQ

- **Rate limits** — every request is paced (next point); 429/468/5xx are retried with backoff. Don't run several normal-mode copies of this Actor at the same time — runs on the same Apify server add up against the same limit (fast-mode runs read through their own proxy IPs).
- **Freshness** — data is read live at run time. Card dates are day-precise and in Kazakhstan time: "Сегодня" / "19 сен." are resolved against the Almaty calendar, so runs in the UTC evening date today's ads correctly and `sinceHours` keeps them; detail mode gives exact timestamps.
- **Blocks / errors** — a block (`403`/`418`, kolesa.kz's edge answers 418 with an empty body), an unrecognized page or a wrong slug (`404`) fails the run with a clear message instead of returning empty data. A failed detail page keeps the item with `detailError`.
- **Typos in make/model** — auto-corrected and never silently widened: `Toyta` → toyota, `camri` → camry, `Хендай` → hyundai. See the log warning, the status message or `SUMMARY` (`searched`, `corrections`) for what was actually searched. Extra words after a model (`camry 70`) are ignored with a warning — use `generation` with `detail: true`. No close match → the run fails with the list of valid slugs.
- **VIP carousel** — kolesa.kz shows 3 random paid VIP ads above every results page. They follow only the make/model/city/condition part of the search and ignore year, price and the other filters (checked 2026-09-18: a `year ≤ 2019` search shows a 2020 VIP car, a `price ≤ 5 M ₸` search shows 5.1–6 M VIP cars). With `includeVip: true` (default) every VIP card is checked against year, price, monthly payment, engine volume, fuel, gearbox and city from its card; filters a VIP card shows nothing about (mileage, body, colour, drive, credit, keywords, `extraParams` …) make it unverifiable and it is dropped. Nothing is lost: a VIP ad that matches your filters is also listed in the regular results, where the actor picks it up (and fills a kept VIP row from its fuller regular card). `SUMMARY.vipCarousel` shows what was kept and dropped.
- **Generation** — no server-side filter exists on kolesa.kz; `generation` is applied after opening each ad (`detail: true`), so you pay only for matching ads but the run opens every ad in `maxItems`.
- **Max items** — 5000 per run (up to 300 pages). Large runs are paced (next point), so budget time: without `detail` up to ~100 ads are instant, 300 ads ≈ 5–6 minutes, 1000 ads ≈ 30 minutes (≈ 20 with `includeViews: false`); with `detail: true` see the batch sizes below. The default run timeout is 1 hour — raise it for bigger jobs or split them by city, year or price range. While a long search is read, kolesa.kz keeps reordering it (bumped ads move to the top), so in a busy city some ads can be skipped or come twice (repeats are dropped; checked 2026-10-02 in Almaty: ~20 new ads per page when pages came 1.4 s apart, often 0–10 when 30 s apart) — for a complete snapshot narrow the filters or sort by price (`cheapest`/`expensive`), an order that bumps do not change. If the run has a spending limit (Maximum cost per run), the run collects no more ads than the limit pays for — every extra request counts toward the IP limit — and ends with "Stopped at your spending limit: N rows delivered"; a limit that pays for no ad reads nothing.
- **IP limit** (normal mode; in fast mode the same budget applies to every proxy IP and a blocked IP is replaced instead of waited out) — kolesa.kz cuts off an IP that sends too many requests in a short time: every connection from it times out — search included — for 15 minutes or more, so a run that lands on a blocked Apify server fails on its first page within ~3 minutes, with that explanation. Start it again: a new run usually lands on another server (in our deploy tests the retry passed); if it fails the same way, wait 30–60 minutes. Measured in the Apify cloud on 2026-10-02: 46 ad pages ~1.3 s apart, 45 ad pages 3 s apart, 68 ad pages at ~6.6 a minute and a search of 34 pages ~1.4 s apart were cut off; 70 ad pages at 8 a minute, 60 at 4 a minute and 100 at 4 a minute were not. Other traffic from the same Apify server counts too, so the limit is not exact. Since build 0.1.17 every request goes through a budget: a short burst (about 20 requests; a search page counts as two), then 4 requests a minute. If kolesa.kz cuts the IP off anyway, the run pauses for 3 and then 10 minutes, retries the ads that did not answer and continues more slowly; the log shows the pause. Only when kolesa.kz still refuses after that (or the run is near its timeout) do the remaining rows keep their card fields with empty detail fields (`detailError` on the ad tried last), and the status message says so. A search page that does not answer gets one more try after a 1-minute pause; then the run fails with a clear message — or, after page 1, ends successfully with the pages already read.
- **Recommended batch size for `detail: true`** — about 4 ads a minute: 30 ads ≈ 4 minutes, 60 ≈ 12, 100 ≈ 25, 150 ≈ 40; 500 ads ≈ 2.3 hours (raise the run timeout to ~3 hours, or split the job) — or use fast mode (500 ads ≈ 14 minutes, see [Speed and pricing](#speed-and-pricing)). Run detail jobs one after another, not in parallel — runs on the same Apify server share the limit. If a run reported a block, wait 30–60 minutes before the next detail run. To check many ads cheaply, run without `detail` first and open only the shortlist with `detail: true` (for example a narrower price or year range).
- **Partial results are never lost** — the dataset is written while the run goes: after every search page, or in batches of 10 ads with `detail: true`. Near its timeout the run stops starting new requests, saves what it has read and ends successfully with "Stopped before the run timeout: N rows saved"; with `detail: true` the ads not opened by then are saved with their card data. An aborted run keeps everything saved before the abort. If the platform migrates or restarts the run, ads already saved are skipped: no ad is stored or charged twice in one run.
- **Roadmap** — price-history via scheduled runs, dealer catalog mode.

***

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

# Actor input Schema

## `make` (type: `string`):

Brand slug as in kolesa.kz URLs: toyota, hyundai, kia, lexus, bmw, mercedes-benz, volkswagen, chevrolet, nissan, mitsubishi, honda, mazda, subaru, audi, land-rover, vaz (Lada), gaz, uaz, chery, haval, geely, byd, changan, exeed, jetour, jac… "Mercedes-Benz", "Land Rover" or "Тойота" are slugified automatically; typos are auto-corrected against kolesa.kz's own make list ("Toyta" → toyota) and shown in the log. Empty = all makes.

## `model` (type: `string`):

Requires make; empty = all models of the make. Model slug as in kolesa.kz URLs: camry, land-cruiser-prado, x5, elantra, sonata, k5, rx, tucson… kolesa.kz searches models only inside a brand, so a model without a make fails with a clear message instead of returning every car. Typos are auto-corrected against the make's model list on kolesa.kz (camri → camry, Королла → corolla) and reported in the log, status and SUMMARY; no close match fails the run with the list of valid slugs.

## `generation` (type: `string`):

Generation code or name as shown on the ad page, e.g. XV70, NX4, VIII. kolesa.kz has no URL filter for generations, so this works only with detail=true: each ad page is opened and kept only if its «Поколение» text contains this value. Narrow with yearFrom/yearTo first.

## `city` (type: `string`):

Empty = all Kazakhstan (no default; the form pre-fills almaty). City, region or country slug as in kolesa.kz URLs. Cities: almaty, astana, shymkent, karaganda, aktobe, aktau, atyrau, kostanai, pavlodar, semei, taraz, uralsk, ust-kamenogorsk, kokshetau… Whole region: region-almatinskaya-oblast, region-akmolinskaya-oblast… Cars listed abroad: rossiya, kyrgyzstan, ujnaya-koreya… Russian names accepted. Full tables in README → Reference.

## `yearFrom` (type: `integer`):

Model year from.

## `yearTo` (type: `integer`):

Model year to.

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

Minimum price in tenge.

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

Maximum price in tenge.

## `monthlyPaymentFrom` (type: `integer`):

Minimum monthly loan payment shown by kolesa.kz financing (month-pay\[from]). Useful together with inCredit.

## `monthlyPaymentTo` (type: `integer`):

Maximum monthly loan payment (month-pay\[to]) — e.g. 'cars I can buy for ≤150 000 ₸/month'.

## `mileageTo` (type: `integer`):

Maximum odometer reading in km (kolesa.kz has no lower bound filter).

## `volumeFrom` (type: `number`):

Engine displacement from, litres (decimals allowed, e.g. 1.6 or 2.5).

## `volumeTo` (type: `number`):

Engine displacement to, litres.

## `body` (type: `array`):

Body types to include. Several values = OR.

## `fuel` (type: `array`):

Engine/fuel type. Several values = OR.

## `transmission` (type: `array`):

Gearbox. automaticAny = any automatic (automatic, tiptronic, CVT, robot). Several values = OR.

## `steeringWheel` (type: `string`):

Left- or right-hand drive. Leave unset for any.

## `drive` (type: `array`):

Drivetrain. Several values = OR.

## `color` (type: `array`):

Body color. Several values = OR.

## `metallic` (type: `boolean`):

Only metallic colors.

## `condition` (type: `string`):

new = brand-new cars (dealer stock), used = with mileage. Leave unset for any. Sent as kolesa's own URL path segment, so all other filters keep working.

## `availability` (type: `string`):

In stock vs. on order (mostly for new cars). Leave unset for any.

## `bodyGroup` (type: `string`):

Coarse vehicle class as on the kolesa.kz top tabs. Leave unset for any.

## `markCountry` (type: `string`):

Country of origin of the brand (kolesa.kz 'Страна происхождения марки'). Leave unset for any.

## `customsCleared` (type: `boolean`):

Only cars cleared through Kazakhstan customs (растаможен).

## `withPhoto` (type: `boolean`):

Skip listings without photos.

## `carHistory` (type: `boolean`):

Only listings with the kolesa.kz 'История авто' report.

## `damaged` (type: `boolean`):

Only cars flagged 'Аварийная/Не на ходу' (salvage buyers).

## `dealersOnly` (type: `boolean`):

Only listings from dealers.

## `inCredit` (type: `boolean`):

Only cars available with kolesa.kz financing.

## `keywords` (type: `string`):

Free-text search inside listing descriptions (kolesa.kz `_txt_`), e.g. "один хозяин" or "обмен".

## `extraParams` (type: `object`):

Escape hatch for any kolesa.kz query parameter not listed above, copied from the site URL, e.g. {"deposit\[to]": 1000000}.

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

Result order as on kolesa.kz.

## `sinceHours` (type: `integer`):

Keep only listings published within the last N hours (card dates are day-precise; detail=true adds exact publication timestamps). With sort=newest pagination stops at the first fully-old page — ideal for monitoring.

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

Stop after this many listings (~20 per page). A run with a spending limit collects no more than the limit pays for.

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

Safety cap on search pages.

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

Fetch every listing page to add: generation, drive, steering wheel, color, customs status, full options list, seller description, exact publication/update timestamps, kolesa.kz average market price for the model (avgPrice) and the % difference (priceVsAvgPct), seller type (private/dealer), credit availability. +1 request per listing.

## `detailDelaySecs` (type: `number`):

Minimum seconds between two listing pages on one IP in detail mode (1–60). Empty = 1.5 s. kolesa.kz cuts off an IP that sends too many requests in a short time (for 15+ minutes), so the Actor paces every request anyway: a short burst, then about 4 a minute per IP. Set 20–30 only if your detail runs still report a block.

## `includeViews` (type: `boolean`):

Attach the site's view counter to each listing (1 batch request per search page, or per 25 listings in detail mode).

## `includeVip` (type: `boolean`):

Include ads from kolesa's paid VIP carousel above the results. The carousel ignores year, price and most filters, so every VIP card is checked against your filters and dropped when it does not match or cannot be verified from the card. Kept VIP ads are marked isVip / fromVipBlock and ignore the sort order.

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

Drop repeated ids across pages and VIP/TOP blocks.

## `proxyConfiguration` (type: `object`):

Off (default): the normal run on one IP — a short burst, then about 4 requests a minute (kolesa.kz cuts off a faster IP for 15+ minutes). On: fast mode — up to 8 IPs at once, each at that same pace; with Apify Proxy each listing costs $0.004 instead of $0.003 (one price, not both). Pick group RESIDENTIAL: a small datacenter pool has fewer distinct IPs, and an IP already in use is never used twice. Own proxy URLs (one per IP, up to 10 at once) keep the normal price.

## Actor input object example

```json
{
  "make": "toyota",
  "city": "almaty",
  "metallic": false,
  "customsCleared": false,
  "withPhoto": false,
  "carHistory": false,
  "damaged": false,
  "dealersOnly": false,
  "inCredit": false,
  "extraParams": {},
  "sort": "newest",
  "maxItems": 40,
  "maxPages": 50,
  "detail": false,
  "includeViews": true,
  "includeVip": true,
  "dedupe": true,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `listings` (type: `string`):

No description

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

No description

## `summary` (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 = {
    "make": "toyota",
    "city": "almaty",
    "extraParams": {},
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yadroo/kolesa-kz").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 = {
    "make": "toyota",
    "city": "almaty",
    "extraParams": {},
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("yadroo/kolesa-kz").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 '{
  "make": "toyota",
  "city": "almaty",
  "extraParams": {},
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call yadroo/kolesa-kz --silent --output-dataset

```

## MCP server setup

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

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/OBT3B62wPVOQsWhql/builds/q6ThlBIUgCKRmnEj1/openapi.json
