# Otodom.pl Scraper — Polish Real Estate Listings & Leads (`ahmed_jasarevic/otodom-pl-property-scraper`) Actor

Extract listings from Otodom.pl — Poland's #1 property portal. Get price, price/m², rooms, agent & agency contacts, photos, GPS coordinates. Fast HTTP scraper, no browser. Sale & rent, apartments to commercial, nationwide. From $1.90/1,000 results.

- **URL**: https://apify.com/ahmed\_jasarevic/otodom-pl-property-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Categories:** Real estate, Automation, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.90 / 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/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 — Polish Real Estate Listings & Leads

Scrape **otodom.pl — Poland's #1 real estate portal** (OLX Group, 200K+ active listings). Get structured data for apartments, houses, plots, commercial space, garages and rooms — for sale or rent — including **price, price/m², area, rooms, floor, building type, market (primary/secondary), advertiser type (private/agency/developer), agent name & phone numbers, full description, photo gallery, publish date and exact GPS coordinates**.

The actor reads Otodom's own embedded `__NEXT_DATA__` JSON — **pure HTTP, no browser**, so it's fast and reliable, priced at **$1.90 per 1,000 results**.

### Why use this Actor?

Built for **Polish real estate agencies, property investors, market analysts and lead-gen teams**:

- **Lead generation** — agent/agency name + phone numbers on every listing, with advertiser type (private owner vs agency vs developer) so you can target the right sellers
- **Market analysis** — price, price/m², area, rooms, floor, building type, market segment (primary/secondary) and publish dates for time-series and PLN/m² heatmaps
- **Investment screening** — exact geo coordinates + full address hierarchy (province → city → district → street) for polygon/radius analysis
- **Change tracking** — `publishDate`, `modifiedAt` and `pushedUpAt` timestamps let you diff runs to detect new listings and price changes
- **Simple, transparent pricing** — $1.90 per 1,000 results, no subscriptions or compute-unit guesswork

### How to use

1. Open **otodom.pl** in your browser, set your filters (city, district, price range, rooms, market, sort), and copy the URL from the address bar.
2. Paste one or more of those URLs into the **Otodom URLs** input field (search URLs are paginated automatically; offer URLs are scraped directly).
3. Set **Maximum listings** and **Max pages per search URL**, then click **Start**.
4. Download the results as **JSON, CSV, Excel or XML** from the Dataset tab.

Example search URL:

```
https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/mazowieckie/warszawa/warszawa/warszawa
```

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `startUrls` | array | — | One or more otodom.pl search or offer URLs |
| `maxItems` | integer | 1000 | Hard cap on listings collected per run |
| `maxPagesPerSearch` | integer | 10 | Result pages walked per search URL (36 listings/page) |
| `maxConcurrency` | integer | 4 | Parallel requests (keep modest to avoid rate-limiting) |
| `proxy` | proxy | Residential | Apify Proxy; **Residential IPs recommended** — otodom blocks datacenter IPs |

### Output

One flat JSON row per listing. Example:

```json
{
  "id": 67977497,
  "url": "https://www.otodom.pl/pl/oferta/targowek-ul-turmoncka4-pokoje-balkon-parking-metro-brodno-10min-ID4Be3f",
  "title": "Targówek ul.Turmoncka⭐4 pokoje + balkon PARKING // Metro Bródno 10min",
  "transaction": "sprzedaz",
  "propertyType": "mieszkanie",
  "market": "secondary",
  "advertiserType": "agency",
  "price": 969000,
  "priceCurrency": "PLN",
  "pricePerSqm": 14571.43,
  "areaSqm": 66.5,
  "rooms": 4,
  "floor": "ground floor",
  "buildingFloors": 4,
  "buildYear": 2020,
  "buildingType": "block",
  "agentName": "Oddział Warszawa Forma Estates",
  "agentPhones": ["+48579528009", "+48697002400"],
  "agencyName": "Forma Estates",
  "description": "Targówek - ul.Tarmoncka⭐66,5m2 / balkon / piwnica / parking...",
  "photos": ["https://ireland.apollo.olxcdn.com/v1/files/.../image;s=2048x1536;q=80"],
  "photoCount": 12,
  "publishDate": "2026-05-06T11:44:14Z",
  "latitude": 52.29786,
  "longitude": 21.0353,
  "street": "ul. Turmoncka",
  "district": "Targówek",
  "city": "Warszawa",
  "province": "mazowieckie",
  "scrapedAt": "2026-08-16T06:30:00.000Z"
}
```

You can download the dataset in various formats such as **JSON, HTML, CSV, or Excel**.

### Data table

| Field | Description |
|---|---|
| `id`, `url`, `title` | Listing identity |
| `transaction` | `sprzedaz` (sale) / `wynajem` (rent) |
| `propertyType` | `mieszkanie`, `dom`, `dzialka`, `lokal`, ... |
| `market` | `primary` (new from developer) / `secondary` (resale) |
| `advertiserType` | `private` / `agency` / `developer` |
| `price`, `priceCurrency`, `pricePerSqm` | Pricing in PLN |
| `areaSqm`, `rooms`, `floor`, `buildingFloors`, `buildYear` | Property specs |
| `buildingType`, `buildingMaterial`, `constructionStatus`, `ownership` | Construction details |
| `agentName`, `agentPhones`, `agencyName`, `agencyId` | Advertiser lead data |
| `description` | Full listing text (HTML stripped) |
| `photos`, `photoCount` | Image gallery URLs |
| `publishDate`, `modifiedAt`, `pushedUpAt` | Listing timestamps |
| `latitude`, `longitude` | Exact GPS coordinates |
| `street`, `district`, `city`, `province`, `subdistrict`, `postalCode` | Address hierarchy |
| `features` | Equipment / extras / security tags |

### Pricing

This Actor uses simple **pay-per-result pricing: $1.90 per 1,000 results**. No subscriptions, no compute-unit guesswork — you only pay for the listings you actually extract. Because it's a pure HTTP scraper with no browser overhead, this pricing stays predictable even on large, nationwide runs. **Free Apify users** get a capped preview of **10 listings** per run; paid users get unlimited runs up to the configured `maxItems`. Residential proxy traffic is billed per Apify's standard proxy rates — recommended because otodom.pl blocks datacenter IPs.

### Tips & advanced options

- **Use residential proxy** — otodom.pl serves 403s to datacenter IPs. The actor defaults to Apify Residential proxy.
- **Keep `maxConcurrency` modest** (4-6) to avoid rate-limiting and keep your IP pool healthy.
- **Copy filtered search URLs** from your browser for precise targeting (price, rooms, market, district).
- **Diff `publishDate` across scheduled runs** to detect new listings and price changes.
- **Investment/development pages** (`estate: INVESTMENT`) are skipped — they are development marketing pages, not individual listings.

### FAQ

**How much does it cost to scrape Otodom.pl with this Actor?**
$1.90 per 1,000 results — a flat, predictable price regardless of how much detail you extract per listing.

**Is this legal?**
Scraping publicly available listing data for analysis is generally permitted, but you should review otodom.pl's Terms of Service and applicable law (including the Polish Act on the Protection of Personal Data) before using scraped data commercially. This Actor only collects data that is publicly displayed on listing pages.

**Does it need a browser or special proxies?**
No browser — it's pure HTTP, which is why it stays fast and efficient. Residential proxy is recommended and required, since otodom.pl blocks datacenter IPs.

**What lead data can I extract?**
Agent name, agency name, and phone numbers on every listing, plus advertiser type (private/agency/developer) so you can target the right sellers for outreach.

**Known limitations** — Otodom may rate-limit or block aggressive crawling; use residential proxies and modest concurrency. Some listings hide prices or contact details by the advertiser's choice — those fields will be `null`.

**Support**: found a bug or want a custom feature? Open an issue on the Actor's Issues tab, or contact us for a custom solution.

# Actor input Schema

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

One or more otodom.pl URLs. Search URLs (https://www.otodom.pl/pl/wyniki/...) are paginated automatically and fanned out to individual offer pages. Offer URLs (https://www.otodom.pl/pl/oferta/...) are scraped directly. Tip: open otodom.pl, set your filters (city, district, price, rooms, market), copy the URL from the address bar.

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

Hard cap on the number of listings collected per run.

## `maxPagesPerSearch` (type: `integer`):

Maximum number of result pages to walk for each search URL (each page holds up to 36 listings).

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

Number of parallel requests. Keep modest to avoid rate-limiting.

## `proxy` (type: `object`):

Apify Proxy with Residential IPs is recommended to avoid blocking (otodom.pl blocks datacenter IPs).

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/mazowieckie/warszawa/warszawa/warszawa"
    }
  ],
  "maxItems": 1000,
  "maxPagesPerSearch": 10,
  "maxConcurrency": 4,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (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": [
        {
            "url": "https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/mazowieckie/warszawa/warszawa/warszawa"
        }
    ],
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/otodom-pl-property-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": [{ "url": "https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/mazowieckie/warszawa/warszawa/warszawa" }],
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/otodom-pl-property-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": [
    {
      "url": "https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/mazowieckie/warszawa/warszawa/warszawa"
    }
  ],
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call ahmed_jasarevic/otodom-pl-property-scraper --silent --output-dataset

```

## MCP server setup

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