OLX Scraper - Poland, Romania, Ukraine, Bulgaria & Portugal avatar

OLX Scraper - Poland, Romania, Ukraine, Bulgaria & Portugal

Pricing

from $1.00 / 1,000 run start fees

Go to Apify Store
OLX Scraper - Poland, Romania, Ukraine, Bulgaria & Portugal

OLX Scraper - Poland, Romania, Ukraine, Bulgaria & Portugal

Search OLX in Poland, Romania, Bulgaria, Ukraine and Portugal and get every ad as a row: title, asking price as a number, currency, the seller's town, new or used, and whether the price is negotiable. For price research, resellers and market monitoring.

Pricing

from $1.00 / 1,000 run start fees

Rating

0.0

(0)

Developer

SR

SR

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

13 days ago

Last modified

Share

OLX Scraper

OLX Scraper searches OLX and returns ads as rows: title, asking price as a number, the seller's town, whether the item is new or used, and whether the price is negotiable. Covers Poland, Romania, Bulgaria, Ukraine and Portugal from one actor.

The actor reads public search and category listings. You do not need an OLX account. Choose a search term in the local language or paste an OLX search URL with the filters you need.

Use it for second-hand price research, cross-border reselling, supply monitoring in a category, or any dataset of classified ads that you would otherwise copy out of the browser by hand. Results come out as JSON, CSV, Excel or through the Apify API, with the same field names in every country.

What OLX Scraper returns

  • Five markets, one actor. Each OLX country runs its own domain and its own search path: /oferty/ in Poland, /oferte/ in Romania, /ads/ in Bulgaria and Portugal, /uk/list/ in Ukraine. Pick a market and the right shape is used
  • Currency read off the price, not assumed. Bulgaria has moved to the euro, so olx.bg now prints 139.99 €. Anything with BGN hard-coded is mislabelling every Bulgarian row today
  • Prices parsed per row, not per locale. Portugal writes 1.400 € meaning fourteen hundred; Bulgaria writes 139.99 € meaning a hundred and forty. Same character, opposite meanings, same website. Both come out right
  • price_type instead of a bare null. A free ad, a swap-only ad and an ad with no stated price are three different things, and none of them is a parse failure
  • negotiable as its own flag, because "6 800 zł do negocjacji" is an opening position rather than a price
  • Condition in the market's own wording where the seller set it, read from the card rather than translated
  • Ad id, town and posting date on every row, so consecutive runs diff cleanly

Why OLX

OLX is the classifieds market across Central and Eastern Europe and Portugal. In Poland it is where used goods are actually bought and sold, the way Marktplaats is in the Netherlands or Kleinanzeigen is in Germany. For second-hand pricing in those countries there is no meaningful second source.

Because it is one platform under many domains, the same query can be run across five countries and compared directly. That is the part most tooling misses: the country-scoped actors on the Store cover one market each, so a cross-border comparison means running several and reconciling their formats yourself. The formats are the hard part, and they are not consistent even within OLX.

Input

FieldTypeRequiredDefaultWhat it does
querystringone of the twonone (prefill rower)What to search for, in the market's language
marketselectnoplpl, ro, bg, ua or pt
urlstringone of the two–An OLX search or category URL, from the desktop or the mobile site. Takes precedence
price_minintegerno–Lower bound in the market's currency
price_maxintegerno–Upper bound in the market's currency
limitintegerno50Ads to return, 1 to 1000. A page carries about 50
retriesintegerno3Retry attempts per page, 1 to 6

A full input with every option, as used for a real run on the Portuguese site:

{
"query": "bicicleta",
"market": "pt",
"price_min": 100,
"price_max": 500,
"limit": 120,
"retries": 2
}

That run returned 120 ads from three result pages, all priced between 100 and 500 €, 50 of them marked negotiable.

How to scrape OLX with OLX Scraper

  1. Pick the market. pl for olx.pl, ro for olx.ro, bg for olx.bg, ua for olx.ua, pt for olx.pt.
  2. Type the search term in that market's language. rower in Poland, bicicletă in Romania, колело in Bulgaria, велосипед in Ukraine, bicicleta in Portugal. An English term works only as far as sellers write English titles.
  3. Or paste a URL. Open the OLX site, set the category and filters you want, and copy the address bar into url. A link copied on your phone (m.olx.pl/...) works as well as the desktop address. Keep market on the same country.
  4. Set limit. 50 is one result page; 1000 is about twenty.
  5. Run, then export. The dataset downloads as JSON, CSV or Excel, or comes back from the API in the same call when you use the synchronous run endpoint.

Output

{
"ad_id": "1098286495",
"url": "https://www.olx.pl/d/oferta/rower-szosowy-kolarka-vintage-CID767-ID1ckiuj.html?search_reason=search%7Cpromoted",
"title": "Rower szosowy kolarka vintage",
"price": 900.0,
"price_text": "900 zł",
"price_type": "asking price",
"negotiable": false,
"currency": "PLN",
"location": "Nowy Glinnik",
"posted_label": "Odświeżono dnia 02 października 2026",
"condition": "Używane",
"is_promoted": false,
"image": "https://ireland.apollo.olxcdn.com:443/v1/files/bw22j0yc5aav-PL/image;s=216x152;q=50",
"market": "pl",
"query": "rower",
"position": 1,
"country": "PL",
"fetched_at": "2026-10-04T03:46:59.273757Z",
"source": "olx-scraper",
"listing_id": "1098286495",
"image_url": "https://ireland.apollo.olxcdn.com:443/v1/files/bw22j0yc5aav-PL/image;s=216x152;q=50"
}

Two more real rows from the same day. A free ad in Poland, where price is 0 and price_type says why:

{
"ad_id": "1102516739",
"title": "Rower oraz hulajnoga dla dziewczynki",
"price": 0.0,
"price_text": "Za darmo",
"price_type": "free",
"negotiable": false,
"currency": "PLN",
"location": "Chylice",
"posted_label": "03 października 2026",
"condition": "Używane",
"market": "pl",
"position": 4
}

And a negotiable ad in Portugal, where the price text carries the flag:

{
"ad_id": "673969412",
"title": "Bicicleta de estrada Bianchi ML3 Alloy Reparto Corse, ano 2000",
"price": 495.0,
"price_text": "495 € Negociável",
"price_type": "asking price",
"negotiable": true,
"currency": "EUR",
"location": "Estrela",
"posted_label": "01 de outubro de 2026",
"condition": "Usado",
"market": "pt",
"position": 2
}

Both rows are shortened for reading; in the dataset they carry every field shown in the first example.

Output fields

FieldTypeMeaning
ad_idstringOLX's id for the ad
urlstringLink to the ad page
titlestringAd title as the seller wrote it
pricenumber or nullAsking price; 0 for a free ad, null for swap or no price
price_textstring or nullThe price exactly as OLX shows it
price_typestringasking price, free, swap or not stated
negotiablebooleanThe seller marked the price as negotiable
currencystringPLN, RON, EUR or UAH, read from the price
locationstring or nullTown (and district where given)
posted_labelstring or nullPosting or refresh date in the market's language
conditionstring or nullNew or used, in the market's wording
is_promotedbooleanPromoted-ad flag
imagestring or nullThumbnail URL
marketstringThe market you searched
querystring or nullYour search term, or null for a URL run
positionintegerRank in the results, 1 upward across pages

The existing row fields remain available. Each row also has source, listing_id, image_url, fetched_at and country. listing_id repeats ad_id; image_url repeats image. fetched_at is a UTC timestamp shared across the search, including later pages. country is the uppercase country code for market. These additions help combine results from different marketplaces without changing existing consumers.

The summary record reports returned ads, pages containing ads, price states, negotiability, location and condition coverage, the market and the currencies observed. If a later page cannot be read, already collected ads are retained and the errors record identifies the affected page. Missing results are never represented as invented ads.

Use cases

Second-hand pricing in a country you do not live in. Run your product term, filter to price_type: asking price, and take the median. condition lets you separate the new-in-box listings from the used ones, which usually sit in different price bands.

Cross-border arbitrage. The same query in pl, ro and ua returns three price distributions in three currencies. Traders live on that spread, and running it from one actor means the parsing is consistent across all three rather than three different scrapers' idea of a number.

Watching supply in a category. Schedule a query and count rows per run. posted_label shows how fresh the top of the results is, and diffing ad_id between runs tells you what appeared and what sold.

Finding dealers among private sellers. A seller posting many Nowe items in the same category is trading, not clearing out a garage. Group by location and condition to find them.

Lead lists. ad_id, title, location and url are enough to build a contact list for a category, with the ad page one fetch away.

OLX Scraper compared with the alternatives

OptionWhat you getWhere it falls short
OLX partner API (developer portals per country)Managing your own ads as a registered business partnerIt is for posting and managing your listings, not for searching everyone else's. Access per country, per account
Your own script (the many GitHub OLX scrapers)Full controlEach country has its own paths and price formats; scripts written for one market break on the next, and they stop working when the page layout changes
Scraping APIs and data vendorsGeneric page fetching or bulk datasetsYou still parse the page yourself, or you buy a dataset on someone else's schedule
Single-country OLX actorsOne market, often with more fields for that marketA cross-border comparison means running several and reconciling their formats
This OLX ScraperSearch results from five OLX countries in one schema, prices as numbers, currency per row, pay per adReads the results page only: no seller phone numbers or full descriptions

Pricing

Two events. run_start costs $0.001 per run. listing costs $0.001 per ad written to the dataset, which is $1.00 per 1,000 ads. Only ads written to the dataset incur the listing event. Empty searches and unavailable pages incur no listing charge; the run-start event still applies. Free Apify users receive at most 10 ads per run. Paying users can request up to 1000 ads. All pricing is pay-per-event, with no per-compute-unit charges.

RunCharge
Prefill (rower in Poland, 50 ads)$0.001 + 50 × $0.001 = $0.051
1000 ads$0.001 + 1000 × $0.001 = $1.001
Search with no results$0.001

Limits and gotchas

  • The search path differs per country. If you paste a URL, paste it from that country's own site. A Polish path on the Romanian domain returns a 404 page that still renders the site chrome, so it looks like a working request with no results.
  • Bulgaria prices in euro now. currency is read from the price text, so Bulgarian rows come back as EUR. If you have historical BGN data, the changeover is yours to reconcile.
  • posted_label is not a timestamp. OLX writes dates in the market's own language ("26 sierpnia 2026", "Обновено на 31 август 2026 г."), and it is returned verbatim rather than parsed through a month-name table per market that would silently be wrong somewhere.
  • Condition is optional for sellers. Coverage runs from about 97% in Romania down to roughly 23% in Bulgaria. The summary reports it per run so you know before you filter on it.
  • A free ad is 0, a swap ad is null. price_type distinguishes them. Filter to asking price before averaging anything.
  • Zero search results stay empty. Recommendations shown below an empty results grid are excluded. OLX can also broaden a query and return genuine suggested matches; check titles when an exact text match matters.
  • Promoted ads repeat across pages. The walk deduplicates on ad_id, so a deep run returns slightly fewer rows than pages times 50. That is correct, not loss.

FAQ

Which OLX countries are supported? Poland, Romania, Bulgaria, Ukraine and Portugal, through the market field. OLX runs more domains than that; these five are the ones verified working.

Why is my Bulgarian result in euro? Because that is what OLX shows there now. The currency comes from the price on the page rather than a table in the code.

Why do some ads have no price? Check price_type. Swap-only ads have no asking price at all, and a small number of ads state none. Free ads come back as 0 with price_type: free.

Can I paste a link from the OLX mobile site? Yes. Addresses on m.olx.pl, m.olx.ro and the other mobile hosts of the five markets are accepted alongside olx.pl and www.olx.pl. OLX forwards them to the regular results page, and you get the same rows. Only the five supported OLX domains are fetched.

Can I filter by price? Yes, price_min and price_max, in the market's own currency.

How many ads can I get in one run? Up to 1000, about 20 pages.

Does it return seller phone numbers? No. The results page does not carry them and this actor reads only the results page.

Is there an official OLX API for this? OLX runs partner APIs per country, but they are for businesses that post and manage their own ads. They do not offer a search across everyone's listings. OLX Scraper fills that gap from the public search pages.

Do I need an OLX account or login? No. The actor reads the same public result pages anyone can open in a browser.

Can I call OLX Scraper from my own code? Yes. Every Apify actor has an HTTP API and clients for Python and JavaScript. Start a run with your input and read the dataset back as JSON, or use the synchronous endpoint to get the rows in the same request.

Does it work for OLX Brazil or OLX India? Not at the moment. The five markets above are the ones this actor is built and verified for; other OLX countries are not covered.