# Otodom.pl Scraper (`parsebird/otodom-scraper`) Actor

Scrape property listings from Otodom.pl, Poland's largest real estate portal. Extract prices, area, rooms, location, agency info, and images for sale and rental listings.

- **URL**: https://apify.com/parsebird/otodom-scraper.md
- **Developed by:** [ParseBird](https://apify.com/parsebird) (community)
- **Categories:** Real estate, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.90 / 1,000 property scrapeds

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/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### Otodom.pl Scraper

Extract structured property listing data from [Otodom.pl](https://www.otodom.pl/), Poland's largest real estate portal, covering sale and rental listings for flats, houses, plots, commercial premises, halls, and garages nationwide.

<table><tr>
<td style="border-left:4px solid #1C1917;padding:12px 16px;font-weight:600">
Search any Polish voivodeship or city, filter by price, area, rooms, build year, and market type — get clean, structured property data with GPS coordinates, agency contacts, and images ready for analysis, monitoring, or integration.
</td>
</tr></table>

##### Copy to your AI assistant

Copy this block into ChatGPT, Claude, Cursor, or any LLM to start using this actor.

```
parsebird/otodom-scraper on Apify. Call: ApifyClient("TOKEN").actor("parsebird/otodom-scraper").call(run_input={...}), then client.dataset(run["defaultDatasetId"]).list_items().items for results. Key inputs: startUrls (array of strings, direct Otodom.pl search or offer URLs — overrides the filters below), searchType (string: "sprzedaz"/"wynajem", default "sprzedaz"), propertyType (string: "mieszkanie"/"dom"/"dzialka"/"lokal"/"haleimagazyny"/"garaz", default "mieszkanie"), location (string, e.g. "mazowieckie/warszawa", empty = all of Poland), priceMin/priceMax (integer, PLN), areaMin/areaMax (integer, m²), roomsMin/roomsMax (integer, 1-6), buildYear (integer, minimum construction year), market (string: "ALL"/"PRIMARY"/"SECONDARY"), postedDate (string: ""/"1"/"3"/"7"/"14", days), maxItems (integer, default 50, 0 = unlimited), extractDetails (boolean, default true — visits each offer page for full data). Full actor spec: fetch via GET https://api.apify.com/v2/acts/parsebird~otodom-scraper (Bearer TOKEN). Get token: https://console.apify.com/account/integrations
```

### What does Otodom.pl Scraper do?

**Otodom.pl Scraper** extracts structured property listing data from [Otodom.pl](https://www.otodom.pl/), Poland's largest real estate marketplace. It collects prices, area, rooms, floor, GPS coordinates, agency contact details, images, and full descriptions — either from search result pages or directly from a specific offer URL.

Use it as an **Otodom API alternative** to get Polish real estate data in JSON, CSV, or Excel — no coding required. Configure your search, click Start, and download results. Or integrate via the [Apify API](https://docs.apify.com/api/v2) to automate property data collection at scale.

- 🔍 **Search any Polish location** — voivodeship, city, or nationwide
- 🏠 **Six property types** — flats, houses, plots, commercial premises, halls & warehouses, and garages
- 💰 **Sale and rental listings** — sprzedaż (sale) or wynajem (rent)
- 🎯 **Filter by price, area, rooms, build year, market, and posting date** — narrow results to exactly what you need
- 🔗 **Direct URL scraping** — paste any Otodom.pl search or offer URL and skip the filter builder
- 📄 **Optional full-detail extraction** — description, features, images, heating, ownership type, and seller phone from each offer page
- 🔄 **Schedule recurring runs** — monitor new listings and price changes with [Apify scheduling](https://docs.apify.com/platform/schedules)
- 🔗 **API access and integrations** — connect to Google Sheets, Zapier, Make, webhooks, or any workflow via the Apify API

### What data can you extract from Otodom.pl?

**Listing mode** (`extractDetails: false`) — fast, from search result pages only:

| Field | Description |
|-------|-------------|
| `id` | Otodom internal property ID |
| `title` | Property listing title |
| `price` | Listing price in PLN |
| `pricePerM2` | Price per square meter |
| `area` | Area in square meters |
| `rooms` | Number of rooms (1–6, 6 = six or more) |
| `floor` | Floor number |
| `city`, `district`, `street` | Address components |
| `mainImage`, `imageCount` | Main image URL and total image count |
| `sellerType`, `agencyName` | Private owner or agency, with agency name |
| `propertyUrl` | Direct URL to the offer page |

**Detail mode** (`extractDetails: true`, default) — adds all of the following from each offer page:

| Field | Description |
|-------|-------------|
| `serviceFee` | Monthly administrative/service charge (czynsz) in PLN |
| `buildingType`, `buildingMaterial` | Building classification and construction material |
| `buildYear` | Year of construction |
| `heating`, `windowsType` | Heating type and window material |
| `ownershipType`, `condition` | Legal ownership form and property condition |
| `elevator`, `parkingType` | Elevator availability and parking type |
| `latitude`, `longitude` | GPS coordinates |
| `description` | Full listing description |
| `features`, `additionalFeatures` | Amenities and utilities |
| `images` | All image URLs |
| `agencyLicenseNumber`, `agencyUrl` | Agency license and profile URL |
| `sellerPhone` | Seller or agency phone number |

### Input parameters

| Parameter | Type | Required | Default | Description |
|-----------|------|----------|---------|-------------|
| `startUrls` | array | No | `[]` | Direct Otodom.pl URLs (search or offer pages). Overrides the filters below when set |
| `searchType` | string | No | `"sprzedaz"` | Sale (`sprzedaz`) or rent (`wynajem`) |
| `propertyType` | string | No | `"mieszkanie"` | `mieszkanie`, `dom`, `dzialka`, `lokal`, `haleimagazyny`, `garaz` |
| `location` | string | No | `""` | Location path, e.g. `mazowieckie/warszawa`. Empty = all of Poland |
| `priceMin` / `priceMax` | integer | No | — | Price range in PLN |
| `areaMin` / `areaMax` | integer | No | — | Area range in m² |
| `roomsMin` / `roomsMax` | integer | No | — | Room count range (1–6, 6 = six or more) |
| `buildYear` | integer | No | — | Minimum construction year |
| `market` | string | No | `"ALL"` | `ALL`, `PRIMARY`, `SECONDARY` |
| `postedDate` | string | No | `""` | Posted within: `""` (any), `1`, `3`, `7`, `14` days |
| `maxItems` | integer | No | `50` | Maximum listings to scrape. `0` = unlimited |
| `extractDetails` | boolean | No | `true` | Visit each offer page for full details |
| `maxConcurrency` | integer | No | `5` | Parallel requests when extracting details |
| `maxRequestRetries` | integer | No | `3` | Retries per failed request |
| `maxRequestsPerMinute` | integer | No | `60` | Rate limit across all requests |
| `proxyConfiguration` | object | No | Residential | Proxy settings (Apify Proxy, residential recommended) |

### Output example

```json
{
    "id": "68133433",
    "title": "KILOMETR OD ZŁOTYCH TARASÓW I PKiN ☆ MOŻLIWOŚĆ 2 POKOI ☆ BEZPOŚREDNIO",
    "price": 485000,
    "priceCurrency": "PLN",
    "priceFormatted": "485 000 PLN",
    "pricePerM2": 17636.36,
    "pricePerM2Formatted": "17 636.36 PLN/m²",
    "area": 27.5,
    "rooms": 2,
    "floor": "8",
    "totalFloors": 11,
    "market": "SECONDARY",
    "location": "Warszawa, Wola, al. Aleje Jerozolimskie",
    "city": "Warszawa",
    "province": "mazowieckie",
    "district": "Wola",
    "latitude": 52.225937,
    "longitude": 20.991928,
    "mainImage": "https://ireland.apollo.olxcdn.com/v1/files/.../image;s=2048x1536;q=80",
    "imageCount": 20,
    "sellerType": "private",
    "dateCreated": "2026-06-22T21:25:25Z",
    "propertyUrl": "https://www.otodom.pl/pl/oferta/kilometr-od-zlotych-tarasow-i-pkin-mozliwosc-2-pokoi-bezposrednio-ID4BSCl",
    "serviceFee": 443,
    "buildingType": "block",
    "buildingMaterial": "reinforced_concrete",
    "buildYear": 1970,
    "heating": "urban",
    "ownershipType": "limited_ownership",
    "elevator": true,
    "parkingType": "garage",
    "features": ["garage", "lift", "separate_kitchen", "air_conditioning", "monitoring"],
    "sellerPhone": "+48732922700"
}
```

Download results in **JSON, HTML, CSV, or Excel**, or connect via the [Input and output tabs](https://docs.apify.com/platform/actors/running/input-and-output) on your run.

### Use cases

- 📈 **Market analysis** — track pricing trends, average PLN/m² costs, and inventory across Polish cities
- 💼 **Investment research** — compare yields, identify undervalued districts, monitor price-per-m² over time
- 📇 **Lead generation** — extract agency contact details for outreach and partnership opportunities
- 🏠 **Relocation and home search** — build filtered shortlists by price, size, rooms, and location
- 🔄 **Price monitoring** — schedule recurring runs to track new listings and price changes
- 🔗 **PropTech integration** — feed structured data into CRMs, valuation models, or dashboards

### How to scrape Otodom.pl

1. Go to the [Otodom.pl Scraper](https://apify.com/parsebird/otodom-scraper) page on Apify Store
2. Click **Try for free** to open the Actor console
3. Choose **Sale** or **Rent**, then a **property type** — flat, house, plot, commercial premises, hall/warehouse, or garage
4. Enter a **location** (e.g. `mazowieckie/warszawa`, `malopolskie/krakow`) or leave empty to search all of Poland
5. Set optional **filters** — price, area, rooms, minimum build year, market, or posted-within date
6. Alternatively, paste direct Otodom.pl **search or offer URLs** into Start URLs to skip the filter builder
7. Toggle **Extract Full Details** on for complete data, or off for a faster listing-only scrape
8. Click **Start** and download your data in **JSON, CSV, Excel**, or via the **Apify API**

#### Python API example

```python
from apify_client import ApifyClient

client = ApifyClient("YOUR_API_TOKEN")

run = client.actor("parsebird/otodom-scraper").call(run_input={
    "searchType": "sprzedaz",
    "propertyType": "mieszkanie",
    "location": "mazowieckie/warszawa",
    "priceMax": 1000000,
    "roomsMin": 2,
    "maxItems": 100,
    "extractDetails": True,
})

for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f"{item['price']} {item['priceCurrency']} — {item['area']}m² — {item.get('district', 'N/A')}")
```

#### JavaScript API example

```javascript
import { ApifyClient } from "apify-client";

const client = new ApifyClient({ token: "YOUR_API_TOKEN" });

const run = await client.actor("parsebird/otodom-scraper").call({
    searchType: "wynajem",
    propertyType: "mieszkanie",
    location: "malopolskie/krakow",
    priceMax: 4000,
    maxItems: 50,
    extractDetails: true,
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.log(`${item.price} ${item.priceCurrency} — ${item.area}m² — ${item.district ?? "N/A"}`);
});
```

### How it works

1. Builds an Otodom.pl search URL from your input filters (or uses your direct start URLs)
2. Fetches each search result page and parses the property data embedded in the page's own Next.js data payload
3. Paginates through results until `maxItems` is reached or the search is exhausted
4. When **Extract Full Details** is on, visits each offer page to pull description, features, images, and seller contact info
5. Deduplicates by listing ID and pushes each property to the Apify dataset

### How much does it cost to scrape Otodom.pl?

| Event | Price per event | Price per 1,000 |
|-------|----------------|-----------------|
| `property-scraped` | $0.0019 | **$1.90** |

One event is charged each time a property listing is successfully scraped and saved to the dataset — you only pay for listings actually returned. At the default `maxItems: 50` with details on, a run costs about **$0.095**.

**Cost examples:**

| Listings | Cost |
|----------|------|
| 50 (default run) | $0.10 |
| 500 | $0.95 |
| 5,000 | $9.50 |
| 50,000 | $95.00 |

Apify offers a **free trial** with platform credits included on signup — enough to scrape thousands of listings at no cost. Higher-spending Apify accounts (Bronze/Silver/Gold tiers) receive automatically discounted per-event pricing.

### Is it legal to scrape Otodom.pl?

This Actor extracts publicly available data from Otodom.pl. Scraping public data is generally considered legal based on recent court rulings, including the US Ninth Circuit's decision in *hiQ Labs v. LinkedIn*. However, you are responsible for ensuring your use of scraped data complies with applicable laws, Otodom.pl's Terms of Service, and data protection regulations including GDPR. Do not use extracted personal data (such as seller phone numbers) for unsolicited contact or purposes incompatible with its original context. For more information, read Apify's blog post on [web scraping legality](https://blog.apify.com/is-web-scraping-legal/).

### Other ParseBird real estate scrapers

| Actor | Target site | Region |
|-------|------------|--------|
| [Fotocasa Scraper](https://apify.com/parsebird/fotocasa-scraper) | Fotocasa.es | 🇪🇸 Spain |
| [Funda.nl Scraper](https://apify.com/parsebird/funda-scraper) | Funda.nl | 🇳🇱 Netherlands |
| [Funda in Business Scraper](https://apify.com/parsebird/fundainbusiness-scraper) | FundaInBusiness.nl | 🇳🇱 Netherlands (commercial) |
| [Propertyfinder Scraper](https://apify.com/parsebird/propertyfinder-scraper) | PropertyFinder.ae | 🌍 MENA |
| [MagicBricks Scraper](https://apify.com/parsebird/magicbricks-scraper) | MagicBricks.com | 🇮🇳 India |
| [NoBroker.in Scraper](https://apify.com/parsebird/nobroker-scraper) | NoBroker.in | 🇮🇳 India |

Browse all ParseBird actors on the [Apify Store](https://apify.com/parsebird).

### FAQ

**What locations can I search on Otodom.pl?**
Any voivodeship or city covered by Otodom.pl — use the `location` field in the format `voivodeship/city` (e.g. `mazowieckie/warszawa`, `malopolskie/krakow`), just `voivodeship` for a whole region, or leave it empty to search all of Poland.

**Can I scrape rental listings?**
Yes. Set `searchType` to `wynajem`. Rental listings return the monthly rent in `price`/`rentPrice`, and the building's administrative fee separately in `serviceFee`.

**What's the difference between `serviceFee` and `rentPrice`?**
`serviceFee` is the monthly administrative/building charge (czynsz) and appears on both sale and rental listings. `rentPrice` is only set on rental listings and mirrors the monthly rent already shown in `price`.

**Does this scraper need residential proxies?**
Yes. Otodom.pl blocks Apify's shared datacenter proxy IPs at the CDN/WAF level. The Actor defaults `proxyConfiguration` to Apify's `RESIDENTIAL` proxy group — leave this on for reliable runs.

**Can I scrape a specific listing directly?**
Yes. Paste one or more Otodom.pl offer URLs (`otodom.pl/pl/oferta/...`) into **Start URLs**. You can also mix in search result URLs in the same list.

**How many listings can I scrape per run?**
There's no hard limit. Set `maxItems` to `0` for unlimited, though very large runs take longer and cost more in compute and proxy bandwidth.

**Can I schedule recurring scrapes?**
Yes. Use [Apify scheduling](https://docs.apify.com/platform/schedules) to run daily, weekly, or at any custom interval, and combine it with webhooks or integrations to automate your data pipeline.

**Can I access the data via API?**
Yes. Every run produces a dataset accessible via the [Apify API](https://docs.apify.com/api/v2). Integrate with Python, JavaScript, Google Sheets, Zapier, Make, or any HTTP-capable tool.

Found an issue or have a feature request? Use the **Issues** tab on the Actor page — feedback helps improve reliability.

# Actor input Schema

## `startUrls` (type: `array`):

Direct Otodom.pl URLs to scrape — search result pages (otodom.pl/pl/wyniki/...) or single offer pages (otodom.pl/pl/oferta/...). When set, the search filters below are ignored.

## `searchType` (type: `string`):

Sale (sprzedaż) or rental (wynajem) listings.

## `propertyType` (type: `string`):

Category of property to search for.

## `location` (type: `string`):

Location path as used in Otodom URLs: voivodeship, or voivodeship/city (e.g. mazowieckie, mazowieckie/warszawa, malopolskie/krakow). Leave empty to search all of Poland.

## `priceMin` (type: `integer`):

Minimum price in PLN. Leave empty for no minimum.

## `priceMax` (type: `integer`):

Maximum price in PLN. Leave empty for no maximum.

## `areaMin` (type: `integer`):

Minimum property area in square meters. Leave empty for no minimum.

## `areaMax` (type: `integer`):

Maximum property area in square meters. Leave empty for no maximum.

## `roomsMin` (type: `integer`):

Minimum number of rooms (1-6, where 6 means '6 or more').

## `roomsMax` (type: `integer`):

Maximum number of rooms (1-6, where 6 means '6 or more').

## `buildYear` (type: `integer`):

Only include properties built in this year or later.

## `market` (type: `string`):

Filter by primary (new/developer) or secondary market.

## `postedDate` (type: `string`):

Only include listings posted within the last N days.

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

Maximum number of property listings to scrape. Set to 0 for unlimited.

## `extractDetails` (type: `boolean`):

Visit each property's offer page to extract full details (description, features, images, build year, seller phone). Slower and uses more compute; turn off for a fast listing-only scrape.

## `maxConcurrency` (type: `integer`):

Maximum number of parallel requests when extracting offer page details.

## `maxRequestRetries` (type: `integer`):

How many times to retry a failed request before giving up on it.

## `maxRequestsPerMinute` (type: `integer`):

Rate limit applied across all requests to Otodom.pl.

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

Proxy settings for the scraper. Otodom.pl blocks Apify's shared datacenter proxy IPs, so residential proxies are used by default.

## Actor input object example

```json
{
  "startUrls": [],
  "searchType": "sprzedaz",
  "propertyType": "mieszkanie",
  "location": "mazowieckie/warszawa",
  "market": "ALL",
  "postedDate": "",
  "maxItems": 50,
  "extractDetails": true,
  "maxConcurrency": 5,
  "maxRequestRetries": 3,
  "maxRequestsPerMinute": 60,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# 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 = {
    "startUrls": [],
    "searchType": "sprzedaz",
    "propertyType": "mieszkanie",
    "location": "mazowieckie/warszawa",
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("parsebird/otodom-scraper").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 = {
    "startUrls": [],
    "searchType": "sprzedaz",
    "propertyType": "mieszkanie",
    "location": "mazowieckie/warszawa",
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("parsebird/otodom-scraper").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 '{
  "startUrls": [],
  "searchType": "sprzedaz",
  "propertyType": "mieszkanie",
  "location": "mazowieckie/warszawa",
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call parsebird/otodom-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/fFD0okxgj782G0isH/builds/Otipy9nZGCyYOS364/openapi.json
