OLX Listing Scraper: Poland Classifieds Data
Pricing
from $1.52 / 1,000 listing returneds
OLX Listing Scraper: Poland Classifieds Data
OLX scraper for Poland, Portugal, Romania, Bulgaria and Ukraine: search OLX for a list of keywords without login and get title, price, city, seller type, link. Monitoring returns new listings, price drops and gone ones: an OLX sold items tracker with sell-through rate and median price.
Pricing
from $1.52 / 1,000 listing returneds
Rating
0.0
(0)
Developer
Adriana Voss
Maintained by CommunityActor stats
0
Bookmarked
7
Total users
4
Monthly active users
18 hours ago
Last modified
Categories
Share
OLX Listing Lookup: olx.pl scraper from $2/1k
You type a search the way you'd type it into OLX's own search box ("iphone", "rower gorski", "mieszkanie warszawa"), and this actor runs it against OLX's own internal search API, across five OLX country sites (Poland, Portugal, Romania, Bulgaria, Ukraine), and returns one clean row per listing: title, price, city, seller type, and a permanent link. Turn on Monitoring and the same search becomes a watchlist that only reports new listings and price drops since your last run, and, on request, the listings that disappeared: an OLX sold items tracker with a lifetime sell-through rate and the search's median price on every row.
OLX sits behind a CloudFront bot wall: a bare request gets a 403 "Request blocked" page, not the
listings. This actor requests every search through Apify's RESIDENTIAL proxy, which clears it
cleanly (a real JSON response comes back, no headless browser needed), with the original
__PRERENDERED_STATE__ HTML route kept as an automatic fallback if that ever changes. You never
have to think about either yourself.
What's new (2026-09-25)
Sold signal: a new "Alert on gone listings" checkbox (alertOnGone, off by default) returns
listings your watchlist saw before that have since disappeared from OLX, with lastPrice,
daysListed and gonePresumedSold. Every monitoring row now also carries sellThroughRate,
medianPrice / medianPriceCurrency, lastSeenAt and daysListed, and the search row carries
goneCount. See "Sold signal and sell-through" below. Existing watchlists keep their memory, no
column was removed or renamed, and pricing is unchanged: a gone row is an ordinary listing row.
What's new (2026-09-17)
Added Portugal, Romania, Bulgaria, and Ukraine (country input, defaults to pl; every existing
task and integration keeps working unchanged), new-listing/price-drop monitoring, and these output
columns: country, currency, postedAt, sellerType, sellerHash, sellerName (gated behind
"Include raw seller info", off by default), isPromoted, isNew, changeType, previousPrice,
priceDropPct, firstSeenAt, newCount, priceDropCount, monitorStatus. No column was removed
or renamed, and pricing is unchanged.
Who it's for
A reseller or arbitrage buyer watching one category (phones, bikes, electronics) for underpriced listings wants a live feed of what's actually posted right now on OLX, across many search terms at once, without refreshing OLX's own search page by hand. A market-research team tracking asking prices for a product category, or an apartment hunter scanning a city's rental listings, gets the same shape here: paste a list of search terms, get back a flat row per listing, and pay only for listings actually returned; a search that finds nothing costs nothing.
This actor is OLX's counterpart to leboncoin-listing-lookup (France) in this catalogue: both
take a free-text search term rather than a specific listing URL or ID, and return every matching
listing the site's own search turns up, for when you don't have specific ad links yet, only a
category or keyword you're watching.
Why this one
- Covers five OLX country sites from one actor. Poland, Portugal, Romania, Bulgaria, and Ukraine all share the exact same internal search API and result shape, confirmed directly by probing all five, not assumed. Pick the country from a dropdown; the search text and every other input stays the same.
- Gets past OLX's CloudFront wall for you. A plain request returns an HTTP 403 "Request
blocked" page on every OLX country site, confirmed directly, not assumed. This actor routes
every request through Apify's RESIDENTIAL proxy, which clears it cleanly, with the original
__PRERENDERED_STATE__HTML route (via UNBLOCKER) kept as an automatic fallback. - Reads OLX's own structured data, not scraped text. Every field here comes from OLX's own JSON, not regex'd out of visible page text, so prices, IDs, and location fields are exact, typed values rather than parsed strings.
- Monitoring built in. Turn on new-listing and price-drop alerts and this actor remembers what it has already shown you, so a scheduled run only returns what actually changed: see "Monitoring / only new results" below.
- Sold signal and sell-through rate. The same watchlist notices listings that disappeared (most often sold) and keeps a lifetime sell-through rate for the search, so you can see how fast a model actually moves at a given price, not just what is listed.
- Works across every OLX category, not just one. Electronics, vehicles, real estate, jobs,
general goods: OLX's per-listing
paramsvary by category (phone model and storage for a handset, mileage and fuel for a car), and this actor carries all of them through in a genericparamsobject instead of hardcoding one category's fields and dropping the rest. - Never charged for a miss, a filtered-out listing, or a quiet monitoring run. A search that
finds nothing, where every result falls outside your
minPrice/maxPricefilter, or where monitoring finds nothing new, still gets a row explaining what happened, and costs nothing. See "Pricing" below for the found-row rate.
What you get
One row per listing by default. (Turn off "One row per listing" in the Input tab to get one row
per search instead, with the whole listing list nested in listings.) Every row carries these
fields:
| Field | Type / format | Description |
|---|---|---|
query | text | The search term you passed in, unchanged. |
found | boolean | true if the search returned at least one listing. false rows are never charged. |
status | text | OK, NOT_FOUND (no listings for that search), BAD_FORMAT (a blank line), or BLOCKED. |
searchQuery | text | The search text actually sent to OLX. |
listingCount | number | How many listings this search returned after your price filters and monitoring: this is exactly what you're charged for. |
totalAvailable | number | OLX's own total-match count for this search. |
truncated | boolean | true if more listings were available than this run fetched. |
newCount / priceDropCount | number | New listings, and price drops, found this run (only meaningful with Monitoring on). |
goneCount | number | Listings this watchlist detected as gone this run (delisted, most often sold), whether or not "Alert on gone listings" returns them. null without a watchlist. |
monitorStatus | text | NO_NEW_ROWS or WATCHLIST_SEEDED on a quiet/seeded monitoring run, otherwise null; see "Monitoring" below. |
sellThroughRate | number | Monitoring only: listings this watchlist has seen go / listings it has ever tracked, 0 to 1, over its whole lifetime. null with Monitoring off. |
medianPrice / medianPriceCurrency | number / text | Monitoring only: median price of every listing this run read for the search (after your price filters), in the currency most of them use. Currencies are never mixed (olx.ua can list in both UAH and USD). null with Monitoring off. |
listings | array | The full listing list. Present in every row; it's what gets expanded into separate rows in "one row per listing" mode. |
listingId | text | OLX's own numeric listing ID. |
title | text | Listing title. |
description | text | Listing description (HTML stripped, contact-info-like strings redacted), truncated to 500 characters. |
price | number | Price in that country's own currency, or null for a free/price-on-request listing; see priceDisplay/isFree. |
priceDisplay | text | Price exactly as OLX formats it, e.g. "2 599 zł" or "1.199 €". |
currency | text | Currency code as OLX itself reports it for that listing (PLN, EUR, RON, UAH, ...). |
isFree | boolean | true for listings marked "free"/exchange rather than priced. |
city / region | text | Seller's stated location, as OLX displays it. |
country | text | Which OLX country site this listing came from (pl, pt, ro, bg, ua). |
isBusiness | boolean | true if the seller is a registered business account. |
sellerType | text | business or private: the same signal as isBusiness, spelled out. |
sellerHash | text | A short, one-way hash of the seller's OLX id: lets you spot the same reseller across listings without exposing who they are. Always on. |
sellerName | text | The seller's OLX display name. null unless "Include raw seller info" is on; see "Data & privacy". |
isPromoted | boolean | true if OLX itself is showing this as a paid/promoted placement. |
createdAt / postedAt | date (ISO) | When the listing was created, from OLX's own timestamp (carries a timezone offset). Both carry the same value; postedAt is the name used across this catalogue's other monitoring actors. |
changeType | text | new, price-drop, gone, or seen (only meaningful with Monitoring on). |
isNew | boolean | true when changeType is new. null when monitoring isn't tracking this search at all. |
previousPrice / priceDropPct | number | The price last seen for this listing, and the percentage drop, on a price-drop row. |
firstSeenAt | date (ISO) | When this watchlist first saw this listing. |
lastSeenAt / daysListed | date (ISO) / number | When this watchlist last saw the listing, and the days from first to last sighting. |
lastPrice | number | On a gone row: the price when the listing was last seen. null on every other row. |
gonePresumedSold | boolean | On a gone row: true when it was seen on 2+ runs in a row, its last price was at or under the run's median, and its own OLX listing period had not run out. null on every other row. |
url | link | Permanent link to the listing. |
image | link | First photo URL. |
photoCount | number | How many photos the listing has. |
params | object | Every category-specific attribute OLX shows on the listing (phone model, vehicle mileage, apartment size, etc.) as a flat key/value object; see "Why this one". |
scrapedAt | date (ISO) | When this actor fetched the row. |
A search that returns no listings comes back as a single found: false row with a
status/message explaining why, and is never charged.
Country
| Country | country value | Currency observed | Status |
|---|---|---|---|
| Poland | pl (default) | PLN | Live-verified since the original build; re-confirmed for this upgrade |
| Portugal | pt | EUR | Live-verified for this upgrade |
| Romania | ro | RON | Live-verified for this upgrade |
| Bulgaria | bg | EUR (observed; see note below) | Live-verified for this upgrade |
| Ukraine | ua | UAH | Live-verified for this upgrade |
All five share byte-for-byte the same search API, response shape, and ad fields, confirmed by
probing all five directly, not inferred from Poland alone. currency always reflects what OLX
itself reports for that specific listing, never a hardcoded per-country assumption, which is why
Bulgaria shows EUR here rather than BGN: Bulgaria's own euro changeover means olx.bg listings were
already pricing in EUR at the time this was built.
Pricing
- Listing returned: $2 per 1,000 listings
Plus a $0.00005 start fee per run. Each event above is billed independently, only when it actually returns data — misses (found:false) are never charged.
Pay-per-event, per listing returned:
- Listing returned: $2 per 1,000 listings, less on paid Apify plans.
Plus a $0.00005 start fee per run. Misses (found: false) are never charged.
You're charged per listing returned, not per search: a search that returns 40 listings costs forty, a search that returns none costs nothing, and a blank line costs nothing. Gone listings (with "Alert on gone listings" on) are ordinary listing rows at the same price. No separate event.
Getting past OLX's CloudFront wall needs Apify's RESIDENTIAL proxy group, already configured by default, so there's nothing for you to set up, but it is a real, metered cost on this actor's own side, which is reflected in the price. This upgrade measured comfortably inside that price (see the build handoff for the exact figure); the price itself is unchanged from before this upgrade.
1,000 listings through this actor: ~$2 if every search finds results, less on a paid Apify plan. Because you pay per listing, "Most listings to return per search" is your budget control: leave it at 52 and a ten-search run costs at most 520 listings' worth. A quiet monitoring run, or a search filtered down to nothing, costs only the flat per-run start fee.
How to use
- In the Apify Console. Open the actor page and click Start — the
searchesfield is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found. - Via the API. Call it directly with a POST request — no Console needed once you have an API token:
curl "https://api.apify.com/v2/acts/accountable_eel~olx-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"searches":["iphone"]}'
- On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.
Paste one search per line:
iphonerower gorskimieszkanie warszawa
Narrow the results, applied here, to the listings after they arrive:
| Input | What it does |
|---|---|
country | Which OLX country site to search: pl (default), pt, ro, bg, or ua. |
minPrice | Drop listings priced below this, in that country's own currency. |
maxPrice | Drop listings priced above this, in that country's own currency. |
maxListingsPerQuery | Most listings to return per search. Default 52, same as before this upgrade; this actor now pages further if you raise it. |
Monitoring / only new results
Turn on "Only return results that are new, or dropped in price" and a search line (for a given country) becomes a watchlist instead of a one-off dump:
- A listing counts as new the first time its OLX listing ID is returned by this watchlist.
- A listing counts as a price drop when its price falls by at least "Minimum price drop" (5% by default) since it was last seen, measured against the most recently seen price, so a listing that drops twice is compared against its latest price each time, not its original one.
- Already-seen, unchanged listings are dropped before you're billed. A quiet run (nothing new,
nothing cheaper, nothing gone that you asked for) still finishes and returns one free row with
monitorStatus: NO_NEW_ROWS, so a scheduled task shows it actually ran. - The first run has nothing to compare against. By default it returns everything it finds as "new" (so you see your whole current search result once). Turn on "Seed silently" to instead have the first run bank everything quietly with zero rows and zero charge, and start alerting from the second run on: this is what stops a fresh watchlist from firing a hundred "new listing" messages into your Discord channel on day one.
- Every search is always sorted freshest-activity-first (OLX's own
sort_by, which favors a recently bumped/refreshed listing as much as a genuinely new one), so two runs of the same watchlist compare the same ordering. - A watchlist is keyed on country + search text + price filters, so the same keyword monitored on two different OLX country sites never shares one memory, even if you give both the same watchlist name.
Schedule recipe. Save this actor as an Apify Task with deltaMode: true and a
deltaName you choose, add an hourly (or daily) Schedule, and point the task's webhook at
Discord, Slack, Google Sheets, or an n8n/Make webhook URL to get pinged only when something
actually changes.
Price-drop window limitation. A price drop is only ever seen while the listing is still inside
what a run actually fetches: if a listing falls out of your maxListingsPerQuery window or your
price filters between runs, this actor has no way to notice it dropped. Keep searches reasonably
narrow (a specific model, a tight category) rather than one huge catch-all if price-drop coverage
matters to you.
Sold signal and sell-through
Turn on "Alert on gone listings" (alertOnGone) next to the price-drop alert, and a watchlist
also returns the listings it saw before that have since disappeared from OLX, as rows with
changeType: "gone". It is an OLX sold items tracker for your own searches.
What "gone" means, honestly. OLX never tells anyone that a listing sold. gone means
delisted: most often sold, sometimes withdrawn (the seller deleted it, paused it, or edited it
so it no longer matches your search words). This actor adds one more hint,
gonePresumedSold: trueWhat a gone row carries. The title, link, city, region, seller type and seller code banked the
last time the listing was seen, plus lastPrice, firstSeenAt, lastSeenAt and daysListed.
No request is made for a gone listing; fields only a live listing has (photo, description,
params) are null. Each gone listing is reported once. If it comes back (a relisting of the same
ad), it is quietly taken back off the gone count and not re-alerted.
How detection works. A run only reads the top of OLX's feed (up to maxListingsPerQuery), and
a listing that slid below that is still for sale, so "missing" alone proves nothing. This actor
only calls a listing gone when it can show the listing should have been there:
- Complete fetch. When paging reaches OLX's last page with nothing failed (a small, focused
search under your
maxListingsPerQuery), every remembered listing that is missing is gone. - Feed position. Otherwise, the search is sorted freshest-activity-first, and the actor first checks that this run's feed really is in that order (promoted slots left out). A listing seen on the previous run is gone only if its old place, pushed down by every new or refreshed listing above it, still falls inside this run's window with a safety margin. The count of pushes deliberately errs high, so any doubt lands on "still for sale".
- "Missing" means missing from everything the run fetched, in any slot, before your price filters,
so a listing that was just re-priced out of your
minPrice/maxPricerange is not gone.
Limits. No gone check is made on a watchlist's first run, on a run that fetched nothing, when a
page was blocked or failed, when the HTML fallback route was used (its order is relevance, not
time), or when OLX's feed came back out of order and the fetch was not complete. Listings near the
bottom edge of the window, or right at a page boundary, are left alone for that run. So the signal
favours precision over recall: for a busy search, give maxListingsPerQuery comfortable headroom
over the number of new listings between two runs, or narrow the search. Detection starts on the
second run.
Sell-through rate. sellThroughRate is the watchlist's lifetime count of gone listings divided
by every listing it has ever tracked (0 to 1). Gone listings are counted even when "Alert on gone
listings" is off, so the rate is right from day one. Listings unseen for 30 days are forgotten.
medianPrice is the median of everything the run read for the search, in local currency.
Billing. Gone rows are ordinary listing rows, at the same per-listing price. There is no separate event. With "Alert on gone listings" off you are never billed for them.
Example. Track which iPhone 13 listings in Warsaw sell, and at what price, without paying for new-listing rows:
{"searches": ["iphone 13 warszawa"],"country": "pl","maxListingsPerQuery": 120,"deltaMode": true,"deltaName": "iphone13-sell-through","alertOnNew": false,"alertOnPriceDrop": false,"alertOnGone": true}
Schedule it daily. The first run seeds the watchlist (0 listings billed, sellThroughRate 0); from
the second run on you get only gone rows, and every row (and the free search row on a quiet day)
carries the current sell-through rate and median price.
Input
{"searches": ["iphone"]}
One search per line: any keywords, e.g. "iphone 14", "rower gorski", "mieszkanie warszawa". No login required. Pick the OLX country below (Poland by default). Accepted formats: iphone, rower gorski, mieszkanie warszawa.
Output
| query | found | status | searchQuery | listingCount | totalAvailable | truncated | newCount | priceDropCount | goneCount | monitorStatus | sellThroughRate | medianPrice | medianPriceCurrency | listings | listingId | title | price | currency | city | region | country | isBusiness | sellerType | sellerHash | sellerName | isPromoted | createdAt | postedAt | changeType | isNew | previousPrice | priceDropPct | firstSeenAt | lastSeenAt | daysListed | url | listingStatus | scrapedAt |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| iphone | false | REQUEST_FAILED | <gone since last run (delisted, most often sold)> | <monitoring status (quiet / seeded runs)> | <sell-through rate, watchlist lifetime (0-1)> | <median price of the search (local currency)> | <all listings found (full list)> | <price (local currency)> | <seller type (business / private)> | <seller code (hashed, no name)> | <seller name (only with seller info on)> | <promoted / sponsored listing> | <posted (olx timestamp)> | <new / price-drop / gone / seen> | <is this listing new?> | <price drop %> | <days listed (first to last seen)> | <status (marketplace-filters standard: available/reserved/sold)> | 2026-09-11T00:40:55.618Z |
A miss comes back as a row with "found": false and is never charged.
How to filter
All of these are optional and off by default — leave them out and you get exactly what you got before. Every filter runs before billing: a listing that doesn't match is never charged, and the actor keeps paging (up to its page budget) until it has enough matches, not just enough raw listings.
Price range — only listings between 2,000 and 4,000 PLN:
{ "searches": ["iphone 14"], "minPrice": 2000, "maxPrice": 4000 }
Returns iPhone 14 listings priced 2,000–4,000 PLN; anything cheaper or pricier is filtered out before you're billed.
City + keyword filters — Warsaw or Krakow only, and drop broken/parts listings:
{ "searches": ["rower gorski"], "cities": ["warszawa", "krakow"], "excludeKeywords": ["uszkodzony", "na czesci"] }
Returns mountain-bike listings whose city or region contains "warszawa" or "krakow", with any listing whose title contains "uszkodzony" (damaged) or "na czesci" (for parts) dropped.
Sort by price — cheapest first, mieszkanie warszawa search:
{ "searches": ["mieszkanie warszawa"], "sortBy": "price_asc" }
Returns the listings this run fetched sorted lowest price to highest; leave sortBy empty to
keep OLX's own freshest-activity ordering (the existing default).
Use it from Clay, n8n, Make, or an AI agent
This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.
curl "https://api.apify.com/v2/acts/accountable_eel~olx-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"searches":["iphone"]}'
n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~olx-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"searches":["iphone"]} (swap in an expression from an earlier node for a real value).
Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~olx-listing-lookup/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"searches":["{{search}}"]}, mapping the row's search into the searches array.
MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "OLX Scraper API: Poland, Portugal, Romania & More" — the agent will find and run this actor.
Tips
- Run "Try it first" on a handful of searches you already know return results for, to sanity-check the shape before spending on a full list.
- Start monitoring with "Seed silently" on for any watchlist you're setting up on a schedule: it avoids a wall of "new" alerts for your entire current search result on day one.
- Keep a monitored search reasonably narrow (a model, a tight category, a price band); see "Price-drop window limitation" above for why a huge catch-all search misses price drops on listings that fall outside what gets fetched.
- Use
minPrice/maxPriceto cut noise from a broad category search before you pay for rows you don't want, rather than filtering client-side after the fact. paramsvaries by category: inspect a few real rows for your search term before building a downstream schema around specific param keys, since a phone search and an apartment search return different keys.isBusiness/sellerTypelet you split registered-business listings from private-seller ones if you only want one or the other.- A
BLOCKEDstatus means OLX returned a 403/429/503 on both the primary and fallback route; lowering "Max concurrency" or trying again shortly usually clears it.
vs. alternatives
| What it costs | What you get | Trade-off | |
|---|---|---|---|
This actor (olx-listing-lookup) | $0.002 per listing returned (less on paid Apify plans), $0.00005 actor start, nothing for a miss or a quiet monitoring run | One row per OLX listing (title, price, city, business/private seller, and link) across 5 OLX country sites, with new-listing, price-drop and gone (sold signal) monitoring plus a sell-through rate | Paging is generous but bounded (see maxListingsPerQuery); very deep result sets aren't fully mirrored. |
| solidcode/olx-brazil-scraper | Pay-per-result on Apify (58 u30, rated 5.00 on 2 reviews) | Scrapes OLX Brazil (olx.com.br) search results | A very thin review base (2 reviews) and covers Brazil, which this actor doesn't. No monitoring mode. |
| Doing it yourself | Your time + a CloudFront-clearing proxy, tracking OLX's own API shape as it changes, a seen-listing store, and handling category-specific fields by hand | The same data | The proxy wiring, monitoring state, and generic param handling this actor already does are the maintenance burden it absorbs. |
Prices for third-party tools are their published figures as of September 2026 and are not tracked here; check the vendor before relying on the comparison.
Data & privacy
This actor reads public search results that anyone can see without logging in, on OLX's own five
country sites. It doesn't log in, solve CAPTCHAs, or reveal hidden contact details. The seller's
OLX display name is off by default: turn on "Include raw seller info" if you need it. A hashed
seller code (not the name or the raw OLX id) is always included so you can spot the same reseller
across listings either way. OLX's own API also exposes phone/chat contact flags on every listing;
this actor never reads or outputs those, on or off. Contact-info-like strings (emails, phone
numbers) inside a listing's description are redacted to [redacted]. Not affiliated with OLX
Group.
Is this allowed? It collects the same public listing data your browser shows, for the searches you choose, query-bounded rather than mirroring the marketplace. It's built for monitoring a search, not for copying OLX's database wholesale. Check that your use fits OLX's terms and your local law.
FAQ
Why is a row empty, or why does found say false?
Either the input line is blank (status: BAD_FORMAT), OLX/CloudFront blocked the request on both
the primary and fallback route (status: BLOCKED, HTTP 403/429/503), the request failed after
retries (status: REQUEST_FAILED), or the search genuinely has no matching listings right now
(status: NOT_FOUND). Check the message column for the specific reason. None of these are
billed.
Am I charged for a miss, or a quiet monitoring run?
No. You're only charged for listings actually returned. A blocked search, a search with zero
matches, a search where every result falls outside your price filter, or a quiet monitoring run
(monitorStatus: NO_NEW_ROWS) all produce a row (unless you turn on "Hide rows with no result")
and none of them cost anything.
Does this work for OLX country sites other than Poland?
Yes: Poland (pl, the default), Portugal (pt), Romania (ro), Bulgaria (bg), and Ukraine
(ua) are all live-verified. OLX runs the exact same search API and result shape on all five,
confirmed directly rather than assumed. country defaults to pl, so anything built against this
actor before this upgrade keeps working unchanged. Other OLX country sites (including
olx.com.br, the incumbent competitor's focus) are not covered; extending further would need its
own probe first, same as these five got.
Does this actor page through more than one screen of results?
Yes, up to your maxListingsPerQuery. OLX serves 40 listings per page; this actor follows OLX's
own pagination links for as many pages as your limit needs, generously capped. totalAvailable
still reports OLX's total-match count so you know how many more exist beyond that;
truncated is true whenever there are more.
What does "freshest first" actually mean? OLX's own sort favors a listing's most recent activity: a seller "bumping"/refreshing an old listing pushes it back to the top, the same as a brand-new post would. That's still the right signal for "what changed most recently", which is what a monitoring buyer wants, just not literally "youngest listing ID first".
Does this handle CloudFront's block on OLX?
Yes, automatically, on every country site. Requests go through Apify's RESIDENTIAL proxy group by
default (there's nothing for you to configure), with the original HTML route (via UNBLOCKER)
kept as an automatic fallback. If OLX still re-challenges a session on both routes, that shows up
as a BLOCKED status on the affected search rather than a silent failure.
Do I need to configure proxies? No. RESIDENTIAL is the default proxy group for this actor specifically, because a plain request to OLX is blocked by CloudFront on every country site. You don't need to change anything to use it.
Can I schedule this to re-check the same searches on a cadence? Yes: set up an Apify Task with a schedule (daily, weekly, whatever cadence fits) and point it at this actor with a saved input. Turn on Monitoring (see above) to only get pinged when something actually changed, instead of the full result every time.
Does it find sold listings?
Close to it. OLX never publishes that a listing sold, so no tool can confirm a sale. With
Monitoring and "Alert on gone listings" on, this actor reports listings that disappeared
(changeType: "gone"; most often sold, sometimes withdrawn), flags the likely sales with
gonePresumedSold, leaves out listings whose own OLX period simply expired, and keeps a lifetime
sellThroughRate per watchlist. See "Sold signal and sell-through" for how it decides and its
limits.
Can an AI agent call this directly? Yes. It's registered on the Apify MCP server: an agent in Claude, Cursor, or another MCP client can find and run it by name ("OLX Listing Lookup | Apify"), or you can call the REST endpoint shown above from any script or workflow tool.
Related actors
-
OLX New Listing Alert: Watch a Saved Search, No Login: watch a saved OLX search and get only the new listings.
-
Leboncoin Listing Lookup: the same search-by-keyword shape, for France's leboncoin.fr.
-
Kleinanzeigen Listing Lookup: the same classifieds category, for Germany's Kleinanzeigen, takes a listing URL rather than a search term.
-
Otomoto Listing Lookup: a vehicle-specific classifieds lookup for Poland's largest car marketplace.