# Otodom Scraper - Polish Real Estate Listings (`scraptivo/otodom-scraper`) Actor

Scrapes property listings from Otodom.pl, Poland's leading real estate marketplace. Supports filters for transaction type, property type, location, price, area, rooms, building type, extras, and more.

- **URL**: https://apify.com/scraptivo/otodom-scraper.md
- **Developed by:** [Scraptivo](https://apify.com/scraptivo) (community)
- **Categories:** Real estate, Integrations, MCP servers
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Scraper** collects property listings from Otodom.pl, Poland's leading real estate marketplace, and turns them into structured data for real estate analysis, lead generation, and market monitoring. Provide a search URL or a location with filters, run the Actor, and export prices, area, rooms, floor, address, images, and seller details to JSON, CSV, Excel, or your preferred integration. Use it to track asking prices, build property lists, and monitor new listings. Each property result costs $0.001.

### What can you automate with Otodom Scraper?

- **Track asking prices** — collect total price and price per square meter across cities and property types.
- **Build property lists** — filter by transaction, property type, price, area, rooms, and building type.
- **Monitor new listings** — schedule recurring runs to catch fresh offers by date.
- **Identify private sellers vs agencies** — export `isPrivateOwner` and `agencyName`.
- **Feed a CRM or spreadsheet** — export JSON, CSV, or Excel for outreach or analysis.

### Who is this scraper for?

| Team | Workflow |
|---|---|
| Real estate agents | Monitor competing listings and pricing in their market. |
| Investors and analysts | Track price trends and yields by location and property type. |
| Lead-generation teams | Build lists of sellers and agents with contact context. |
| Proptech and data teams | Power apps and dashboards with structured listing data. |

### What data can you collect from Otodom?

| Data group | Example fields | How it helps |
|---|---|---|
| Listing identity | id, title, url, dateCreated | Identify and link the offer. |
| Price | totalPrice, priceCurrency, pricePerSquareMeter | Assess value and compare. |
| Property details | areaInSquareMeters, roomsNumber, floorNumber, estate, transaction | Qualify the property. |
| Location | city, province, street, location | Map and target areas. |
| Seller | isPrivateOwner, agencyName, ownerName, isExclusiveOffer | Understand who is selling. |

### How to use Otodom Scraper

1. Open the Actor in the Scraptivo account.
2. Paste a copied Otodom search URL, or enter a location plus filters.
3. Set optional filters for price, area, rooms, and property type.
4. Run the Actor.
5. Export the dataset to JSON, CSV, Excel, or your integration.

```json
{ "locationQuery": "Bielawa", "transaction": "RENT", "estate": "FLAT", "maxItems": 20 }
```

### Example workflow

#### Track apartment asking prices in a district every week

1. Run an apartment (`FLAT`) search for one city every Monday.
2. Keep listings posted in the last 7 days.
3. Send new records to Google Sheets or a CRM.
4. Deduplicate using the stable listing `id`.

### Automate and integrate your results

- **Schedule** daily or weekly runs per location using Apify's Scheduler or the API.
- **Webhooks** after a successful run to trigger your downstream pipeline.
- **Export** to Google Sheets, Make, Zapier, Slack, or a database.
- **Deduplicate** using the stable `id` field.

```shell
curl "https://api.apify.com/v2/acts/scraptivo~otodom-scraper/run-sync" -H "Content-Type: application/json" -d '{"locationQuery":"Bielawa","transaction":"SELL","estate":"FLAT","maxItems":20}'
```

### Input reference

| Field | Type | Required | Default | What it controls |
|---|---|---|---:|---|
| searchUrl | string | no | — | Full Otodom search URL; when set, filter fields are ignored. |
| locationQuery | string | no | — | City/region name or Otodom domain path. |
| transaction | string | no | SELL | For sale or for rent. |
| estate | string | no | FLAT | Property type (apartment, house, plot, etc.). |
| market | string | no | ALL | Primary (new), secondary (resale), or all. |
| ownerType | string | no | ALL | Filter by private, developer, or agency. |
| availability | string | no | "" | Filter by "available now" or any. |
| priceMin / priceMax | integer | no | — | Price range in PLN. |
| areaMin / areaMax | integer | no | — | Living area range in m². |
| roomsNumber | array | no | — | Filter by number of rooms (1 to 6+). |
| buildingType | array | no | — | Building construction type. |
| heating | array | no | — | Heating type. |
| floorNumber | array | no | — | Floor position. |
| floorsNumberMin / Max | integer | no | — | Building floor count range. |
| buildYearMin / Max | integer | no | — | Construction year range. |
| extras | array | no | — | Amenities (balcony, garage, elevator, etc.). |
| daysSinceCreated | string | no | "" | Filter by listing age (1/3/7/14/30 days). |
| hasPhotos | boolean | no | false | Only listings with photos. |
| isExclusiveOffer | boolean | no | false | Only exclusive (private) offers. |
| sortBy | string | no | DEFAULT | Sort by price, date, or area. |
| sortDirection | string | no | DESC | Ascending or descending order. |
| maxPages | integer | no | 0 | Max result pages to scrape (0 = unlimited). |
| maxItems | integer | no | 100 | Max listings to scrape (0 = unlimited). |
| proxyConfiguration | object | no | RESIDENTIAL | Proxy settings for anti-bot protection. |

### Output example

```json
{
  "id": 68126450,
  "title": "3-POKOJOWE MIESZKANIE – BIELAWA, UL. REYMONTA",
  "url": "https://www.otodom.pl/pl/ad/3-pokojowe-mieszkanie-bielawa-ul-reymonta-ID4BQNI",
  "estate": "FLAT",
  "transaction": "RENT",
  "totalPrice": 1900,
  "priceCurrency": "PLN",
  "pricePerSquareMeter": 29,
  "areaInSquareMeters": 65,
  "roomsNumber": "THREE",
  "floorNumber": "SECOND",
  "city": "Bielawa",
  "province": "dolnośląskie",
  "isPrivateOwner": true,
  "hasPhotos": true,
  "imageCount": 11
}
```

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

Otodom Scraper uses pay-per-event billing on Apify:

- **$0.001 per property result** (the headline result event).
- **$0.00005 per run** for the actor-start event.

Examples: 100 listings cost about $0.10; 1,000 listings cost about $1.00 plus the start fee. Residential proxy traffic is billed separately by Apify according to your plan.

### Reliability and responsible use

- Residential proxies are enabled by default for anti-bot protection.
- When `searchUrl` is provided, the filter fields are ignored and only `maxItems`, `maxPages`, and proxy apply.
- Location names are resolved automatically via Otodom's autocomplete.
- Scrape only public listing data and follow Otodom's terms of service.

### Frequently asked questions

#### Can I scrape Otodom by search URL instead of filters?

Yes. Paste a copied Otodom search URL into `searchUrl`; the Actor uses it as-is and ignores the filter fields.

#### Can I filter by price, area, and rooms?

Yes. Use `priceMin`/`priceMax`, `areaMin`/`areaMax`, and `roomsNumber`. These apply only when `searchUrl` is empty.

#### What counts as one result?

One property listing in the dataset.

#### Why are some fields empty?

Some listings do not publish every field (e.g. `agencyName` is empty for private sellers, and `pricePerSquareMeter` can be missing).

#### How do I avoid duplicate records?

Deduplicate on the stable `id` field before writing to your CRM or spreadsheet.

#### Do I need a proxy?

Residential proxies are recommended and enabled by default for anti-bot protection.

### Related Scraptivo automations

- [Apartments Scraper](https://apify.com/scraptivo/apartments-scraper) — apartment listings from Apartments.com.
- [Immobiliare Scraper](https://apify.com/scraptivo/immobiliare-scraper) — property listings from Immobiliare.it.
- [Rightmove Scraper](https://apify.com/scraptivo/rightmove-scraper) — UK property listings from Rightmove.
- [Immowelt Property Scraper](https://apify.com/scraptivo/immowelt-property-scraper) — German property listings from Immowelt.

### Support and custom workflows

Need a different field, source, or delivery workflow? Contact Scraptivo at scraptivo@gmail.com. Include the Actor name, a sample URL, the required fields, and expected volume so we can assess the request.

# Actor input Schema

## `searchUrl` (type: `string`):

Full URL copied from otodom.pl search results. When provided, this URL is preferred and all filter fields below are ignored (only Max Items, Max Pages, and Proxy apply).

## `locationQuery` (type: `string`):

City or region name (e.g. 'Bielawa', 'Warszawa') or full Otodom domain path (e.g. 'dolnoslaskie/dzierzoniowski/bielawa/bielawa'). Free-text names are resolved automatically via Otodom autocomplete. Ignored when Search URL is provided.

## `transaction` (type: `string`):

For sale or for rent. Ignored when Search URL is provided.

## `estate` (type: `string`):

Type of property. Ignored when Search URL is provided.

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

Primary (new developments) or Secondary (resale). Ignored when Search URL is provided.

## `ownerType` (type: `string`):

Filter by seller type. Ignored when Search URL is provided.

## `availability` (type: `string`):

When the property is available from. Ignored when Search URL is provided.

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

Minimum total price in PLN. Ignored when Search URL is provided.

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

Maximum total price in PLN. Ignored when Search URL is provided.

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

Minimum living area in square meters. Ignored when Search URL is provided.

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

Maximum living area in square meters. Ignored when Search URL is provided.

## `roomsNumber` (type: `array`):

Filter by number of rooms. Ignored when Search URL is provided.

## `buildingType` (type: `array`):

Type of building construction. Ignored when Search URL is provided.

## `heating` (type: `array`):

Heating type. Ignored when Search URL is provided.

## `floorNumber` (type: `array`):

Floor position of the property. Ignored when Search URL is provided.

## `floorsNumberMin` (type: `integer`):

Minimum number of floors in the building. Ignored when Search URL is provided.

## `floorsNumberMax` (type: `integer`):

Maximum number of floors in the building. Ignored when Search URL is provided.

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

Minimum construction year. Ignored when Search URL is provided.

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

Maximum construction year. Ignored when Search URL is provided.

## `extras` (type: `array`):

Property amenities (multi-select). Ignored when Search URL is provided.

## `daysSinceCreated` (type: `string`):

Filter listings by how recently they were posted. Ignored when Search URL is provided.

## `hasPhotos` (type: `boolean`):

Only show listings that have photos. Ignored when Search URL is provided.

## `isExclusiveOffer` (type: `boolean`):

Only show exclusive offers (private listings). Ignored when Search URL is provided.

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

How to sort the results. Ignored when Search URL is provided.

## `sortDirection` (type: `string`):

Ascending or descending order. Ignored when Search URL is provided.

## `maxPages` (type: `integer`):

Maximum number of result pages to scrape (0 = unlimited, ~36 listings per page). maxItems takes precedence.

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

Maximum number of listings to scrape (0 = unlimited). Takes precedence over maxPages.

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

Proxy settings for anti-bot protection

## Actor input object example

```json
{
  "searchUrl": "https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/dolnoslaskie/dzierzoniowski/bielawa/bielawa?priceMin=0&priceMax=500000",
  "locationQuery": "dolnoslaskie/dzierzoniowski/bielawa/bielawa",
  "transaction": "SELL",
  "estate": "FLAT",
  "market": "ALL",
  "ownerType": "ALL",
  "availability": "",
  "daysSinceCreated": "",
  "hasPhotos": false,
  "isExclusiveOffer": false,
  "sortBy": "DEFAULT",
  "sortDirection": "DESC",
  "maxPages": 0,
  "maxItems": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (type: `string`):

Dataset containing scraped property listings

# 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 = {
    "searchUrl": "https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/dolnoslaskie/dzierzoniowski/bielawa/bielawa?priceMin=0&priceMax=500000",
    "locationQuery": "dolnoslaskie/dzierzoniowski/bielawa/bielawa",
    "maxItems": 20
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraptivo/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 = {
    "searchUrl": "https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/dolnoslaskie/dzierzoniowski/bielawa/bielawa?priceMin=0&priceMax=500000",
    "locationQuery": "dolnoslaskie/dzierzoniowski/bielawa/bielawa",
    "maxItems": 20,
}

# Run the Actor and wait for it to finish
run = client.actor("scraptivo/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 '{
  "searchUrl": "https://www.otodom.pl/pl/wyniki/sprzedaz/mieszkanie/dolnoslaskie/dzierzoniowski/bielawa/bielawa?priceMin=0&priceMax=500000",
  "locationQuery": "dolnoslaskie/dzierzoniowski/bielawa/bielawa",
  "maxItems": 20
}' |
apify call scraptivo/otodom-scraper --silent --output-dataset

```

## MCP server setup

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