# OLX Scraper — Listings, Prices & Sellers | $4/1K (`bovi/olx-listings`) Actor

Scrape OLX listings via its public internal API. Get titles, prices, seller locations and listing URLs. Run with searchQuery; no OLX login or buyer-supplied API key needed. Pricing: $0.004/listing on Free, plus $0.00005 per Actor Start.

- **URL**: https://apify.com/bovi/olx-listings.md
- **Developed by:** [Vitalii Bondarev](https://apify.com/bovi) (community)
- **Categories:** E-commerce, MCP servers
- **Features:** Limited permissions
- **Stats:** 43 total users, 6 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.88 / 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

## OLX Listings Scraper

Scrape OLX classified listings by keyword from the OLX public internal API on `olx.pl`, `olx.ua`, `olx.bg`, `olx.ro` and `olx.pt`, with no OLX login. On the Free plan, pricing is $0.004 per listing plus a $0.00005 Actor Start event.

- Extract titles, descriptions, prices, currencies, locations, photos and canonical URLs.
- Compare classified prices and locations across OLX country domains.
- Review cars, electronics and real-estate listings for arbitrage research.
- Collect seller IDs, names, category IDs and timestamps for lead-generation workflows.

### What you get

Fields are `null` when OLX omits them; `negotiable` and `delivery_available` default to `false`, `photos` and `warnings` are empty arrays, and `domain` and `parse_confidence` are always set.

| Field | Type | Description |
|---|---|---|
| `offer_id` | integer | Numeric OLX offer ID; `null` if absent. |
| `title` | string | Listing title; `null` if absent. |
| `description` | string | HTML-free description; `null` if absent or empty. |
| `price` | number | Numeric price; `null` if absent. |
| `currency` | string | Listing currency; `null` if absent. |
| `negotiable` | boolean | Whether the price is negotiable; `false` if no flag or price parameter is provided. |
| `city` | string | Listing city; `null` if absent. |
| `region` | string | Listing region; `null` if absent. |
| `category_id` | integer | OLX category ID; `null` if absent. Output only; no category filter. |
| `seller_id` | integer | OLX seller ID; `null` if absent. |
| `seller_name` | string | Seller display name; `null` if absent. |
| `seller_last_seen` | ISO 8601 string | Seller last-seen timestamp; `null` if absent. |
| `url` | string | Canonical listing URL; `null` if absent. |
| `photo_url` | string | First photo at 400×400; `null` if unavailable. |
| `photos` | array of strings | All photos at 400×400; empty if unavailable. |
| `created_time` | ISO 8601 string | Listing creation time; `null` if absent. |
| `last_refresh_time` | ISO 8601 string | Last refresh time; `null` if absent. |
| `delivery_available` | boolean | Whether OLX Delivery (Rock) is active; `false` unless active. |
| `domain` | string | OLX domain used; always set. |
| `parse_confidence` | number | Number from 0 to 1: 1 minus deductions, clamped to 0–1. |
| `warnings` | array of strings | Quality codes; empty if none. Codes: `offer_id_missing`, `title_missing`, `price_missing`, `currency_missing`, `city_missing`, `url_missing`, `photo_missing`. |

| Code | Deduction | Line |
|---|---|---|
| `offer_id_missing` | 0.5 | `src/normalize.py:130` |
| `title_missing` | 0.2 | `src/normalize.py:134` |
| `price_missing` | 0.2 | `src/normalize.py:158` |
| `currency_missing` | 0.05 | `src/normalize.py:160` |
| `city_missing` | 0.05 | `src/normalize.py:169` |
| `url_missing` | 0.1 | `src/normalize.py:184` |
| `photo_missing` | 0.05 | `src/normalize.py:194` |

### Sample output

Example row for the keyword `nike` on `olx.pl`.

```json
{
  "offer_id": 1102683547,
  "title": "Nike shox czarne",
  "description": "Nike Shox – czarne, nowe Sprzedam nowe, nieużywane buty Nike Shox w kolorze czarnym. Sportowy model z charakterystyczną podeszwą Shox. Buty nigdy nie były noszone. Rozmiar: 45 Stan: nowe Kolor: czarny Cena: 349 zł Możliwa wysyłka Paczkomatem InPost po wcześniejszym opłaceniu. Możliwy również odbiór osobisty. Brak pudełka",
  "price": 299, "currency": "PLN",
  "negotiable": false, "city": "Jaworze",
  "region": "Śląskie", "category_id": 2961,
  "seller_id": 980297664, "seller_name": "Piotr",
  "seller_last_seen": "2026-10-10T21:35:36+02:00",
  "url": "https://www.olx.pl/d/oferta/nike-shox-czarne-CID87-ID1cCKmw.html",
  "photo_url": "https://ireland.apollo.olxcdn.com:443/v1/files/oa1gn3i8f6op-PL/image;s=400x400",
  "photos": ["https://ireland.apollo.olxcdn.com:443/v1/files/oa1gn3i8f6op-PL/image;s=400x400", "https://ireland.apollo.olxcdn.com:443/v1/files/zej93z5rg7s3-PL/image;s=400x400", "https://ireland.apollo.olxcdn.com:443/v1/files/who3vj2ojtxt2-PL/image;s=400x400", "https://ireland.apollo.olxcdn.com:443/v1/files/88zct9vc317r2-PL/image;s=400x400"],
  "created_time": "2026-10-04T19:07:02+02:00",
  "last_refresh_time": "2026-10-13T21:37:02+02:00",
  "delivery_available": true, "domain": "olx.pl",
  "parse_confidence": 1, "warnings": []
}
```

`price` is the structured OLX price. `description` is the seller's text and can quote a different price, as `Cena: 349 zł` does here.

### Pricing

Pricing is pay per event:

| Plan | Event | Price per event |
|---|---|---:|
| Free plan | `apify-actor-start` | $0.000050 |
| Free plan | `apify-default-dataset-item` | $0.004000 |

`apify-actor-start` is charged once per GB of run memory, with a minimum of one event. `apify-default-dataset-item` represents one OLX listing. The `listing-item` event has no price, so the buyer is not charged for it.

Worked example: **100 results = $0.40005 on Free**: 100 × $0.004000 plus $0.000050.

On Free, 1,000 listing events = 1,000 × $0.004000 + $0.000050 = $4.00005, and 10,000 listing events = 10,000 × $0.004000 + $0.000050 = $40.00005.

The Apify Free plan includes **$5 of monthly platform usage credit**. The Free plan's $5 credit covers **1 full run (1,249 listing events)** when the run uses the minimum one Actor Start event.

You pay only for the events listed above. This Actor does not use the Pay per event + usage option, so compute, proxy traffic and storage are not billed separately.

### How to use

1. **Enter** the required `searchQuery`, such as `nike`, `iphone 13` or `laptop`.
2. **Set** `domain` to `olx.pl`, `olx.ua`, `olx.bg`, `olx.ro` or `olx.pt`.
3. **Choose** `maxItems`; set `0` to read pages until OLX returns no more. The Actor stops on an empty page, a page containing only repeated listings, or no next page. OLX caps search results at 1,000 per query.
4. **Add** `minPrice` or `maxPrice` for client-side filtering in the listing's local currency. Use `0` to disable a boundary. `minPrice` excludes listings without a price; `maxPrice` keeps them.
5. **Run** the Actor and inspect fields such as `price`, `currency`, `photos`, `seller_name`, `delivery_available`, `parse_confidence` and `warnings`.
6. **Schedule** repeat runs through Apify Schedules; daily is a practical starting point for listing and price monitoring.

Example input:

```json
{
  "searchQuery": "nike",
  "domain": "olx.pl",
  "maxItems": 100,
  "minPrice": 0,
  "maxPrice": 0
}
```

Export the dataset as JSON or CSV, or read it through the Apify dataset API.

### Input parameters

| Parameter | What it does | Default |
|---|---|---|
| `searchQuery` | Required keyword or keywords sent to OLX. Blank input ends the run without rows. | Required |
| `domain` | OLX domain to search. | `olx.pl` |
| `maxItems` | Maximum listings; `0` means no Actor-level limit. | `100` |
| `minPrice` | Removes listings below this local-currency value and listings without a price; `0` disables it. | `0` |
| `maxPrice` | Removes listings above this local-currency value; keeps listings without a price; `0` disables it. | `0` |
| `proxyConfiguration` | Optional Apify proxy for OLX requests; failed setup does not stop the run. | Not set |
| `disableUsageStats` | Set to `true` to turn off the run summary described in Usage statistics. | `false` |

### Limits and edge cases

For applicable rows, `OUTPUT` contains `totalItems`, `failedCount`, `query`, `domain` and `scrapedAt`. For a blank `searchQuery`, it contains only `error`.

| Condition | What you see | What to do |
|---|---|---|
| A query has more than 1,000 OLX results | At most 1,000 listings. | Use narrower or multiple searches. |
| A price filter is used with non-zero `maxItems` | The Actor reads at most 3 × `maxItems` listings before filtering, so fewer than `maxItems` rows may result. With `maxItems` at `0`, there is no scan cap. | Raise `maxItems` or narrow the keyword. |
| OLX returns no listings for the keyword | Empty dataset and a **Succeeded** run. The status message and log warning give the reason; `OUTPUT` contains the zero-item summary. | Use a broader or local-language keyword and the matching domain. |
| `minPrice` or `maxPrice` removes every listing | Empty dataset, **Succeeded** run, status message and `OUTPUT` summary. | Widen or clear the range. |
| `searchQuery` is missing or blank | No rows; **Succeeded** run; `OUTPUT` is `{"error": "searchQuery_required"}`. | Enter a keyword and run again. |
| OLX blocks or rejects a request | HTTP 429, HTTP 5xx and network errors are tried 3 times total, waiting 2 s and 4 s between attempts. Other errors such as 403, 404 or 400 stop immediately. If no rows were pushed, the run still ends **Succeeded**; `OUTPUT` shows `totalItems` 0 and `failedCount` 1. | Run later; for 403 add `proxyConfiguration`. |
| A later page fails after earlier pages were fetched | Earlier listings are pushed; the error is logged, `failedCount` is 1, and no status message is set when at least one row was returned. | Review returned rows and run again. |
| An abort, timeout or crash occurs | During fetching, pages are fetched before rows are pushed, so the dataset stays empty and no `OUTPUT` summary is written. During pushing, already-pushed batches remain. | Run again; a lower `maxItems` means fewer pages before pushing. |
| Promoted listings repeat across pages | Repeated offer IDs are removed during pagination. | Use `offer_id` for downstream checks. |

### FAQ

#### How much does it cost to scrape OLX listings?

On the Free plan, listings cost $0.004 each and the Actor Start event costs $0.000050. **100 results = $0.40005 on Free.**

#### Why are no OLX listings returned?

The query may have no matches, use the wrong language for the domain, or be removed by price filters. Check the status message and `OUTPUT`, then broaden the keyword or price range.

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

No OLX login is required, and the public API works from Apify cloud IPs without a proxy. An optional `proxyConfiguration` is available if you observe a 403 response.

#### Why use this instead of the official OLX API?

This Actor uses the OLX public internal API and converts responses into flat dataset rows. It handles pagination, repeated offer IDs, 400×400 photos and client-side price filters.

#### Is using public OLX data legal or allowed?

The Actor accesses OLX public data. Whether a use is legal or allowed depends on the source terms and applicable law for your use case; review those requirements before using the data.

### Related actors

- [Allegro Offers](https://apify.com/bovi/allegro-offers) — related Poland/CEE marketplace offers, prices and sellers.
- [Leboncoin Listings](https://apify.com/bovi/leboncoin-listings) — classifieds listings from France.
- [Depop Scraper](https://apify.com/bovi/depop-scraper) — fashion resale and sold items.

### Usage statistics

This Actor creates a small, content-free summary at the end of each run, used only to monitor reliability and improve this Actor. No input values, credentials or scraped data are sent.

A copy of the exact record for your run is saved as `USAGE_STATS` in your own Apify key-value store.

To opt out, set `disableUsageStats` to `true` in the input. Nothing is sent then.

[Full list of collected fields](https://api.apify.com/v2/key-value-stores/v9rgHjMKLDGtHf8tD/records/index.html)

# Actor input Schema

## `searchQuery` (type: `string`):

Keyword(s) to search for on OLX (e.g. 'nike air max', 'iphone 13', 'laptop'). Required.

## `domain` (type: `string`):

OLX country domain to search. Examples: olx.pl (Poland), olx.ua (Ukraine), olx.bg (Bulgaria), olx.ro (Romania), olx.pt (Portugal). Default: olx.pl.

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

Maximum number of listings to return (0 = no limit, fetches all pages). Default 100.

## `minPrice` (type: `integer`):

Skip listings with price below this value (in the local currency). 0 = no minimum.

## `maxPrice` (type: `integer`):

Skip listings with price above this value (in the local currency). 0 = no maximum.

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

Optional Apify proxy. The OLX public API works without a proxy from Apify cloud IPs. Only needed if you observe 403 errors.

## `disableUsageStats` (type: `boolean`):

See the README Usage statistics section for details.

## Actor input object example

```json
{
  "searchQuery": "nike",
  "domain": "olx.pl",
  "maxItems": 100,
  "minPrice": 0,
  "maxPrice": 0,
  "proxyConfiguration": {},
  "disableUsageStats": false
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset containing OLX listing records (offer_id, title, price, currency, city, region, seller_name, url, photo_url, created_time, etc.)

# 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 = {
    "searchQuery": "nike",
    "domain": "olx.pl",
    "maxItems": 100,
    "minPrice": 0,
    "maxPrice": 0,
    "proxyConfiguration": {}
};

// Run the Actor and wait for it to finish
const run = await client.actor("bovi/olx-listings").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 = {
    "searchQuery": "nike",
    "domain": "olx.pl",
    "maxItems": 100,
    "minPrice": 0,
    "maxPrice": 0,
    "proxyConfiguration": {},
}

# Run the Actor and wait for it to finish
run = client.actor("bovi/olx-listings").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 '{
  "searchQuery": "nike",
  "domain": "olx.pl",
  "maxItems": 100,
  "minPrice": 0,
  "maxPrice": 0,
  "proxyConfiguration": {}
}' |
apify call bovi/olx-listings --silent --output-dataset

```

## MCP server setup

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

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/d6eFNuchkWY4t0goJ/builds/UOlzkgBdtZ8xjQfCM/openapi.json
