# Otodom Scraper (`simoit/otodom-scraper`) Actor

Extract Polish real-estate listings from Otodom.pl with prices, locations, property details, images and seller information. Filter by location, map area, property type, budget, rooms and building features.

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

## Pricing

from $1.50 / 1,000 offer 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/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 Real Estate Scraper

Fast and reliable Apify Actor for scraping public property listings from
Otodom.pl, Poland's largest real-estate portal. Collect apartments, houses and
land listings with prices, locations, technical details, images and seller data.

### Features

- Sale and rental listings for apartments, houses, plots, rooms, garages and commercial properties.
- Search by Otodom location ID or map-drawn GeoJSON polygon.
- Fast listing mode or detail mode with concurrent page enrichment.
- Multi-page pagination with `maxItems` and ID/URL deduplication.
- Price, area, rooms, market, `buildingType`, `extras`, build-year and publication filters.
- Clean descriptions and AI decision signals for renovation, tenants, auctions, financing and commission.
- Coordinates, image URLs, seller/agency data and publicly exposed phone numbers.
- Automatic proxy rotation, retries and browser-like requests are enabled by default; no proxy setup is required.

### Input parameters

| Parameter | Type | Default | Description |
| --- | --- | --- | --- |
| `location` | string | Warsaw | Province/city such as `mazowieckie/warszawa`; full Otodom IDs are also accepted |
| `geometry` | object | — | GeoJSON `Polygon` or `MultiPolygon` from map drawing |
| `transaction` | string | `sell` | `sell` or `rent` |
| `estate` | string | `flat` | `flat`, `house`, `terrain`, `room`, `garage` or `commercial` |
| `buildingType` | array | — | Values such as `BLOCK`, `TENEMENT` |
| `extras` | array | — | Values such as `GARAGE` |
| `priceMin` / `priceMax` | integer | — | Price range in PLN |
| `areaMin` / `areaMax` | number | — | Area range in m² |
| `roomsMin` / `roomsMax` | integer | — | Room range from 1 to 6 |
| `buildYear` | integer | — | Minimum construction year |
| `postedDate` | string | — | Otodom publication-date filter |
| `maxItems` | integer | `50` | Maximum results across pages (1–1000) |
| `extractDetails` | boolean | `true` | Visit detail pages for full enrichment |
| `maxConcurrency` | integer | `5` | Parallel detail requests (1–20) |

Otodom pages contain 20 listings. The Actor follows additional pages until the
limit is reached or no more results are available.

### Listing mode output

With `extractDetails: false`, each item includes `id`, `title`, `url`, `price`,
`currency`, `price_per_square_meter`, `area`, `rooms`, `market`, `city`, `street`,
`image_url`, owner/promotion flags and `created_at`.

### Detail mode output

With `extractDetails: true`, each item also has `details` containing:

- `description_preview` and `decision_signals`
- `characteristics`, `attributes`, `features` and `additional_information`
- `images`, `images_total`, `coordinates` and `address`
- seller `type`, `name`, `agency`, `phone` and `has_phone_number`

Public phone example:

```json
{
  "id": "67962236",
  "title": "3 rooms, balcony, near M2 metro",
  "price": 474999,
  "currency": "PLN",
  "area": 47.5,
  "rooms": 3,
  "city": "Warszawa",
  "details": {
    "description_preview": "Apartment requires renovation...",
    "decision_signals": [{"type": "requires_renovation", "evidence": "..."}],
    "coordinates": {"latitude": 52.287846, "longitude": 21.044584},
    "seller": {
      "type": "agency",
      "name": "Example Agency",
      "agency": "Example Agency",
      "phone": "+48123456789",
      "has_phone_number": true
    }
  }
}
```

Masked/private phone numbers are returned as `null`; the Actor does not bypass
Otodom contact controls.

### Usage examples

#### Apartments for sale in Warsaw

```json
{
  "location": "mazowieckie/warszawa",
  "transaction": "sell",
  "estate": "flat",
  "priceMax": 1000000,
  "roomsMin": 2,
  "roomsMax": 4,
  "maxItems": 100,
  "extractDetails": true
}
```

#### Rental apartments in Krakow

```json
{
  "location": "malopolskie/krakow",
  "transaction": "rent",
  "estate": "flat",
  "priceMax": 4000,
  "maxItems": 50,
  "extractDetails": true
}
```

#### Fast listing-only scrape

```json
{
  "location": "mazowieckie/warszawa",
  "estate": "flat",
  "maxItems": 500,
  "extractDetails": false
}
```

#### Map-drawn area

```json
{
  "location": "cala-polska",
  "geometry": {
    "type": "Polygon",
    "coordinates": [[[21.01,52.24],[21.06,52.24],[21.06,52.28],[21.01,52.24]]]
  },
  "maxItems": 50
}
```

### How to run

1. Open the Actor in Apify Console and click **Start**.
2. Fill in the Input form, or paste one of the JSON examples above.
3. Choose **Run** and open the default Dataset when the run finishes.

For a first run, use `maxItems: 20` and `extractDetails: false`. Enable
`extractDetails` when you need descriptions, images, coordinates and seller
information. The Actor handles pagination and deduplicates listings by URL.

Proxy rotation, retries and request pacing are automatic. You do not need to
provide proxy credentials or any environment variables.

### Pricing and billing

The Actor is billed automatically through Apify per returned listing. Every run
has a minimum charge of 20 events: 11 results consume 20 events, while 21
results consume 21 events. A run with no matching listings also consumes 20
events.

On the free plan you can start **3 searches per calendar month**, with up to
**20 listings per search**. Paid Apify plans can run larger searches according
to the same minimum-charge billing shown in the Console.

Invalid filters are reported directly in the run output. If Otodom is
temporarily unavailable, Apify marks the run as failed and can retry it.

# Actor input Schema

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

Province/city path or full Otodom domain ID.

## `geometry` (type: `object`):

Polygon or MultiPolygon drawn on the map.

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

Sell or rent listings.

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

Otodom property category.

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

Otodom building type enum values.

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

Otodom extra feature enum values.

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

Minimum price in PLN.

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

Maximum price in PLN.

## `areaMin` (type: `number`):

Minimum area in square metres.

## `areaMax` (type: `number`):

Maximum area in square metres.

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

Minimum construction year.

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

Minimum number of rooms.

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

Maximum number of rooms.

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

Otodom publication-date filter.

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

Maximum listings returned across pages.

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

Fetch and enrich individual property pages.

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

Maximum parallel detail requests.

## Actor input object example

```json
{
  "location": "mazowieckie/warszawa",
  "transaction": "sell",
  "estate": "flat",
  "buildingType": [],
  "extras": [],
  "maxItems": 50,
  "extractDetails": true,
  "maxConcurrency": 5
}
```

# Actor output Schema

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

No description

## `runInfo` (type: `string`):

No description

## `billing` (type: `string`):

No description

## `clientError` (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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("simoit/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 = {}

# Run the Actor and wait for it to finish
run = client.actor("simoit/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 '{}' |
apify call simoit/otodom-scraper --silent --output-dataset

```

## MCP server setup

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