# Otodom Listing Monitor — New Rental & Sale Alerts (`arkadr/otodom-listing-monitor`) Actor

Monitors Otodom.pl search results and alerts you only about genuinely new listings via webhook, instead of dumping the same data every run.

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

## Pricing

from $1.50 / 1,000 listing returneds

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 a software tools running on the Apify platform, for all kinds of web data extraction and automation use cases.
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.

In JavaScript/TypeScript projects, use official [JavaScript/TypeScript client](https://docs.apify.com/api/client/js.md):

```bash
npm install apify-client
```

In Python projects, use official [Python client library](https://docs.apify.com/api/client/python.md):

```bash
pip install apify-client
```

In shell scripts, use [Apify CLI](https://docs.apify.com/cli/docs.md):

````bash
# MacOS / Linux
curl -fsSL https://apify.com/install-cli.sh | bash
# Windows
irm https://apify.com/install-cli.ps1 | iex
```bash

In AI frameworks, you might use the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp.md).

If your project is in a different language, use 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

**Get notified the moment a new listing appears on Otodom.pl** — instead of re-scraping
the same search results over and over, this Actor remembers what it already saw and
sends you only the genuinely new matches, straight to your own webhook, Google Sheet,
Slack channel, or CRM.

### What does Otodom Listing Monitor do?

Otodom Listing Monitor watches a saved search on [Otodom.pl](https://www.otodom.pl)
(Poland's largest real-estate portal, covering both rentals and sales) and reports
back only the listings that are **new since the previous run** — price, area, rooms,
floor, location, photos, and description for each one. Point it at any Otodom search
URL (copy it straight from your browser after setting your own city/price/room
filters), put it on an [Apify Schedule](https://docs.apify.com/platform/schedules) to
run every 15–60 minutes, and it becomes a real-time "new apartment" alert feed you can
wire into anything: a webhook, an n8n/Make/Zapier scenario, a Google Sheet via Apify's
built-in [dataset integrations](https://apify.com/integrations), or your own script.

### Why use Otodom Listing Monitor instead of a scraper?

Most Otodom scrapers (including others on Apify Store) dump the same batch of
listings every time you run them, leaving you to diff the results yourself. This
Actor does the diffing for you:

- **Apartment hunters** — get a push alert the second a matching flat goes live,
  instead of refreshing the site every hour or relying on Otodom's own email digest
  (which can't be piped into anything else).
- **Relocation agencies / property managers** — feed new listings straight into an
  internal dashboard, CRM, or Slack channel for a whole team, filtered by client
  criteria.
- **Market researchers** — track new-supply volume over time for a city or district
  without re-processing duplicate data on every run.

### How to use Otodom Listing Monitor

1. Go to [otodom.pl](https://www.otodom.pl), set your filters (city, district, price,
   rooms, rent or sale), and copy the resulting URL from your browser's address bar.
2. Paste that URL into the **Otodom search URL** input field below.
3. To get recurring "new listing" alerts instead of a one-time export, turn on
   **Monitor mode**, give it a **Monitor ID** (any short name for this search), and
   optionally set a **Webhook URL** to receive new listings as JSON as soon as they
   appear.
4. Attach an [Apify Schedule](https://docs.apify.com/platform/schedules) (e.g. every
   30 minutes) so it keeps checking automatically.
5. The first monitor run always establishes a baseline (no alerts yet) — every run
   after that reports only what's new.

### Input

| Field | Type | Description |
|---|---|---|
| `searchUrl` | string (required) | An Otodom search-results URL, e.g. `https://www.otodom.pl/pl/wyniki/wynajem/mieszkanie/mazowieckie/warszawa/warszawa/warszawa` |
| `maxListings` | integer | Cap on listings fetched per run (default 100) |
| `monitorMode` | boolean | Turn on recurring new-listing detection (default off) |
| `monitorId` | string | Required with Monitor mode — namespaces this search's "seen" state |
| `webhookUrl` | string | Optional — POST target for new-listing alerts (JSON: `{ monitorId, newListings }`) |

### Output

One row per listing in the dataset (downloadable as JSON, CSV, Excel, etc.):

```json
{
  "id": "66583347",
  "url": "https://www.otodom.pl/pl/oferta/atrakcyjne-3-pokoje-po-remoncie-na-mokotowie-ID4wnmX",
  "title": "Atrakcyjne. 3 pokoje. Po remoncie. Na Mokotowie!",
  "price": 4500,
  "currency": "PLN",
  "pricePerM2": 84.76,
  "area": 53.09,
  "rooms": 3,
  "floor": "SECOND",
  "propertyType": "FLAT",
  "transactionType": "RENT",
  "city": "Warszawa",
  "district": "Mokotów",
  "street": "ul. Chełmska",
  "photos": ["https://..."],
  "description": "Wynajmę bezpośrednio 3 pokoje na Mokotowie...",
  "publishedAt": "2025-03-12T11:00:32Z",
  "scrapedAt": "2026-07-05T12:00:00.000Z",
  "isNew": true
}
````

Note: to minimize personal-data handling, this Actor deliberately does **not**
extract the seller/agent's name, phone, or email — only the property listing itself.

### Data fields

| Field | Description |
|---|---|
| `id`, `url` | Otodom listing ID and full link |
| `title`, `description` | Listing headline and short excerpt |
| `price`, `currency`, `pricePerM2` | Total price and price per m² |
| `area`, `rooms`, `floor` | Size, room count, floor |
| `propertyType`, `transactionType` | e.g. FLAT/HOUSE, RENT/SALE |
| `city`, `district`, `street` | Location |
| `photos` | Array of image URLs |
| `publishedAt`, `scrapedAt` | Original listing date and when this Actor saw it |
| `isNew` | true only in Monitor mode, on the 2nd+ run, for listings not seen before |

### Pricing / cost

This Actor uses Apify's **Pay-Per-Event** pricing: a small per-run start fee, a small
fee per listing returned, and a fee per new-listing alert successfully delivered to
your webhook (alerts only fire in Monitor mode, and never on the first baseline run).
See the Pricing tab for exact current rates — it costs a fraction of a cent to check a
typical search for new listings.

### Tips

- Keep `maxListings` reasonable (50–200) for monitor runs on a specific
  city/district — you only need to cover one page or two of "sorted by newest" to
  catch new listings between schedule runs.
- Sort your Otodom search by "Newest first" before copying the URL — it makes new
  listings show up on page 1 immediately.
- Use one `monitorId` per distinct saved search if you're tracking several
  cities/filters from the same Actor.

### FAQ

#### How do I get notified about new listings on Otodom automatically?

Turn on **Monitor mode**, set a **Webhook URL**, and attach an Apify Schedule. Every
run after the first reports only listings that weren't there last time, and POSTs
them to your webhook.

#### Can I export new listings straight to Google Sheets?

Yes — use Apify's built-in dataset **Integrations** (available on every Actor run) to
push results to Google Sheets, Airtable, Slack, or email without any extra code. The
`webhookUrl` input is for routing new-listing alerts to your own endpoint or
automation tool (n8n, Make, Zapier) instead.

#### Does this work for both rentals and sales?

Yes — just copy the search URL for whichever Otodom section (`wynajem` for rent,
`sprzedaz` for sale) and filters you want.

#### Is this legal?

The Actor only reads publicly listed search-results pages, the same way a browser
does, and does not access any authenticated or private data, nor the seller's contact
details. It respects Otodom's robots.txt.

#### Something looks broken / a field is missing

Otodom occasionally changes its page structure. Please open an issue on this Actor's
Issues tab with the search URL you used — reports like this are how this Actor stays
working, unlike a lot of abandoned one-off scrapers.

# Actor input Schema

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

Copy the URL from your browser after setting your filters (city, price, rooms, etc.) on otodom.pl. Must look like https://www.otodom.pl/pl/wyniki/wynajem/mieszkanie/...

## `maxListings` (type: `integer`):

Stop fetching once this many listings have been collected.

## `monitorMode` (type: `boolean`):

If enabled, the Actor remembers listings it has already seen (keyed by "Monitor ID") and marks only genuinely new listings as isNew on the 2nd and later runs. Combine with an Apify Schedule to get recurring alerts. The first run always establishes a baseline with no alerts.

## `monitorId` (type: `string`):

Required when Monitor mode is on. A short name for this specific search (e.g. "warsaw-2br-rental") so multiple monitors don't mix up their state.

## `webhookUrl` (type: `string`):

Optional. Only used in Monitor mode. When new listings are found, the Actor POSTs a JSON payload ({ monitorId, newListings }) to this URL — e.g. an n8n/Make/Zapier webhook, or your own endpoint. For Google Sheets/Airtable/Slack delivery instead, use Apify's built-in dataset Integrations on this Actor's run.

## Actor input object example

```json
{
  "searchUrl": "https://www.otodom.pl/pl/wyniki/wynajem/mieszkanie/mazowieckie/warszawa/warszawa/warszawa",
  "maxListings": 100,
  "monitorMode": false
}
```

# 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 = {
    "searchUrl": "https://www.otodom.pl/pl/wyniki/wynajem/mieszkanie/mazowieckie/warszawa/warszawa/warszawa"
};

// Run the Actor and wait for it to finish
const run = await client.actor("arkadr/otodom-listing-monitor").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/wynajem/mieszkanie/mazowieckie/warszawa/warszawa/warszawa" }

# Run the Actor and wait for it to finish
run = client.actor("arkadr/otodom-listing-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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/wynajem/mieszkanie/mazowieckie/warszawa/warszawa/warszawa"
}' |
apify call arkadr/otodom-listing-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=arkadr/otodom-listing-monitor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

```json
{
    "openapi": "3.0.1",
    "info": {
        "title": "Otodom Listing Monitor — New Rental & Sale Alerts",
        "description": "Monitors Otodom.pl search results and alerts you only about genuinely new listings via webhook, instead of dumping the same data every run.",
        "version": "0.1",
        "x-build-id": "6fwfghQLfcf6I8CJ6"
    },
    "servers": [
        {
            "url": "https://api.apify.com/v2"
        }
    ],
    "paths": {
        "/acts/arkadr~otodom-listing-monitor/run-sync-get-dataset-items": {
            "post": {
                "operationId": "run-sync-get-dataset-items-arkadr-otodom-listing-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for its completion, and returns Actor's dataset items in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        },
        "/acts/arkadr~otodom-listing-monitor/runs": {
            "post": {
                "operationId": "runs-sync-arkadr-otodom-listing-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor and returns information about the initiated run in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK",
                        "content": {
                            "application/json": {
                                "schema": {
                                    "$ref": "#/components/schemas/runsResponseSchema"
                                }
                            }
                        }
                    }
                }
            }
        },
        "/acts/arkadr~otodom-listing-monitor/run-sync": {
            "post": {
                "operationId": "run-sync-arkadr-otodom-listing-monitor",
                "x-openai-isConsequential": false,
                "summary": "Executes an Actor, waits for completion, and returns the OUTPUT from Key-value store in response.",
                "tags": [
                    "Run Actor"
                ],
                "requestBody": {
                    "required": true,
                    "content": {
                        "application/json": {
                            "schema": {
                                "$ref": "#/components/schemas/inputSchema"
                            }
                        }
                    }
                },
                "parameters": [
                    {
                        "name": "token",
                        "in": "query",
                        "required": true,
                        "schema": {
                            "type": "string"
                        },
                        "description": "Enter your Apify token here"
                    }
                ],
                "responses": {
                    "200": {
                        "description": "OK"
                    }
                }
            }
        }
    },
    "components": {
        "schemas": {
            "inputSchema": {
                "type": "object",
                "required": [
                    "searchUrl"
                ],
                "properties": {
                    "searchUrl": {
                        "title": "Otodom search URL",
                        "type": "string",
                        "description": "Copy the URL from your browser after setting your filters (city, price, rooms, etc.) on otodom.pl. Must look like https://www.otodom.pl/pl/wyniki/wynajem/mieszkanie/..."
                    },
                    "maxListings": {
                        "title": "Max listings per run",
                        "minimum": 1,
                        "maximum": 2000,
                        "type": "integer",
                        "description": "Stop fetching once this many listings have been collected.",
                        "default": 100
                    },
                    "monitorMode": {
                        "title": "Monitor mode (recurring alerts)",
                        "type": "boolean",
                        "description": "If enabled, the Actor remembers listings it has already seen (keyed by \"Monitor ID\") and marks only genuinely new listings as isNew on the 2nd and later runs. Combine with an Apify Schedule to get recurring alerts. The first run always establishes a baseline with no alerts.",
                        "default": false
                    },
                    "monitorId": {
                        "title": "Monitor ID",
                        "type": "string",
                        "description": "Required when Monitor mode is on. A short name for this specific search (e.g. \"warsaw-2br-rental\") so multiple monitors don't mix up their state."
                    },
                    "webhookUrl": {
                        "title": "Webhook URL for new-listing alerts",
                        "type": "string",
                        "description": "Optional. Only used in Monitor mode. When new listings are found, the Actor POSTs a JSON payload ({ monitorId, newListings }) to this URL — e.g. an n8n/Make/Zapier webhook, or your own endpoint. For Google Sheets/Airtable/Slack delivery instead, use Apify's built-in dataset Integrations on this Actor's run."
                    }
                }
            },
            "runsResponseSchema": {
                "type": "object",
                "properties": {
                    "data": {
                        "type": "object",
                        "properties": {
                            "id": {
                                "type": "string"
                            },
                            "actId": {
                                "type": "string"
                            },
                            "userId": {
                                "type": "string"
                            },
                            "startedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "finishedAt": {
                                "type": "string",
                                "format": "date-time",
                                "example": "2025-01-08T00:00:00.000Z"
                            },
                            "status": {
                                "type": "string",
                                "example": "READY"
                            },
                            "meta": {
                                "type": "object",
                                "properties": {
                                    "origin": {
                                        "type": "string",
                                        "example": "API"
                                    },
                                    "userAgent": {
                                        "type": "string"
                                    }
                                }
                            },
                            "stats": {
                                "type": "object",
                                "properties": {
                                    "inputBodyLen": {
                                        "type": "integer",
                                        "example": 2000
                                    },
                                    "rebootCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "restartCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "resurrectCount": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "computeUnits": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "options": {
                                "type": "object",
                                "properties": {
                                    "build": {
                                        "type": "string",
                                        "example": "latest"
                                    },
                                    "timeoutSecs": {
                                        "type": "integer",
                                        "example": 300
                                    },
                                    "memoryMbytes": {
                                        "type": "integer",
                                        "example": 1024
                                    },
                                    "diskMbytes": {
                                        "type": "integer",
                                        "example": 2048
                                    }
                                }
                            },
                            "buildId": {
                                "type": "string"
                            },
                            "defaultKeyValueStoreId": {
                                "type": "string"
                            },
                            "defaultDatasetId": {
                                "type": "string"
                            },
                            "defaultRequestQueueId": {
                                "type": "string"
                            },
                            "buildNumber": {
                                "type": "string",
                                "example": "1.0.0"
                            },
                            "containerUrl": {
                                "type": "string"
                            },
                            "usage": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "integer",
                                        "example": 1
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            },
                            "usageTotalUsd": {
                                "type": "number",
                                "example": 0.00005
                            },
                            "usageUsd": {
                                "type": "object",
                                "properties": {
                                    "ACTOR_COMPUTE_UNITS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATASET_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "KEY_VALUE_STORE_WRITES": {
                                        "type": "number",
                                        "example": 0.00005
                                    },
                                    "KEY_VALUE_STORE_LISTS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_READS": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "REQUEST_QUEUE_WRITES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_INTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "DATA_TRANSFER_EXTERNAL_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_RESIDENTIAL_TRANSFER_GBYTES": {
                                        "type": "integer",
                                        "example": 0
                                    },
                                    "PROXY_SERPS": {
                                        "type": "integer",
                                        "example": 0
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}
```
