Otodom.pl Scraper at a glance
Otodom.pl Scraper is a ready-to-run Apify actor from abotapi for collecting real estate data. Its documented output includes id, url, title, transaction and type, which you can export as JSON, CSV or Excel or read through the Apify API. It costs $1.50 per 1,000 results on the Apify Free plan and from $0.80 on paid plans, with smaller per-run or optional feature charges listed on Apify.
- Runs on
- Apify cloud: console, API, schedules and integrations
- Data type
- Real Estate, Automation, Developer Tools
- Region
- Europe
- Pricing
- $1.50 per 1,000 results (Free plan), from $0.80 on paid plans
- Output
- Documented below · JSON, CSV, Excel
- Inputs
- 28 options
- Run success
- 96.7% of completed public runs in the last 30 days
Scrape Otodom.pl properties for sale and rent, including apartments, houses, plots, commercial spaces, garages, rooms and new developments. Build searches by city, transaction, property type and filters, or paste Otodom URLs directly.
What Otodom.pl Scraper can do
- Two ways to search. Build a query from transaction, property type, cities and filters, or paste any Otodom search URL refined in your browser. No need to construct search URLs by hand.
- 80 cities plus all 16 voivodeships recognized by name. Warszawa, Kraków, Wrocław, Gdańsk, Łódź, Poznań, Szczecin, Sopot and more, built in. For a city or district that is not recognized, drop a URL into URL mode instead.
- 30+ fields per listing. SERP fields (price, area, rooms, agency, photo) plus optional detail-page enrichment (city and province, GPS coordinates, full description, agent phone, building year, ownership, full feature list).
- Detail depth on demand. Switch fetchDetails on or off per run: SERP-only fields are always included, detail-page fields are added when you need them.
- Forward pagination with cost caps. Walks every result page per search by default, with per-run and per-search limits so a multi-city search returns balanced results instead of exhausting the budget on the first city.
- Resume across runs. Continue an interrupted full-catalogue walk from a previous run or dataset ID without re-scraping listings you already collected.
Choose what to collect
These inputs let you configure Otodom.pl Scraper - Property Listings, Prices & Rentals. Open the actor on Apify to enter your values and review the current options.
| Input | What it controls |
|---|---|
modestring · required | Search mode = pick transaction + property type + cities + filters below. URL mode = paste any Otodom search URL refined in a browser (recommended for filters not exposed below, like district/neighborhood). |
transactionstring | Sale (sprzedaż) or rent (wynajem). Used to build the canonical Otodom URL. |
estatestring | Otodom property type segment. Apartment (mieszkanie), house (dom), plot (działka), commercial (lokal), garage (garaż), investment / new development (inwestycja), room (pokój), halls and warehouses (hale i magazyny). |
locationsarray | Polish city names. Recognized: Warszawa, Kraków, Wrocław, Gdańsk, Łódź, Poznań, Szczecin, Bydgoszcz, Lublin, Białystok, Katowice, Gdynia, Sopot, Gliwice, Zabrze, Rzeszów, Olsztyn, Toruń, Kielce, Radom, Częstochowa, Bytom, Tychy, Opole, Sosnowiec, plus all 16 voivodeship names. For unknown / smaller cities, leave empty (Poland-wide search) or use URL mode. The cartesian product of property type × city is searched. |
marketTypestring | Filter by primary (rynek pierwotny, new from developer) or secondary (rynek wtórny, resale). Default = both. |
minPriceinteger | Lower bound on totalPrice (PLN). Optional. |
maxPriceinteger | Upper bound on totalPrice (PLN). Optional. |
Show 21 more inputs
| Input | What it controls |
|---|---|
minAreainteger | Lower bound on areaInSquareMeters. Optional. |
maxAreainteger | Upper bound on areaInSquareMeters. Optional. |
minRoomsinteger | Minimum number of rooms (1-10). |
maxRoomsinteger | Maximum number of rooms (1-10). |
buildYearinteger | Only listings built in this year or later (1900-2030). Search mode only; listings without a build year on Otodom are excluded by the site. |
postedDatestring | Only listings posted within the last 1, 3, 7 or 14 days. Empty = any time. Search mode only. |
districtsarray | City districts to search, e.g. Mokotów, Wola (one search per district; Search mode only). Applies to city locations such as Warszawa or Kraków, ignored for voivodeships. Use the district name as written on Otodom. |
sortBystring | Default = newest. Otodom inserts promoted listings ahead of organic order regardless of sort, so sort is best-effort. |
urlsarray | One or more full otodom.pl URLs: a search (city, district, filters, sort?page=N), a single listing page (/pl/oferta/...), or an agency profile (/pl/firmy/biura-nieruchomosci/-ID...). Tip: open otodom.pl in your browser, copy the URL from the address bar. Leaving this field untouched scrapes the eight sample URLs listed here. Unsupported pages (new-development detail pages, agency directory lists, m.otodom.pl, /en/ and old-style addresses) are skipped with an error in the log. Search-mode-only fields above (transaction, property type, cities, market type, sort order) are ignored; the price/area/rooms filters above still apply to listings found via search and agency URLs. Pagination starts at the page in the URL and walks forward. |
maxPagesinteger | How many SERP pages to walk per city × property type combination (or per pasted URL). Each page returns ~36 listings. Leave empty to walk every result page. |
maxListingsinteger | Stop after this many listings across all searches. 0 = no cap. Values above 1,000,000 are rejected. |
fetchDetailsboolean | When ON, also fetch each listing's detail page for GPS coordinates, full description, agent phone, building year, ownership type, full feature list. SERP cards already carry id, title, price, area, rooms, agency and the cover image. City, province, latitude/longitude, description and contact details come from the detail page, so they are empty when this is off. Default ON. Each delivered listing whose detail page is read is charged as one detail-page event on top of the per-result charge; listings whose detail page is refused, and listings incremental mode suppresses as unchanged, are not charged. |
resumeFromRunIdstring | Paste a previous run ID or dataset ID to continue a full-catalogue walk across separate runs. Listings already collected there (matched by id) are skipped, so this run only saves the new ones. Leave empty for a normal fresh run. For ongoing scheduled monitoring of this search, use incrementalMode below instead. |
incrementalModeboolean | Turn on when you run this same search on a schedule (e.g. daily) and only want to know what's new or changed since last time. The actor remembers this search's listings itself, no run ID needed. Every field of a listing is compared (price, area, rooms, title, description, address, contact and agency data, features, image count and the rest) except scrapedAt, images, imageUrl, isPromoted and any field you list in the ignore setting at the end of this section; ignored fields stay in the output but never trigger UPDATED. dateModified is the site's own modified-at stamp (it moves when an ad is edited or refreshed); list it to ignore refresh-only changes. Adds changeType (NEW/UPDATED/UNCHANGED/REAPPEARED/EXPIRED), changedFields, firstSeenAt, and lastSeenAt to every row. Off by default so existing scheduled runs are unaffected. See stateKey, emitUnchanged, and emitExpired below. |
stateKeystring | Optional label for the incrementalMode baseline. Leave empty to auto-derive one from your search settings (mode/transaction/estate/locations/urls/marketType/price/area/rooms ranges/sort), a different filter setup automatically gets its own baseline, never sharing one by accident. Set this only if you want multiple differently-configured runs to intentionally share one baseline. |
emitUnchangedboolean | When incrementalMode is on, also output listings that are UNCHANGED since the last run (changeType=UNCHANGED, changedFields=[]). Off by default: unchanged listings are silently skipped, so you only see and pay for what's new or different. Turning this on bills extra dataset-item rows for listings that haven't changed. |
emitExpiredboolean | When incrementalMode is on, also output a row for previously-tracked listings that are no longer found (changeType=EXPIRED), so you can detect delistings. Only emitted after a run that scans the full tracked search with no page/item cap and no resumeFromRunId, a partial run never marks a still-live listing as expired. Off by default. Turning this on bills extra dataset-item rows. |
ignoreFieldsForChangesarray | Incremental mode only. Field names to leave out when deciding whether a listing changed (they still appear in the output). Use a dotted path for a nested field, for example agency.name. Fields excluded by default: scrapedAt, images, imageUrl, isPromoted. Example: dateModified, agency.name. Leave empty to compare every other field. |
mcpConnectorsarray | Optionally send the scraped results into the apps you already use, via Model Context Protocol (MCP) connectors. Authorize a connector once under Apify → Settings → Integrations, then select it here. The connector receives a condensed, human-readable summary per item (title + key fields), not the full JSON, the complete record stays in the dataset. Leave empty to skip. Supported: Notion (https://mcp.notion.com/mcp), Linear (https://mcp.linear.app/sse), Airtable (https://mcp.airtable.com/mcp), Apify (https://mcp.apify.com). |
notionParentPageUrlstring | URL (or id) of the Notion page under which item pages are created. Required to enable the Notion export; ignored by other connectors. |
maxNotifyListingsinteger | Cap on items written to each connector per run. Does not affect the dataset. |
Fields in the output
The documented dataset includes the fields below. Availability can depend on the source page and selected mode.
idIDurlURL (link)titleTitletransactionTransactionestateTypepriceTotalPricepriceCurrencyCurrencypricePerSquareMeterPrice / m²rentPriceRentareaInSquareMetersArea (m²)roomsRoomsfloorFloorShow 27 more fields
buildYearBuild yearmarketTypeMarketownershipOwnershipbuildingTypeBuildingcityCityprovinceProvincedistrictDistrictstreetStreetlatitudeLatlongitudeLngagencyNameAgencyadvertiserTypeListerphonePhoneisPromotedPromotedisExclusiveExclusiveimageCountImagesimageUrlPhoto (image)scrapedAtScrapedchangeTypeChange (text)detailFetcheddetailFetcheddescriptionDescriptionconditionConditionextrasExtrasdateModifiedModifiedchangedFieldsChanged fieldsfirstSeenAtFirst seenlastSeenAtLast seenExample output
An example from this actor’s documentation. Values are illustrative; this is not a fresh live result.
{
"id": "00000001",
"url": "https://www.otodom.pl/pl/oferta/sample-listing-ID00000",
"title": "Przytulne mieszkanie na Mokotowie, 2 pokoje",
"transaction": "sprzedaz",
"estate": "mieszkanie",
"priceTotal": 750000,
"priceCurrency": "PLN",
"pricePerSquareMeter": 15000,
"rentPrice": null,
"rentAdditional": null,
"deposit": null,
"areaInSquareMeters": 50,
"rooms": 2,
"floor": "3",
"buildingFloors": 5,
"buildYear": 2010,
"marketType": "secondary",
"ownership": "full_ownership",
"buildingType": "block",
"buildingMaterial": "concrete",
"heating": "urban",
"condition": "ready_to_use",
"extras": [
"balcony",
"garden"
],
"dateModified": "2026-10-14T21:48:21Z",
"windowsType": "plastic",
"city": "Warszawa",
"province": "mazowieckie",
"district": "Mokotów",
"street": "ul. Sample",
"postalCode": "00-000",
"latitude": 52,
"longitude": 21,
"agencyName": "Sample Agency",
"advertiserType": "agency",
"contactName": "Agent Name",
"phone": "+48000000000",
"referenceId": "REF-0001",
"description": "Sprzedam przytulne mieszkanie w spokojnej okolicy, blisko metra i parku.",
"features": [
"meble",
"balkon",
"winda"
],
"isPromoted": false,
"isExclusive": false,
"isPrivateOwner": false,
"imageCount": 12,
"imageUrl": "https://img.otodom.pl/api/v1/offers/sample-id/image",
"dateCreated": "2026-01-01T00:00:00.000Z",
"investmentEstimatedDelivery": null,
"scrapedAt": "2026-04-28T00:00:00.000Z"
}Ways to use this data
- Real estate market research: track asking prices, price per square meter and inventory across cities, districts and property types over time.
- Property investment analysis: pull GPS-tagged listings with build year, ownership type and agent contact to compare deals across multiple cities.
- Lead generation for agents and brokers: filter by market type and advertiser type to find private-seller and secondary-market listings worth a call.
- Rental market tracking: compare rent, deposit and additional fees across cities, room counts and property types.
- Proptech and data products: feed structured Polish listings into a search app, price index or valuation model.
Before you run
Start with a small input and check the resulting records against your expected fields. Source content and actor options can change; the current Apify listing is the reference for availability and pricing.
Questions about this actor
What data does Otodom.pl Scraper return?
The documented output for Otodom.pl Scraper includes id, url, title, transaction, type, price, currency and price / m². Availability of each field depends on the source page and the selected mode.
How much does Otodom.pl Scraper cost?
It costs $1.50 per 1,000 results on the Apify Free plan and from $0.80 on paid plans, with smaller per-run or optional feature charges listed on Apify. The Apify listing shows the current rate for every plan.
Can I get only new or changed listings on a schedule?
Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new, updated, reappeared, and (if you also turn on Emit expired listings) delisted records for that same search; unchanged ones are not returned or billed unless you turn that on too.
Why did my city search return listings from all over Poland?
locations recognizes 80 built-in cities and the 16 voivodeships by name. An unrecognized or misspelled name is skipped with an error in the log (if every entry is unrecognized the run fails with an input error). Check the spelling, or switch to URL mode and paste a search URL for that city or district.
Can I use it with AI agents or MCP?
Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.
