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

\[💰 $0.95 / 1K] Extract real-estate listings from Otodom.pl. Get prices, area, rooms, addresses, photos, agent contacts, and full descriptions for apartments, houses, plots, and commercial properties — both for sale and for rent — across Poland.

- **URL**: https://apify.com/solidcode/otodom-pl-scraper.md
- **Developed by:** [SolidCode](https://apify.com/solidcode) (community)
- **Categories:** Real estate, Automation, Developer tools
- **Stats:** 4 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.95 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#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

Pull real-estate listings from Otodom.pl — Poland's largest property portal — at scale, with prices in PLN, GPS coordinates, full image galleries, and listing-agent phone numbers on every row. Cover all 32 major Polish cities plus an all-of-Poland sweep, across apartments, houses, studios, rooms, plots, garages, commercial premises, halls/warehouses, and new-build investments — for sale or for rent. Built for lead-generation agencies prospecting Polish real-estate agents, expat and international buyers researching Warszawa or Kraków apartment prices, and market analysts tracking price-per-m² trends without wrestling with Otodom's filter URLs or stitching paginated results by hand.

### Why This Scraper?

- **Lead-generation ready** — every listing returns the seller's phone number in plaintext E.164 format (e.g. `+48573582897`), plus agency name and Otodom agency URL. Typical population rate is 90%+ across active sale and rent listings.
- **9 property types in one actor** — Apartment (Mieszkanie), Studio (Kawalerka), House (Dom), Room (Pokój), Plot/Land (Działka), Commercial premises (Lokal użytkowy), Hall/Warehouse (Hala/magazyn), Garage (Garaż), and Investment (Inwestycja — new-build developments). Flip a single dropdown to switch.
- **32 Polish cities covered out of the box** — from Warszawa, Kraków, Wrocław, Gdańsk, Poznań, and Łódź down to Płock, Elbląg, and Bytom, plus an all-of-Poland (`cała Polska`) sweep when you want everything in one run.
- **GPS coordinates + voivodeship → district hierarchy on every detail page** — latitude, longitude, postal code, voivodeship, county, city, district, and street arrive map-ready, no separate geocoding step.
- **Up to ~30 photos per listing pulled at full resolution** — straight from the source CDN at 1280×1024, not thumbnail crops.
- **Multi-room selection** — pick exactly the room counts you want (e.g. 2 + 3 + 4) instead of an awkward "minimum 2 rooms" range filter. Six options including a "6 or more" bucket.
- **Primary vs secondary market filter** — split new-build developer listings from resale stock with one dropdown, then sort by lowest price-per-m² to surface undervalued primary launches.
- **PLN-native pricing throughout** — `price` and `pricePerSquareMeter` are computed and exposed as separate fields. No currency conversion guesswork; price-per-m² is ready to sort, filter, and chart.
- **Build-year filtering with min/max** — bracket your search to e.g. 2010–2024 for newer construction, or 1900–1939 for pre-war Warszawa townhouses. Pairs naturally with apartments and houses.

### Use Cases

**Lead Generation for Polish Real Estate**

- Build call lists of listing agents and developers — name, mobile phone, agency, agency profile URL
- Target by city, property type, and price band to focus outreach
- Identify new-build developers (primary market) actively selling inventory
- Pull every active rental agent in Warszawa, Kraków, or Wrocław for a single SMS or call campaign

**Market Research & Price Analysis**

- Track median and percentile price-per-m² across the 32 covered cities
- Compare apartment pricing in Warszawa vs Kraków vs Wrocław over time
- Map inventory levels by voivodeship, county, and district
- Separate primary (new-build) from secondary (resale) market pricing to measure premium

**Investment & Underwriting**

- Sort by lowest price-per-m² to surface undervalued listings in a target district
- Filter by build year (2010+) to focus on newer construction with lower capex
- Pull rental yields by combining for-sale and for-rent runs on the same district
- Identify investment developments (Inwestycja) for buy-to-let or off-plan strategies

**Relocation & Expat Search**

- Search Warszawa, Kraków, Gdańsk, or Wrocław by district and price band
- Pre-filter by build year, room count, and area before reaching out
- Compare rentals across multiple cities with one run for relocation decisions
- Collect photos and full descriptions to shortlist before scheduling viewings

**Listings Aggregation & Competitor Tracking**

- Feed real-time Otodom inventory into a property portal or comparison site
- Monitor competitors' developer projects (primary listings) launching new buildings
- Track price changes by re-running and diffing against your last dataset
- Power Polish-market dashboards with structured, deduplicated rows

### Getting Started

#### Simple — All Apartments for Sale in Warszawa

Just a city and a deal type:

```json
{
    "location": "Warszawa",
    "dealType": "sale",
    "propertyType": "apartment",
    "maxResults": 100
}
```

#### Filtered — Two- and Three-Room Kraków Apartments, 300–800k PLN

```json
{
    "location": "Kraków",
    "dealType": "sale",
    "propertyType": "apartment",
    "rooms": ["2", "3"],
    "priceMin": 300000,
    "priceMax": 800000,
    "maxResults": 500
}
```

#### Advanced — New-Build Wrocław Apartments Built Since 2018, Cheapest €/m² First

```json
{
    "location": "Wrocław",
    "dealType": "sale",
    "propertyType": "apartment",
    "marketType": "primary",
    "buildYearMin": 2018,
    "buildYearMax": 2026,
    "areaMin": 40,
    "areaMax": 90,
    "sortBy": "price_lowest",
    "radius": "10",
    "maxResults": 1000
}
```

#### Power-User — Paste an Otodom Search URL Directly

Skip the guided fields and use a pre-filtered Otodom search you already have open in your browser:

```json
{
    "startUrls": [
        "https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/mazowieckie/warszawa/warszawa/warszawa?priceMin=500000&priceMax=1200000&roomsNumber=%5B%22TWO%22%2C%22THREE%22%5D"
    ],
    "maxResults": 300
}
```

### Input Reference

#### Search Targeting

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `dealType` | select | `For Sale (Sprzedaż)` | Are you looking for properties to buy or to rent? Options: For Sale (Sprzedaż), For Rent (Wynajem). |
| `propertyType` | select | `Apartment (Mieszkanie)` | Property category. Options: Apartment (Mieszkanie), Studio (Kawalerka), House (Dom), Room (Pokój) — rent only, Plot / Land (Działka), Commercial premises (Lokal użytkowy), Hall / Warehouse (Hala / magazyn), Garage (Garaż), Investment / New development (Inwestycja). |
| `location` | string | `Warszawa` | Polish city, voivodeship, or "cała Polska" for the entire country. Polish characters accepted and recommended. |
| `radius` | select | `Exact area only (0 km)` | Expand the search beyond the selected location. Options: 0, +5, +10, +15, +25, +50, +75 km. |
| `startUrls` | URL\[] | `[]` | Power-user input. Paste Otodom search-result URLs or individual listing URLs. When provided, overrides the guided fields. |

#### Filters

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `priceMin` | integer | empty | Minimum price in Polish złoty (PLN). Leave empty for no minimum. |
| `priceMax` | integer | empty | Maximum price in Polish złoty (PLN). Leave empty for no maximum. |
| `areaMin` | integer | empty | Minimum floor area in square metres. |
| `areaMax` | integer | empty | Maximum floor area in square metres. |
| `rooms` | string\[] | `[]` | Multi-select room count. Options: 1 room, 2 rooms, 3 rooms, 4 rooms, 5 rooms, 6 or more. Ignored for plots, garages, and commercial. |
| `buildYearMin` | integer | empty | Minimum build year (1800–2100). Most useful for apartments and houses. |
| `buildYearMax` | integer | empty | Maximum build year (1800–2100). |
| `marketType` | select | `Any market` | Primary (new build) vs Secondary (resale) vs Any market. Most useful on sale listings. |

#### Sorting & Limits

| Parameter | Type | Default | Description |
|-----------|------|---------|-------------|
| `sortBy` | select | `Default (recommended)` | Result order. Options: Default, Newest first, Oldest first, Lowest price first, Highest price first, Smallest area first, Largest area first. |
| `maxResults` | integer | `100` | Maximum listings to collect across all searches and URLs. Set to 0 for no cap (internal safety limit of 100,000 applies). Results arrive in full pages of ~36, so the final page may overshoot by a few rows. |

### Output

One flat row per Otodom listing. Here's a representative sale-side result for a new-build development in Kraków:

```json
{
    "url": "https://www.otodom.pl/pl/oferta/mista-krakow-ID4zTk9",
    "id": 67659493,
    "title": "Mista Kraków",
    "dealType": "sale",
    "propertyType": "investment",
    "price": 489258,
    "pricePerSquareMeter": 15782,
    "currency": "PLN",
    "area": 31,
    "rooms": 1,
    "floor": 2,
    "totalFloors": 5,
    "buildYear": 2025,
    "location": {
        "voivodeship": "małopolskie",
        "county": "Kraków",
        "city": "Kraków",
        "district": "Mistrzejowice",
        "street": "ul. Mistrzejowicka",
        "postalCode": "31-641",
        "latitude": 50.099307,
        "longitude": 20.023872
    },
    "description": "1, 2, 3 i 4-pokojowe mieszkania od 31 m2 do 77 m2 od dewelopera Victoria Dom...",
    "images": [
        "https://ireland.apollo.olxcdn.com/v1/files/eyJmbiI6Im.../image;s=1280x1024;q=80",
        "https://ireland.apollo.olxcdn.com/v1/files/eyJmbiI6Mj.../image;s=1280x1024;q=80"
    ],
    "features": [
        "Miejsce parkingowe podziemne",
        "Balkon",
        "Windy",
        "Strefa wypoczynku",
        "Przyjazny dla osób niepełnosprawnych"
    ],
    "agent": {
        "name": "Biuro Sprzedaży",
        "phone": "+48573582897",
        "email": null,
        "agencyName": "Victoria Dom",
        "agencyUrl": "https://www.otodom.pl/pl/firmy/deweloperzy/victoria-dom-ID10556508"
    },
    "marketType": "PRIMARY",
    "addedAt": "2026-01-30T11:23:15+01:00",
    "updatedAt": "2026-05-22T11:56:00+02:00",
    "scrapedAt": "2026-05-23T12:23:32.319635+00:00",
    "sourceListUrl": "https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/malopolskie/krakow/krakow/krakow"
}
```

#### Core Identity

| Field | Type | Description |
|-------|------|-------------|
| `url` | string | Direct Otodom listing URL |
| `id` | number | Unique Otodom listing identifier |
| `title` | string | Listing title as shown on Otodom |
| `dealType` | string | `sale` or `rent` |
| `propertyType` | string | `apartment`, `studio`, `house`, `room`, `plot`, `commercial`, `hall`, `garage`, or `investment` |
| `marketType` | string | `PRIMARY` (new build), `SECONDARY` (resale), `ALL`, or `null` |

#### Pricing

| Field | Type | Description |
|-------|------|-------------|
| `price` | number | Listing price in PLN. For rentals this is the monthly rent. |
| `pricePerSquareMeter` | number | Price per square metre in PLN — ready to sort, filter, and chart |
| `currency` | string | Always `PLN` |

#### Property Details

| Field | Type | Description |
|-------|------|-------------|
| `area` | number | Floor area in square metres |
| `rooms` | number | Number of rooms (1–10, with 6+ rolled into 6) |
| `floor` | number / string | Floor number (0 = ground floor); special labels like `Garret`, `Cellar` are passed through as strings |
| `totalFloors` | number | Total floors in the building |
| `buildYear` | number | Year the building was constructed |
| `features` | string\[] | Amenity and feature labels in Polish (e.g. parking, balcony, lift, storage room) |

#### Location

| Field | Type | Description |
|-------|------|-------------|
| `location.voivodeship` | string | Polish voivodeship (e.g. `mazowieckie`, `małopolskie`) |
| `location.county` | string | County (powiat) name |
| `location.city` | string | City name |
| `location.district` | string | District / neighbourhood |
| `location.street` | string | Street name with `ul.` prefix when present |
| `location.postalCode` | string | Polish postal code (e.g. `31-641`) |
| `location.latitude` | number | Latitude (WGS84) |
| `location.longitude` | number | Longitude (WGS84) |

#### Description & Media

| Field | Type | Description |
|-------|------|-------------|
| `description` | string | Full plain-text description from the detail page (HTML stripped) |
| `images` | string\[] | All listing photo URLs at 1280×1024 from the source CDN |

#### Agent Contact

| Field | Type | Description |
|-------|------|-------------|
| `agent.name` | string | Seller / agent name (or "Biuro Sprzedaży" for developer sales offices) |
| `agent.phone` | string | Phone number in plaintext E.164 format (e.g. `+48573582897`) |
| `agent.email` | string | Contact email when published — most listings expose phone only |
| `agent.agencyName` | string | Agency or developer name |
| `agent.agencyUrl` | string | Otodom profile page for the agency / developer |

#### Metadata

| Field | Type | Description |
|-------|------|-------------|
| `addedAt` | string | When the listing was first published on Otodom (ISO 8601) |
| `updatedAt` | string | Last update on Otodom (ISO 8601) |
| `scrapedAt` | string | When this row was collected (ISO 8601 UTC) |
| `sourceListUrl` | string | The exact search URL this row came from — useful for traceability and debugging |

### Tips for Best Results

- **Use Polish characters in `location`** — `Warszawa`, `Kraków`, `Gdańsk`, `Łódź`. The actor folds diacritics automatically, but native spellings match Otodom's own search dictionary most reliably.
- **For sub-district precision, paste a Start URL** — Polish cities use a four-level voivodeship/county/city/district hierarchy. The actor resolves city names automatically; for a specific district (e.g. Warszawa-Mokotów), open the search in your browser and paste the URL into `startUrls`.
- **Use `marketType: primary` to find new-build developments only** — these often appear in pre-sale and are harder to surface on aggregators. Pair with `propertyType: investment` to list entire development projects.
- **Sort by `Lowest price first` plus a tight `priceMax` band** — surfaces the best price-per-m² listings in your filter set. Pair with `buildYearMin: 2015` to focus on recent stock.
- **Room counts are ignored for plots, garages, commercial, and halls** — Otodom does not index them by room count, so leave `rooms` empty for those property types.
- **Start with `maxResults: 50–100` to verify your filter combination** — once the result mix looks right, re-run with `maxResults: 0` (capped internally at 100,000) for the full sweep.
- **`cała Polska` is the country-wide fallback** — leave `location` empty or set it to `cała Polska` to scan every Polish region in one run. Useful for nationwide developer or commercial inventory pulls.

### Pricing

**$0.95 per 1,000 listings, pay-per-result.** You only pay for the rows we return — no compute charges, no per-minute billing. Below the typical $1.00/1,000 market rate for Polish real-estate data.

| Listings | Cost |
|----------|------|
| 100 | $0.10 |
| 1,000 | $0.95 |
| 10,000 | $9.50 |
| 100,000 | $95.00 |

A "result" is any listing row in the output dataset. Platform fees (storage, data transfer) are additional and depend on your Apify plan.

### Integrations

Export data in JSON, CSV, Excel, XML, or RSS. Connect to 1,500+ apps via:

- **Zapier** / **Make** / **n8n** — Workflow automation
- **Google Sheets** — Direct spreadsheet export
- **Slack** / **Email** — Notifications on new results
- **Webhooks** — Trigger custom APIs on run completion
- **Apify API** — Full programmatic access

### Legal & Ethical Use

This actor is designed for legitimate market research, lead generation, relocation research, and personal property search. Users are responsible for complying with applicable laws — including Polish and EU data protection rules (GDPR / RODO) — and with Otodom.pl's Terms of Service. Do not use extracted contact data for spam, unsolicited bulk messaging, or any unlawful purpose. Be mindful of consent and opt-out obligations when contacting individuals identified through this data.

# Actor input Schema

## `dealType` (type: `string`):

Are you looking for properties to buy or to rent? Ignored when Start URLs are provided (the URL controls deal type).

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

Filter by property category. Mirrors Otodom's own category navigation. Note: 'Room' is only valid with Deal Type = For Rent. If you pick Room + For Sale, the actor will automatically switch to For Rent and warn you (Otodom does not sell individual rooms).

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

Where in Poland to search — a city name (e.g. 'Warszawa', 'Kraków', 'Gdańsk'), voivodeship, or 'cała Polska' for the entire country. Polish characters are accepted and recommended.

## `radius` (type: `string`):

Expand the search this many kilometres beyond the selected location. Set 0 to limit results to the location boundary itself. Matches Otodom's UI options.

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

Power-user input. Paste Otodom search-result URLs (e.g. https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/warszawa) or individual listing URLs (e.g. https://www.otodom.pl/pl/oferta/...). When provided, these override the Deal Type / Property Type / Location / Filters settings above.

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

Only include listings priced at or above this amount in Polish złoty. Leave empty for no minimum.

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

Only include listings priced at or below this amount in Polish złoty. Leave empty for no maximum.

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

Only include properties with floor area at or above this many square metres.

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

Only include properties with floor area at or below this many square metres.

## `rooms` (type: `array`):

Only include properties with these room counts. Select multiple to combine. Leave empty for no filter. Applies to apartments, houses, and rooms — ignored for plots, garages, and commercial.

## `buildYearMin` (type: `integer`):

Only include properties built in or after this year. Leave empty for no minimum. Most useful for apartments and houses; ignored by Otodom for plots, garages, and commercial premises.

## `buildYearMax` (type: `integer`):

Only include properties built in or before this year. Leave empty for no maximum.

## `marketType` (type: `string`):

Primary market (developer / new build) vs secondary market (resale). Otodom uses this distinction prominently on sale listings.

## `sortBy` (type: `string`):

How Otodom orders results before we collect them.

## `maxResults` (type: `integer`):

Maximum number of listings to collect across all searches and URLs. Set to 0 for no cap (an internal safety limit of 100,000 is then applied). Results are collected in full pages of ~36 listings, so the final page may overshoot this number by a few rows.

## Actor input object example

```json
{
  "dealType": "sale",
  "propertyType": "apartment",
  "location": "Warszawa",
  "radius": "0",
  "startUrls": [],
  "rooms": [],
  "marketType": "any",
  "sortBy": "default",
  "maxResults": 100
}
```

# Actor output Schema

## `overview` (type: `string`):

Table of scraped listings with the key fields — title, price, area, rooms, city, and listing URL.

## `details` (type: `string`):

Full per-listing fields including images, agency, agent contacts, market type, construction year, GPS coordinates, and timestamps.

# 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 = {
    "dealType": "sale",
    "propertyType": "apartment",
    "location": "Warszawa",
    "radius": "0",
    "startUrls": [],
    "rooms": [],
    "marketType": "any",
    "sortBy": "default",
    "maxResults": 100
};

// Run the Actor and wait for it to finish
const run = await client.actor("solidcode/otodom-pl-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 = {
    "dealType": "sale",
    "propertyType": "apartment",
    "location": "Warszawa",
    "radius": "0",
    "startUrls": [],
    "rooms": [],
    "marketType": "any",
    "sortBy": "default",
    "maxResults": 100,
}

# Run the Actor and wait for it to finish
run = client.actor("solidcode/otodom-pl-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 '{
  "dealType": "sale",
  "propertyType": "apartment",
  "location": "Warszawa",
  "radius": "0",
  "startUrls": [],
  "rooms": [],
  "marketType": "any",
  "sortBy": "default",
  "maxResults": 100
}' |
apify call solidcode/otodom-pl-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,solidcode/otodom-pl-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/hVOvdqJM8S4tDj0Sh/builds/LncNxg8nczb0uoEBa/openapi.json
