# OLX Listings Scraper: Poland, Ukraine, Romania & More (`cliqtomedia/olx-listings-scraper`) Actor

Scrape OLX listings from Poland, Ukraine, Kazakhstan, Portugal, Romania, Bulgaria and Uzbekistan by keyword, city, price or category URL. Price, params, dates, photos, seller type; only-new mode for monitoring.

- **URL**: https://apify.com/cliqtomedia/olx-listings-scraper.md
- **Developed by:** [Cliqto Media](https://apify.com/cliqtomedia) (community)
- **Categories:** E-commerce, Real estate
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 saved 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

OLX Listings Scraper collects public listings from OLX in Poland, Ukraine, Kazakhstan, Portugal, Romania, Bulgaria and Uzbekistan by keyword, city, price or a pasted OLX category URL, and returns one clean row per listing with price, location, category, parameters, dates, photos and seller type.

It is for resellers, price analysts, car dealers and real estate agents who watch OLX. The smallest run is one keyword: `pl` + `iphone` + 20 listings finishes in a few seconds.

![OLX Listings Scraper: search OLX by keyword, city and price in 7 countries, get listings with price, params and photos, export JSON or CSV, or get only new listings](https://api.apify.com/v2/key-value-stores/YuxbhUt099lxpqvMv/records/HERO-20261014.png)

### Table of contents

- [What it does](#what-it-does)
- [Quick start](#quick-start)
- [Input](#input)
- [Output](#output)
- [Pricing and limits](#pricing-and-limits)
- [Use cases](#use-cases)
- [Monitoring: only new listings](#monitoring-only-new-listings)
- [API and integrations](#api-and-integrations)
- [Use with AI agents (MCP)](#use-with-ai-agents-mcp)
- [Limits and partial results](#limits-and-partial-results)
- [Troubleshooting](#troubleshooting)
- [FAQ](#faq)
- [Support](#support)

### What it does

The Actor runs OLX searches for you and saves every listing it finds to a Dataset. You can search in two ways:

- **Keywords** (`queries`): one OLX search per keyword on the site you choose in `country`. You can limit keyword searches by `city`.
- **OLX URLs** (`categoryUrls`): paste any OLX results page. The category, city and filters from the page are kept.

`priceMin`, `priceMax` and `sortBy` apply to all searches. Each row has the listing price and currency, city and region, category path, listing parameters (for example model, year, mileage, area, rooms), created and refreshed dates, photo URLs and seller type (`private` or `business`).

Supported OLX sites: olx.pl, olx.ua, olx.kz, olx.pt, olx.ro, olx.bg, olx.uz. All sites use the same output fields, so you can compare markets in one table.

#### Good fit

- Track prices of used phones, laptops or cars in one or more countries.
- Build a list of apartments or cars in one city with price, area, year and mileage.
- Watch a search on a schedule and get only listings that appeared since the last run.

#### Not a fit / limits

- OLX Brazil (olx.com.br), OLX India and other non-listed OLX sites are not supported.
- No phone numbers, e-mails or names of private sellers. The Actor does not log in and does not open single listing pages.
- OLX shows at most about 1,000 listings per search. To get more, split the search by city, category or price range.

### Quick start

1. Open the **Input** tab.
2. Keep **Country** = `pl` and **Search keywords** = `iphone` (the form prefill), or add your own keyword.
3. Keep **Max listings per search** = `20` (prefill) for a first test.
4. Click **Start**.
5. Open the **Output** tab → **Listings** and check `title`, `price` and `city`.

Expected result: 20 OLX listings from olx.pl, newest first, in a few seconds.

### Input

#### Input fields

| Field | Plain name | Type | Required | Default / prefill | Allowed values | Effect | Example | Recommendation |
| --- | --- | --- | --- | --- | --- | --- | --- | --- |
| `country` | Country (OLX site) | string | no | default `pl` | `pl`, `ua`, `kz`, `pt`, `ro`, `bg`, `uz` | Site for keyword searches. URLs always use their own site. | `ua` | Choose the market you watch. |
| `queries` | Search keywords | array of strings | one of `queries` / `categoryUrls` | prefill `["iphone"]` | up to 50 keywords and URLs together | One OLX search per keyword. | `["bmw x5", "audi a6"]` | Use the words buyers type on OLX in the local language. |
| `categoryUrls` | OLX category or search URLs | array of strings | one of `queries` / `categoryUrls` | empty | up to 10 OLX results pages on the 7 supported sites | One search per URL; category, city and page filters are kept. | `["https://www.olx.pl/motoryzacja/samochody/bmw/warszawa/"]` | Best for categories (cars, apartments) and complex filters. Single listing pages are rejected. |
| `city` | City | string | no | empty = whole country | city or region slug from the OLX address bar, up to 100 characters | Limits keyword searches to one city or region. Not used for URLs. | `warszawa`, `kiev`, `alma-ata` | Copy the slug from an OLX URL. Accents are removed (`Kraków` → `krakow`). |
| `priceMin` | Minimum price | integer | no | empty | ≥ 0, in the site currency | Lowest price for all searches and URLs. | `500` | Must not be higher than `priceMax`. |
| `priceMax` | Maximum price | integer | no | empty | ≥ 0, in the site currency | Highest price for all searches and URLs. | `3000` | Use it to skip fake very high prices. |
| `sortBy` | Sort by | string | no | default `newest` | `newest`, `relevance`, `price_asc`, `price_desc` | Order of results. | `price_asc` | Keep `newest` for monitoring and `onlyNew`. |
| `maxItems` | Max listings per search | integer | no | default `100`, prefill `20` | 1–1000 | Each keyword or URL stops after this many listings. | `200` | You pay per saved listing, so set what you need. |
| `onlyNew` | Only new listings since the last run | boolean | no | default `false` | `true` / `false` | Returns only listings not returned before for the same search. | `true` | Turn on for scheduled runs. |
| `includeDescription` | Include description text | boolean | no | default `true` | `true` / `false` | Adds the full description as plain text. | `false` | Turn off for smaller output. |
| `includePromoted` | Include promoted listings | boolean | no | default `true` | `true` / `false` | `false` skips paid (promoted and TOP) listings. | `false` | Turn off when you want only organic results. |

Empty input: if both `queries` and `categoryUrls` are empty, the run fails at once with an input error and only the start event is charged. Repeated keywords (`iphone` and `IPHONE`) run as one search. A listing found by two searches in the same run is saved and charged once.

#### Interacting settings

| When | Input A | Input B | Effective behavior | Example | Cost/result effect |
| --- | --- | --- | --- | --- | --- |
| Both are filled | `queries` | `categoryUrls` | Both run. Each keyword and each URL is a separate search. | 1 keyword + 2 URLs = 3 searches | Up to `maxItems` rows for each search. |
| A URL is used | `categoryUrls` | `country`, `city` | The URL keeps its own site and city. `country` and `city` apply only to keywords. | olx.ua URL with `country: pl` | URL rows have `country: ua`. |
| A price filter is set | `priceMin` / `priceMax` | `categoryUrls` | The price filter is added to every URL too. | URL + `priceMax: 3000` | Fewer rows, same request count per page. |
| `priceMin` > `priceMax` | `priceMin` | `priceMax` | Input error, the run stops before any request. | `2000` / `100` | Only the start event. |
| Monitoring | `onlyNew` | `sortBy` | Works best with `newest`; the Actor stops a search when it reaches listings older than the last run. | `onlyNew: true` | Unchanged runs save 0 rows. |
| Paid listings | `includePromoted` | `maxItems` | When `false`, paid listings are skipped and do not count toward `maxItems`. | `false`, `maxItems: 20` | 20 organic rows. |

#### Input examples

##### Phones in one city, price range

```json
{
  "country": "pl",
  "queries": ["iphone 15"],
  "city": "warszawa",
  "priceMin": 1500,
  "priceMax": 3000,
  "maxItems": 200
}
```

Expected behavior: one OLX search on olx.pl in Warsaw, newest first.
Expected output: up to 200 listings with `title`, `price`, `currency`, `params`, `postedAt`.
Limit or cost note: you pay for each saved listing; the run stops at 200.

##### Apartments from an OLX category URL, scheduled

```json
{
  "categoryUrls": ["https://www.olx.ua/uk/nedvizhimost/kvartiry/kiev/"],
  "onlyNew": true,
  "maxItems": 250
}
```

Expected behavior: the first run returns current listings; next runs return only new ones.
Expected output: apartments with `price`, `params` (area, rooms, floor), `district`, `postedAt`.
Limit or cost note: an unchanged scheduled run saves 0 rows and costs only the start event.

### Output

Each row is one OLX listing. The default view **Listings** shows `title`, `price`, `currency`, `negotiable`, `city`, `region`, `categoryPath`, `sellerType`, `postedAt`, `refreshedAt`, `isPromoted`, `url`. Export the Dataset as JSON, CSV, Excel or other Apify formats.

#### Output example

A real row from the prefill run (`pl`, `iphone`, 20 listings), trimmed: the description is shortened, only one photo and one detailed parameter are shown, `sellerId` is removed.

```json
{
  "id": 1009568339,
  "url": "https://www.olx.pl/d/oferta/szklo-hartowane-na-obiektyw-3mk-apple-iphone-15-plus-CID99-ID16k2Qj.html",
  "title": "Szkło hartowane na obiektyw 3MK  Apple iPhone 15 Plus",
  "description": "Lens Protection Pro to szkło ochronne na obiektyw aparatu iPhone'a, które odznacza się naj…",
  "price": 25,
  "priceLabel": "25 zł",
  "currency": "PLN",
  "priceType": "price",
  "negotiable": false,
  "previousPrice": null,
  "priceConverted": null,
  "convertedCurrency": null,
  "city": "Kraków",
  "cityId": 8959,
  "district": "Mistrzejowice",
  "region": "Małopolskie",
  "regionId": 4,
  "latitude": 50.09557,
  "longitude": 20.00366,
  "locationRadiusKm": 7,
  "categoryId": 2911,
  "category": "Folie i szkła ochronne",
  "categoryPath": "Elektronika > Telefony > Akcesoria > Folie i szkła ochronne",
  "categoryType": "electronics",
  "params": { "state": "Nowe", "type": "Szkło hartowane" },
  "paramsDetailed": [{ "key": "state", "name": "Stan", "value": "Nowe", "valueKey": "new" }],
  "postedAt": "2025-06-21T16:36:04+02:00",
  "refreshedAt": "2026-10-14T16:23:01+02:00",
  "pushedUpAt": null,
  "validTo": "2026-11-13T15:36:05+01:00",
  "photos": ["https://ireland.apollo.olxcdn.com/v1/files/tz6bc091m3xh2-PL/image;s=750x1000"],
  "photoCount": 1,
  "sellerType": "private",
  "sellerName": null,
  "sellerSince": "2016-01-24T18:22:06+01:00",
  "isPromoted": false,
  "isHighlighted": false,
  "isUrgent": false,
  "hasDelivery": true,
  "offerType": "offer",
  "status": "active",
  "country": "pl",
  "domain": "www.olx.pl",
  "search": "iphone",
  "searchUrl": "https://www.olx.pl/api/v1/offers/?offset=0&limit=40&query=iphone&sort_by=created_at%3Adesc",
  "position": 4,
  "isNew": null,
  "source": "olx",
  "fetchedAt": "2026-10-14T14:26:33.531Z"
}
```

`null` means OLX did not give this value. It never means zero: a listing for exchange has `price: null`, and only a free listing has `price: 0`.

#### Output fields

| Field | Meaning | Type | Can be empty? | Example / enum | Source / notes |
| --- | --- | --- | --- | --- | --- |
| `id` | OLX listing id | integer | no | `1009568339` | OLX |
| `url` | Listing page | string | no | `https://www.olx.pl/d/oferta/…` | OLX |
| `title` | Listing title | string | yes | `iPhone 15 128GB` | OLX |
| `description` | Full description, plain text | string | yes: `includeDescription: false` | | HTML removed |
| `price` | Asking price in `currency` | number | yes: exchange or no price | `25`; `0` = free | OLX |
| `priceLabel` | Price as OLX shows it | string | yes | `25 zł`, `Za darmo` | OLX |
| `currency` | Price currency | string | yes, when `price` is null | `PLN`, `UAH`, `KZT`, `EUR`, `RON`, `BGN`, `UZS`, `USD` | OLX |
| `priceType` | Kind of price | string | yes | `price`, `arranged`, `free`, `exchange` | OLX |
| `negotiable` | Seller marked the price as negotiable | boolean | yes | `true` | OLX |
| `previousPrice` | Earlier price after a price drop | number | yes | `2899` | OLX |
| `priceConverted`, `convertedCurrency` | Second price OLX shows (some sites) | number, string | yes | `1250`, `USD` | OLX |
| `city`, `cityId` | City name and id | string, integer | yes | `Kraków`, `8959` | OLX |
| `district` | District, if given | string | yes | `Mistrzejowice` | OLX |
| `region`, `regionId` | Region (voivodeship, oblast) | string, integer | yes | `Małopolskie`, `4` | OLX |
| `latitude`, `longitude`, `locationRadiusKm` | Approximate point and its blur radius | number | yes | `50.09`, `20.00`, `7` | OLX blurs the point |
| `category`, `categoryId` | Leaf category name and id | string, integer | yes | `Folie i szkła ochronne` | OLX |
| `categoryPath` | Full category path | string | yes | `Elektronika > Telefony > …` | OLX category tree |
| `categoryType` | OLX vertical | string | yes | `goods`, `automotive`, `real_estate`, `electronics`, `job` | OLX |
| `params` | Parameters as key → value | object | no, can be `{}` | `{"year": "2018", "milage": "120 000 km"}` | OLX, trimmed |
| `paramsDetailed` | Parameters with display name and value key | array | no, can be `[]` | `[{"key":"state","name":"Stan",…}]` | OLX |
| `postedAt` | When the listing was created | string (ISO 8601) | yes | `2025-06-21T16:36:04+02:00` | OLX |
| `refreshedAt` | Last refresh or bump | string | yes | `2026-10-14T16:23:01+02:00` | OLX |
| `pushedUpAt` | Last paid push-up | string | yes | `null` | OLX |
| `validTo` | When the listing expires | string | yes | `2026-11-13T15:36:05+01:00` | OLX |
| `photos`, `photoCount` | Photo URLs and count | array, integer | no, can be `[]` / `0` | | OLX CDN |
| `sellerType` | Private person or business | string | yes | `private`, `business` | OLX |
| `sellerId` | OLX seller id, to group by seller | integer | yes | | OLX |
| `sellerName` | Business seller name | string | yes: always null for private sellers | | privacy rule |
| `sellerSince` | When the seller account was created | string | yes | | OLX |
| `isPromoted` | Paid listing (promoted slot or TOP ad) | boolean | no | `false` | OLX |
| `isHighlighted`, `isUrgent` | Paid highlight and urgent flags | boolean | yes | `false` | OLX |
| `hasDelivery` | OLX delivery is available | boolean | yes | `true` | OLX |
| `offerType`, `status` | OLX offer type and status | string | yes | `offer`, `active` | OLX |
| `country`, `domain` | OLX site of the row | string | no | `pl`, `www.olx.pl` | Actor |
| `search` | Keyword (with city) or URL that found the row | string | no | `iphone` | Actor |
| `searchUrl` | Exact OLX results request | string | no | | Actor |
| `position` | Position in its search in this run | integer | no | `4` | Actor |
| `isNew` | `true` in `onlyNew` mode, otherwise null | boolean | yes | `null` | Actor |
| `source` | Always `olx` | string | no | `olx` | Actor |
| `fetchedAt` | When the row was fetched (UTC) | string | no | `2026-10-14T14:26:33.531Z` | Actor |

#### Output entities and surfaces

| Situation | Where | Result shape | User action |
| --- | --- | --- | --- |
| Normal listing | Dataset, view **Listings** | one row per listing | open, export or use by API |
| No listings found | Dataset is empty; `RUN_SUMMARY` search status `no_results` | run `SUCCEEDED` | check keyword, city or price filter |
| Unknown city or OLX URL | `RUN_SUMMARY` search status `not_found` | other searches still run | fix the city slug or URL |
| Stopped early (cost limit, time limit) | Dataset has the saved rows; `RUN_SUMMARY.status` = `PARTIAL` with `reason` | run `SUCCEEDED` | raise the limit and run again |
| OLX error or block | `RUN_SUMMARY` search status `error`, `errorCode` | rows saved before the error stay | retry later |

`RUN_SUMMARY` (in the run's key-value store) has the run `status` (`COMPLETE`, `PARTIAL`, `NO_RESULTS`, `NOT_FOUND`, `ERROR`, `INVALID_INPUT`, `CANCELLED`), `reason`, counts, and one entry per search with `status` (`complete`, `partial`, `no_results`, `not_found`, `error`, `skipped`), `listings`, `promoted`, `totalAvailable` and `skippedAsSeen`.

### Pricing and limits

#### Pricing unit

This Actor uses pay-per-event pricing. You pay for:

| Event | Price | When |
| --- | --- | --- |
| Actor start | $0.01 | once per run (one event per GB of memory, minimum one; runs use 256 MB by default, so one event) |
| Saved listing | $0.0007 (Free plan), $0.00066 (Bronze), $0.00063 (Silver), $0.0006 (Gold and higher) | for each listing saved to the Dataset |

That is $0.70 per 1,000 listings on the Free plan, plus $0.01 per run. Platform usage (compute, storage) is included; you do not pay it separately.

- A run with no listings (no results, filter with no match, unchanged `onlyNew` run, input error) costs only the start event: $0.01.
- Listings that are skipped (`onlyNew` already seen, `includePromoted: false`, duplicates in one run) are not charged.
- If you set a maximum cost for the run, the Actor stops when the next listing does not fit. The run still ends `SUCCEEDED`, with `RUN_SUMMARY.status` = `PARTIAL` and `reason` = `CHARGE_LIMIT`. Saved listings stay.

#### Cost examples

Free plan prices. Times are from real test runs.

| Scenario | Input scope | Listings | Start | Listings charge | Total | Time |
| --- | --- | ---: | ---: | ---: | ---: | --- |
| First test | `pl`, `iphone`, `maxItems: 20` | 20 | $0.01 | $0.014 | $0.024 | 2–9 s |
| One city | 1 keyword, `maxItems: 250` | 250 | $0.01 | $0.175 | $0.185 | ~8 s |
| Large | 5 searches × 1,000 | 5,000 | $0.01 | $3.50 | $3.51 | 83–143 s |
| Nothing found | 50 keywords with no results | 0 | $0.01 | $0 | $0.01 | ~21 s |
| Unchanged monitoring | `onlyNew`, no new listings | 0 | $0.01 | $0 | $0.01 | ~3 s |

### Use cases

| Buyer job | Input path | Output entity | Key fields | Next integration |
| --- | --- | --- | --- | --- |
| Resell phones and electronics | `queries`, `priceMax` | listing | `price`, `params`, `postedAt`, `url` | Google Sheets or CSV |
| Car market analysis | `categoryUrls` (cars category) | listing | `price`, `params` (year, mileage, fuel), `city` | BI tool via API |
| Real estate in one city | `categoryUrls` or `queries` + `city` | listing | `price`, `params` (area, rooms), `district`, `latitude` | map or spreadsheet |
| Price comparison across countries | same keyword, different `country` | listing | `price`, `currency`, `country` | Dataset export |
| New listing alerts | `onlyNew` on a schedule | new listing | `title`, `price`, `url`, `isNew` | webhook, Slack or e-mail |

### Monitoring: only new listings

Turn on `onlyNew` and run the same input on an Apify schedule.

- The first run returns current listings and remembers them.
- Next runs return only listings that were created after the last run and were not returned before. They have `isNew: true`.
- When nothing changed, the run saves 0 rows and `RUN_SUMMARY.status` is `NO_RESULTS`.
- Memory is kept per search in your account, in the key-value store `olx-listings-scraper-state`. Change the input and the Actor starts a new memory for the new search.

### API and integrations

- **API:** start the Actor with the same JSON input as in the examples, then read the Dataset items. Use `?view=overview` for the **Listings** columns.
- **Export:** JSON, CSV, Excel, XML and other formats from the Dataset.
- **Scheduling:** create an Apify schedule with `onlyNew: true` for monitoring.
- **Webhooks / no-code:** use Apify integrations (Make, Zapier, Google Sheets, Slack) to send new rows on run finish.

### Use with AI agents (MCP)

- MCP server URL with only this Actor: `https://mcp.apify.com?tools=cliqtomedia/olx-listings-scraper`
- Smallest useful input:

```json
{ "country": "pl", "queries": ["iphone"], "maxItems": 20 }
```

- Key output fields: `title` (listing title), `price` and `currency` (asking price; `null` = no numeric price), `city` (location), `postedAt` (created time), `url` (listing page).
- A run with 20 listings takes a few seconds and costs $0.024 on the Free plan. Keep `maxItems` small; OLX gives at most about 1,000 listings per search.

### Limits and partial results

- At most about 1,000 listings per search (OLX limit). `RUN_SUMMARY.searches[].totalAvailable` shows how many OLX reports.
- Up to 50 keywords and URLs per run, of them at most 10 URLs (each URL search first loads the OLX page to read its filters). 5 searches × 1,000 listings (5,000 rows) were tested in one run.
- The run stops new requests shortly before its timeout and keeps saved rows (`PARTIAL`, `TIME_LIMIT`). The default timeout is 300 s; raise it for large runs.
- Search relevance is OLX's own: a keyword can return related items (for example cases and glass for `iphone`). Use `priceMin` or a category URL to narrow.
- OLX blurs coordinates: `latitude` and `longitude` are approximate.

### Troubleshooting

#### The search returns 0 listings

Symptom: the Dataset is empty, search status `no_results`.
Likely reason: the keyword, city or price filter matches nothing on this site.
Check: open the same search on OLX in a browser.
Action: try a shorter keyword, remove `city` or widen the price range.

#### Search status `not_found`

Symptom: one search has `not_found`; the others work.
Likely reason: the `city` slug or the OLX URL does not exist on this site (for example `almaty` instead of `alma-ata`).
Check: copy the city slug from an OLX URL.
Action: fix the slug or URL and run again.

#### Run is `PARTIAL` with reason `CHARGE_LIMIT`

Symptom: fewer rows than `maxItems`.
Likely reason: the maximum cost of the run was reached.
Action: raise the maximum cost in run options, or lower `maxItems`.

#### Search status `error`

Symptom: `errorCode` such as `BLOCKED`, `RATE_LIMITED` or `SOURCE_UNAVAILABLE`.
Likely reason: OLX did not answer or limited requests. This is not an empty result.
Action: run again later. Rows saved before the error stay in the Dataset.

### FAQ

#### Do I need an OLX account or proxy?

No. The Actor reads public OLX search results without login. If a request is blocked, it retries through Apify Proxy, which is included in the price.

#### Why is `price` null for some listings?

The listing has no numeric price: it is for exchange (`priceType: exchange`) or the seller did not give a price. Free listings have `price: 0`.

#### Does it collect phone numbers or seller names?

No. Phone numbers and e-mails are not collected. `sellerName` is filled only for business sellers; for private sellers it is always null.

#### Are the results complete and fresh?

Each row is what OLX showed at `fetchedAt`. OLX limits a search to about 1,000 listings, and paid listings can appear in several places. The Actor saves each listing once per run.

#### Can I search OLX Brazil or India?

No. Only olx.pl, olx.ua, olx.kz, olx.pt, olx.ro, olx.bg and olx.uz are supported.

### Support

For a bug, question or feature request, open an issue on the **Issues** tab of this Actor. Include the run ID, the input (keywords, country, URLs) and the status message. Never send tokens or account data.

# Changelog

This Actor's version history is a separate document: https://apify.com/cliqtomedia/olx-listings-scraper/changelog.md

# Actor input Schema

## `country` (type: `string`):

Which OLX site keyword searches run on: pl = olx.pl, ua = olx.ua, kz = olx.kz, pt = olx.pt, ro = olx.ro, bg = olx.bg, uz = olx.uz. URLs below always use the site from the URL itself.

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

One OLX search per keyword, e.g. iphone, bmw x5 or mieszkanie. Up to 50 keywords and URLs together. Leave empty when you paste category URLs below.

## `categoryUrls` (type: `array`):

Paste any OLX results page with your filters already set, e.g. https://www.olx.pl/motoryzacja/samochody/bmw/warszawa/ or https://www.olx.ua/uk/nedvizhimost/kvartiry/kiev/. Category, city and the page's own filters are kept. Offer (single listing) pages are not supported. Up to 10 URLs per run.

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

Limit keyword searches to one city or region, written as in the OLX address bar: warszawa, krakow, kiev, alma-ata, astana, lisboa, bucuresti, sofiya, tashkent. Accents are removed automatically (Kraków → krakow). An unknown city gives status not_found for those searches. Empty = whole country.

## `priceMin` (type: `integer`):

Lowest price in the site's currency (PLN, UAH, KZT, EUR, RON, BGN/EUR, UZS). Applies to all searches and URLs. Empty = no minimum.

## `priceMax` (type: `integer`):

Highest price in the site's currency. Applies to all searches and URLs. Empty = no maximum.

## `sortBy` (type: `string`):

Order of results. newest = newest and recently refreshed first (best for monitoring and onlyNew).

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

Stop each keyword or URL after this many listings. OLX itself shows at most about 1,000 listings per search; narrow by city, category or price to get more. You pay per listing saved.

## `onlyNew` (type: `boolean`):

For scheduled monitoring: return only listings created after the previous run of the same search and not returned before. The first run returns current listings. Memory is kept in your account in the key-value store olx-listings-scraper-state.

## `includeDescription` (type: `boolean`):

Add the full listing description as plain text. Turn off for smaller output.

## `includePromoted` (type: `boolean`):

OLX mixes paid (promoted) listings into every results page. They (and TOP ads among the results) are marked isPromoted = true. Turn off to keep only organic results.

## Actor input object example

```json
{
  "country": "pl",
  "queries": [
    "iphone"
  ],
  "sortBy": "newest",
  "maxItems": 20,
  "onlyNew": false,
  "includeDescription": true,
  "includePromoted": true
}
```

# Actor output Schema

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

Listings with price, location, category, parameters, dates, photos and seller type.

## `runSummary` (type: `string`):

Run status, status of every search and request statistics.

# 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 = {
    "country": "pl",
    "queries": [
        "iphone"
    ],
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("cliqtomedia/olx-listings-scraper").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 = {
    "country": "pl",
    "queries": ["iphone"],
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("cliqtomedia/olx-listings-scraper").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 '{
  "country": "pl",
  "queries": [
    "iphone"
  ],
  "maxItems": 20
}' |
apify call cliqtomedia/olx-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,cliqtomedia/olx-listings-scraper"
        }
    }
}
```

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/R4hMWg12sSoShyrvT/builds/rrjEqvDjhOR0aYedR/openapi.json
