Otodom Pl $0.8💰 URL Search | Location Filters | Rich Output
Pricing
from $0.80 / 1,000 results
Otodom Pl $0.8💰 URL Search | Location Filters | Rich Output
Pull property listings from Otodom.pl. Apartments, houses, plots, commercial, garages, new developments, rooms; sale and rent. Search builder (city + transaction + property type + filters) and URL-paste modes.
Pricing
from $0.80 / 1,000 results
Rating
5.0
(1)
Developer
Abot API
Maintained by CommunityActor stats
0
Bookmarked
27
Total users
4
Monthly active users
4 days ago
Last modified
Categories
Share
Otodom.pl Property Scraper
Pull property listings from Otodom.pl, the largest property portal in Poland (OLX Group). Apartments, houses, plots, commercial, garages, new developments, rooms; sale and rent. Search builder (city + transaction + property type + filters) and URL-paste modes, with auto forward pagination across SERP pages.
Output is one flat JSON record per listing: id, title, price, area, rooms, full address, GPS coordinates, description, agent contact, building year, ownership, market type, and full feature list.
Why This Scraper?
- Polish portal coverage: top-80 cities + all 16 voivodeships recognized by name (Warszawa, Kraków, Wrocław, Gdańsk, Łódź, Sopot, ...). For unknown cities, drop a URL into URL mode.
- 30 fields per listing: SERP fields (price, area, rooms, city, agency, photo) plus detail-page enrichment (lat/lng, description, full feature list, build year, ownership, market type, agent phone).
- Two input modes: structured search (transaction, property type, price/area/rooms ranges, market type, sort) or paste any otodom.pl URL refined in your browser.
- Forward pagination by default:
maxPageswalks every result page per search unless capped; per-search budget cap so multi-city searches return balanced results. - Resume across runs: paste a previous run/dataset ID into
resumeFromRunIdto continue a full-catalogue walk without re-scraping already-collected listings. - Incremental & recurring monitoring: turn on
incrementalModefor a scheduled (e.g. daily) run of the same search — the actor remembers it itself and flags every rowNEW/UPDATED/UNCHANGED/REAPPEARED/EXPIRED, so you only see (and pay for) what changed. - Low memory footprint: ~80 MB peak memory, ~36 listings/page.
- Resilient session management: automatic 3-tier proxy preflight (chosen proxy → default Apify proxy → no proxy), so free-tier accounts get a graceful fallback instead of a hard fail.
Data You Get
Sample shape, values are illustrative placeholders, not from a live listing.
| Field | Example |
|---|---|
id | "00000001" |
url | "https://www.otodom.pl/pl/oferta/sample-listing-ID00000" |
title | "Sample Apartment Title" |
transaction | "sprzedaz" |
estate | "mieszkanie" |
priceTotal | 750000 |
priceCurrency | "PLN" |
pricePerSquareMeter | 15000 |
rentPrice | null |
rentAdditional | null |
deposit | null |
areaInSquareMeters | 50.0 |
rooms | 2 |
floor | "3" |
buildingFloors | 5 |
buildYear | 2010 |
marketType | "secondary" |
ownership | "full_ownership" |
buildingType | "block" |
buildingMaterial | "concrete" |
heating | "urban" |
windowsType | "plastic" |
city | "Warszawa" |
province | "mazowieckie" |
district | "Mokotów" |
street | "ul. Sample" |
postalCode | "00-000" |
latitude | 52.0000 |
longitude | 21.0000 |
agencyName | "Sample Agency" |
advertiserType | "agency" |
contactName | "Agent Name" |
phone | "+48000000000" |
contactDetails | full upstream ad.contactDetails block (verbatim — includes email, all phones, types) |
agency | full upstream ad.agency block (verbatim — id, address, license, slug, branding) |
owner | full upstream ad.owner block (verbatim — id, profile URL, role) |
referenceId | "REF-0001" |
description | "Full seller description text appears here when fetchDetails=true." |
features | ["meble", "balkon", "winda"] |
isPromoted | false |
isExclusive | false |
isPrivateOwner | false |
imageCount | 12 |
imageUrl | "https://ireland.apollo.olxcdn.com/v1/files/000000000-OTODOM/image" |
dateCreated | "2026-01-01T00:00:00.000Z" |
investmentEstimatedDelivery | null |
scrapedAt | "2026-04-28T00:00:00.000Z" |
changeType | "NEW" (incremental mode only — see below) |
changedFields | [] (incremental mode only) |
firstSeenAt | "2026-04-28T00:00:00.000Z" (incremental mode only) |
lastSeenAt | "2026-04-28T00:00:00.000Z" (incremental mode only) |
How to Use
Search mode, basic Warsaw apartments for sale
{"mode": "search","transaction": "sprzedaz","estate": "mieszkanie","locations": ["Warszawa"],"maxPages": 3,"maxListings": 50,"fetchDetails": true,"proxy": { "useApifyProxy": true }}
Search mode, rentals in three cities, filtered
{"mode": "search","transaction": "wynajem","estate": "mieszkanie","locations": ["Warszawa", "Krakow", "Wroclaw"],"minPrice": 2000,"maxPrice": 4500,"minRooms": 2,"maxRooms": 3,"sortBy": "PRICE_ASC","maxPages": 2,"maxListings": 60,"fetchDetails": true,"proxy": { "useApifyProxy": true }}
Search mode, new developments only (primary market)
{"mode": "search","transaction": "sprzedaz","estate": "mieszkanie","locations": ["Warszawa"],"marketType": "primary","maxPages": 2,"maxListings": 30,"fetchDetails": true,"proxy": { "useApifyProxy": true }}
URL mode, paste any otodom.pl search URL
{"mode": "url","urls": ["https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/mazowieckie/warszawa/warszawa/warszawa/mokotow","https://www.otodom.pl/pl/wyniki/wynajem/dom/malopolskie/krakow/krakow/krakow"],"minPrice": 400000,"maxRooms": 3,"maxPages": 5,"maxListings": 100,"fetchDetails": true,"proxy": { "useApifyProxy": true }}
URL mode is the recommended path when you need filters not exposed above (district, neighborhood, building type), or for cities outside the built-in lookup table. Open Otodom.pl, refine your search in the browser, copy the URL. The price/area/rooms range fields (minPrice/maxPrice/minArea/maxArea/minRooms/maxRooms above) still apply to listings found via pasted URLs, as shown here.
Input Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
mode | string | "search" | "search" (use filters below) or "url" (paste URLs) |
transaction | string | "sprzedaz" | "sprzedaz" (sale) or "wynajem" (rent) |
estate | string | "mieszkanie" | mieszkanie, dom, dzialka, lokal, garaz, inwestycja, pokoj |
locations | string[] | ["Warszawa"] | Polish city names (built-in lookup for top 80 cities + 16 voivodeships) |
marketType | string | "all" | all, primary (rynek pierwotny), secondary (rynek wtórny) |
minPrice, maxPrice | integer | none | PLN range on totalPrice |
minArea, maxArea | integer | none | m² range on areaInSquareMeters |
minRooms, maxRooms | integer | none | Room count range, 1 to 10 |
sortBy | string | "DEFAULT" | DEFAULT, LATEST, PRICE_ASC, PRICE_DESC, AREA_ASC, AREA_DESC |
urls | string[] | example | Full otodom.pl URLs (URL mode only) |
maxPages | integer | none | Pages to walk per search (each page ~36 listings). Leave empty to walk every result page |
maxListings | integer | 20 | Stop after N total. 0 = no cap |
fetchDetails | boolean | true | Fetch detail page for GPS, description, agent phone, features |
resumeFromRunId | string | none | Previous run/dataset ID; already-collected listings (by id) are skipped so the run only saves new ones |
incrementalMode | boolean | false | Recurring monitoring of the SAME search: remembers listings itself across scheduled runs and adds changeType/changedFields/firstSeenAt/lastSeenAt to every row |
stateKey | string | auto | Optional label for the incremental baseline; leave empty to auto-derive one from your search settings |
emitUnchanged | boolean | false | Also output UNCHANGED rows (bills extra dataset-item rows) |
emitExpired | boolean | false | Also output EXPIRED tombstones for delisted listings, only after a complete (uncapped, non-resumed) scan |
proxy | object | datacenter | Apify proxy config |
Incremental mode (recurring monitoring)
Turn on incrementalMode when you run this same search on a schedule (daily, hourly, whatever fits) and only want to know what's new or changed since last time — no need to paste a run ID.
- How it remembers: a hash of your search settings (mode, transaction, estate, locations/URLs, market type, price/area/room filters, sort) becomes a
stateKeyunless you set one manually. Two differently-configured runs never share a baseline by accident; the same configuration always resumes the same one. - What you get: every row gets
changeType(NEW,UPDATED,UNCHANGED,REAPPEARED, orEXPIRED),changedFields(which fields differ from last time),firstSeenAt, andlastSeenAt. - What's suppressed by default:
UNCHANGEDrows are skipped (not pushed, not billed) unless you turn onemitUnchanged. - Delistings: turn on
emitExpiredto get a tombstone row for listings that disappeared. This only fires after a run that scanned the entire tracked search with nomaxPages/maxListingscap and noresumeFromRunIdtruncating it — a partial run can't tell "delisted" from "not reached yet", so it skips EXPIRED detection instead of guessing. - Distinct from
resumeFromRunId: that continues ONE specific interrupted crawl by pasting its run/dataset id.incrementalModeis for ongoing scheduled monitoring and needs no id. The two combine only when bootstrapping: passresumeFromRunIdon the very firstincrementalModerun to seed its baseline from a prior non-incremental pull. - Off by default: existing scheduled runs are unaffected until you opt in.
Send results into your apps (MCP connectors)
Optionally pipe the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape — the Apify dataset is never changed.
What gets written to the connector: a condensed, human-readable summary of each record — not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.
- Authorize a connector once under Apify → Settings → Integrations (Notion, Linear, Airtable, or Apify).
- Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
- For Notion, also set
notionParentPageUrlto the page where items should be created.
The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.
Output Example
Sample shape, values are illustrative placeholders, not from a live listing.
{"id": "00000001","url": "https://www.otodom.pl/pl/oferta/sample-listing-ID00000","title": "Sample Apartment Title","transaction": "sprzedaz","estate": "mieszkanie","priceTotal": 750000,"priceCurrency": "PLN","pricePerSquareMeter": 15000,"rentPrice": null,"rentAdditional": null,"deposit": null,"areaInSquareMeters": 50.0,"rooms": 2,"floor": "3","buildingFloors": 5,"buildYear": 2010,"marketType": "secondary","ownership": "full_ownership","buildingType": "block","buildingMaterial": "concrete","heating": "urban","windowsType": "plastic","city": "Warszawa","province": "mazowieckie","district": "Mokotów","street": "ul. Sample","postalCode": "00-000","latitude": 52.0000,"longitude": 21.0000,"agencyName": "Sample Agency","advertiserType": "agency","contactName": "Agent Name","phone": "+48000000000","referenceId": "REF-0001","description": "Full seller description text appears here when fetchDetails=true.","features": ["meble", "balkon", "winda"],"isPromoted": false,"isExclusive": false,"isPrivateOwner": false,"imageCount": 12,"imageUrl": "https://ireland.apollo.olxcdn.com/v1/files/000000000-OTODOM/image","dateCreated": "2026-01-01T00:00:00.000Z","investmentEstimatedDelivery": null,"scrapedAt": "2026-04-28T00:00:00.000Z"}
Plan Requirement
- Default proxy is Apify residential with country=PL. Gives clean first-try fetches and the fastest end-to-end wall time.
- Bring your own proxy URLs: paste them into the proxy field instead. Make sure they reach Poland for stable routing.
- fetchDetails ON: roughly 1 extra HTTP request per listing. Latitude / longitude, full description, agent phone, build year, and the full feature list only appear on the detail page; turn it OFF only if you do not need any of these.