# Re New Listing Alert — New Property Watch (`zinin/re-new-listing-alert`) Actor

Watch a saved search on ten supported real-estate portals through built-in adapters and get only listings that are new since the last check, with no nested Actor run or second Actor charge.

- **URL**: https://apify.com/zinin/re-new-listing-alert.md
- **Developed by:** [Tim Zinin](https://apify.com/zinin) (community)
- **Categories:** Real estate, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.50 / 1,000 change founds

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/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

## Re New Listing Alert — New Property Watch

Watch a saved real-estate search on Krisha.kz, Otodom, Rightmove, SS.ge and more, and
get only listings newly observed by the watch, not the same ads you already processed.
For Krisha, the product monitors a declared newest-first rolling window and retains a
durable union of seen listing IDs; it does not pretend a 10-row window is the entire
market. Ten portal adapters run directly inside this Actor:
there is no child Actor run, buyer token hand-off, or second Actor charge.

### What you get

- A named "watch" (one portal + that portal's own search filter) that remembers what
  it has already shown you.
- Every scheduled run reports only identities the watch has not previously delivered
  or included in its first baseline — title, price, currency, location and URL.
- Choose from 10 live portals: Krisha.kz (Kazakhstan), Otodom (Poland), Imovirtual
  (Portugal), Storia (Romania), Willhaben (Austria), Rightmove (UK), SS.ge (Georgia),
  PropertyFinder (UAE/Gulf), Realitica (Adriatic) and Emlakjet (Turkey).
- Run several independent watches from one Actor (e.g. one on Krisha.kz for Almaty
  apartments, one on Rightmove for London flats) — each has its own memory.
- The very first run for a new watch tells you honestly that it's establishing a
  baseline, not hiding a "no new listings" run as if it found something.
- Runs on Apify: schedule it daily, monitor it, call it from the API, export to
  JSON/CSV/Excel or push straight into your own pipeline.

### How to run it

1. Click **Try for free** — no card needed on the free plan.
2. Pick a **Portal to watch**, then paste that portal's own filter into **Portal
   filter (JSON)** — e.g. `{"queries":["sale:apartment:almaty"]}` for Krisha.kz or
   `{"location_identifier":"REGION^87490","deal_type":"sale"}` for Rightmove. See the
   Input table below for every portal's fields.
3. Hit **Start**. The first run creates the baseline; schedule it to run again (daily
   or weekly) to get a stream of only the NEW listings each time.

### Pricing

Pay-per-event. The Actor accepts only Apify's exact six-tier contract: FREE
`$0.005/$0.010`, BRONZE `$0.00475/$0.0095`, SILVER `$0.0045/$0.009`, GOLD
`$0.00425/$0.0085`, PLATINUM `$0.0041/$0.0082`, or DIAMOND
`$0.004/$0.008` per run start/result. A paid result is a NEW listing or a
baseline snapshot from a source-confirmed complete scan. Krisha's first N rows are
billable only when its explicit `add_date-desc` window is parsed without a dropped
card; this is reported as `rolling-ranked-window`. Other portals still require
source-confirmed exhaustion. Partial snapshots, quiet checks, and error rows are free
and never change the baseline. A malformed pricing contract, exhausted budget, or
unconfirmed charge fails closed and never advances the baseline.
Krisha always keeps a durable union of previously delivered identities, even when a
small current result set is source-exhausted before reaching the window limit, so a
displaced listing cannot be forgotten and charged again later.

### Input

| Field | Required | What it does |
|---|---|---|
| `portal` | yes | Which portal to watch: `krisha-kz`, `otodom-warsaw`, `imovirtual-lisbon`, `storia-bucharest`, `willhaben-vienna`, `rightmove-london`, `ss-ge-tbilisi`, `propertyfinder-gulf`, `realitica-adriatic`, `emlakjet-istanbul`. |
| `filter` | yes | Search fields understood by this Actor's in-process adapter for the selected portal. Krisha always adds its official `sort_by=add_date-desc` ordering and treats exactly `max_items` clean rows as the declared rolling window. Its query list is all-or-nothing: malformed entries or more than 30 distinct searches stop free rather than silently narrowing the watch. See "Portal filter fields" below. |
| `watch_name` | no | Name for this watch, so you can run several independent watches. Defaults to a single watch if left empty. |
| `max_items` | no | Max NEW-listing rows delivered (and charged) per run, even if more were found (1-200, default 20). |

Migration: older API clients and saved Tasks may still send `baseline_key`. Runtime accepts that legacy alias only when `watch_name` is absent, preserving the same stored baseline. New integrations should use `watch_name`; an explicitly empty `watch_name` selects the documented fallback and never revives a legacy value.

#### Portal filter fields

| Portal | Required filter fields | Example |
|---|---|---|
| `krisha-kz` | `queries` (`"deal:type:city"`) | `{"queries":["sale:apartment:almaty"]}` |
| `otodom-warsaw` | none (all optional: `deal_type`, `property_type`, `city`) | `{"deal_type":"sprzedaz","city":"mazowieckie/warszawa/warszawa/warszawa"}` |
| `imovirtual-lisbon` | none | `{"deal_type":"comprar","city":"lisboa/lisboa"}` |
| `storia-bucharest` | none | `{"deal_type":"vanzare","city":"bucuresti"}` |
| `willhaben-vienna` | `deal_type`, `city` | `{"deal_type":"mietwohnungen","city":"wien"}` |
| `rightmove-london` | `location_identifier`, `deal_type` | `{"location_identifier":"REGION^87490","deal_type":"sale"}` |
| `ss-ge-tbilisi` | none (`city_id` defaults to 95 = Tbilisi) | `{"city_id":95,"deal_type":"sale"}` |
| `propertyfinder-gulf` | none | `{"deal_type":"sell","emirate":"dubai"}` |
| `realitica-adriatic` | `deal_type`, `property_type`, `region` | `{"deal_type":"prodaja","property_type":"stanova","region":"Crna-Gora"}` |
| `emlakjet-istanbul` | `deal_type`, `property_type` | `{"deal_type":"satilik","property_type":"daire","city":"istanbul"}` |

Any `max_items`/`max_pages` you set inside `filter` are capped at 10/2 regardless of the
portal's own limits, to keep each watch check fast and cheap. For Krisha, use
`max_items:10`: successfully parsing those ten source-ordered rows proves the rolling
window, not global source exhaustion. Seen IDs are retained across later windows, so a
listing displaced and then returned is not charged twice.

```json
{
    "portal": "krisha-kz",
    "filter": { "queries": ["sale:apartment:almaty"], "max_items": 3, "max_pages": 1 },
    "watch_name": "almaty-3br"
}
```

### Output

Representative baseline-created row from a proven bounded rolling window:

```json
{
    "baselineKey": "selftest-live-run",
    "portal": "krisha-kz",
    "found": true,
    "isNew": false,
    "baselineCreated": true,
    "url": null,
    "title": null,
    "price": null,
    "currency": null,
    "dealType": null,
    "propertyType": null,
    "location": null,
    "postedDate": null,
    "currentListingsCount": 10,
    "newListingsCount": null,
    "sourcePartial": false,
    "partialReason": null,
    "snapshotMode": "rolling-ranked-window",
    "observedWindowSize": 10,
    "error": "",
    "summary": "First check for \"selftest-live-run\" (krisha-kz) — baseline created with 10 currently observed listing(s). Future runs report only previously unseen identities entering the rolling window.",
    "checkedAt": "2026-07-30T10:19:12.469Z"
}
```

Representative new-listing row after a later proven rolling window:

```json
{
    "baselineKey": "selftest-live-run",
    "portal": "krisha-kz",
    "found": true,
    "isNew": true,
    "baselineCreated": false,
    "url": "https://krisha.kz/a/show/1010898753",
    "title": "3-комнатная квартира · 92 м² · 9/12 этаж",
    "price": 72000000,
    "currency": "KZT",
    "dealType": "sale",
    "propertyType": "apartment",
    "location": "Алмалинский р-н, Макатаева 129/1 — Байтурсынова",
    "postedDate": null,
    "currentListingsCount": null,
    "newListingsCount": 3,
    "sourcePartial": false,
    "partialReason": null,
    "snapshotMode": "rolling-ranked-window",
    "observedWindowSize": 10,
    "error": "",
    "summary": "New listing for \"selftest-live-run\" (krisha-kz): 3-комнатная квартира · 92 м² · 9/12 этаж — 72000000 KZT, Алмалинский р-н, Макатаева 129/1 — Байтурсынова.",
    "checkedAt": "2026-07-30T10:19:39.951Z"
}
```

| Field | Meaning |
|---|---|
| `baselineKey` | Which watch this row belongs to. |
| `portal` | Which portal this watch scans with its built-in adapter. |
| `found` | `true` for a real result row (new listing or baseline-created); `false` for a notice/error row. |
| `isNew` | `true` only for an actual new-listing row. |
| `baselineCreated` | `true` only on the first-ever run for this watch. |
| `url`, `title`, `price`, `currency`, `dealType`, `propertyType`, `location`, `postedDate` | The listing's own fields, straight from the portal. |
| `currentListingsCount` | Only set on the baseline-created row: how many clean identities were observed in that snapshot/window. |
| `newListingsCount` | Total previously unseen listings detected in this snapshot/window (may exceed the rows delivered if capped by `max_items` or remaining budget). |
| `sourcePartial` / `partialReason` | `true` on a free notice when the portal stopped before confirming a complete snapshot. Such a snapshot is never billed and never creates or advances a baseline. |
| `snapshotMode` | `rolling-ranked-window` for a proven bounded Krisha window, `complete-result-set` after source-confirmed exhaustion, otherwise `null` on unproven/error evidence. |
| `observedWindowSize` | Number of clean listing identities in the current observation window. |
| `error` | Empty string when the check completed cleanly (including "nothing new"); non-empty only on a real problem. |
| `summary` | Human-readable one-liner. |

### Other tools we built

#### Related tools

Related tools for adjacent workflows in real estate listings and monitoring.

| Actor | What it does |
|---|---|
| [Krisha.kz Kazakhstan Real Estate Listings](https://apify.com/zinin/krisha-kz) | Pair it in the real estate listings and monitoring workflow: Pull live apartment and house listings straight from Krisha.kz — Kazakhstan's biggest real-estate... |
| [Emlakjet Istanbul Real Estate Listings](https://apify.com/zinin/emlakjet-istanbul) | Pair it in the real estate listings and monitoring workflow: Pull live apartment/housing listings straight from Emlakjet.com for Istanbul — one of Turkey's biggest... |
| [Otodom Poland Real Estate Listings](https://apify.com/zinin/otodom-warsaw) | Pair it in the real estate listings and monitoring workflow: Pull live apartment and house listings straight from Otodom.pl — Poland's biggest real-estate classifieds... |
| [Realitica.com Adriatic Real Estate Listings](https://apify.com/zinin/realitica-adriatic) | Pair it in the real estate listings and monitoring workflow: Pull live apartment and house listings straight from Realitica.com — a real-estate classifieds portal... |
| [SS.ge Georgia Real Estate Listings](https://apify.com/zinin/ss-ge-tbilisi) | Pair it in the real estate listings and monitoring workflow: Pull live real-estate listings straight from SS.ge — Georgia's biggest real-estate classifieds portal — by... |

### FAQ / Limitations

**Can I watch several portals at once?** Not from a single watch — each `watch_name`
watches one portal. Run several watches (different `watch_name` values) from the same
Actor, one per portal, to cover more than one market.

**What happens if I change my `filter` for an existing `watch_name`?** The watch keeps
comparing against whatever it last saw, so changing the filter can produce a burst of
"new" listings that simply weren't checked for under the old filter. Use a new
`watch_name` for an intentionally different watch.

**Does a Krisha run scan every matching listing?** No. It requests Krisha's
`add_date-desc` ordering and monitors the first `filter.max_items` clean rows (maximum
10\). This bounded rolling window is explicit in every output row. It is useful for
frequent alerts, but a listing that enters and leaves the window between scheduled runs
can be missed; run more frequently for busy markets. The durable seen set prevents a
previously observed ID from being charged again if it returns to the window.

If every configured Krisha query fails, the run returns `source_error` and does not
create or update a baseline. A present but malformed stored baseline is also a fatal
integrity error; it is never treated as a first run.

**What this is NOT.** This is not a valuation tool and does not verify a listing's
legitimacy, ownership, or price accuracy. It surfaces public listing data only.

Found a bug or need a custom watch (e.g. tracking price drops, not just new listings)?
Issues on the Actor's page.

# Actor input Schema

## `portal` (type: `string`):

Which real-estate portal this Actor scans with its built-in adapter. Each portal uses different filter fields; see the README Input section.

## `filter` (type: `object`):

Search fields for the selected in-process portal adapter. Krisha.kz uses an explicit newest-first rolling window, for example {"queries":\["sale:apartment:almaty"],"max\_items":10}; Rightmove uses {"location\_identifier":"REGION^87490","deal\_type":"sale"}. See the README table. Adapter max\_items/max\_pages are capped at 10/2.

## `watch_name` (type: `string`):

A name for THIS watch, so you can run several independent watches (different portals and/or filters) from one Actor without one overwriting another's memory of what's already been seen. Each name is scoped to YOUR OWN Apify account. The prefilled value is only there so this Actor's own daily test run has a stable, obviously-a-test name; replace it with your own watch name.

## `max_items` (type: `integer`):

Caps how many NEW-listing rows a single run will deliver and charge for, even if more were found.

## Actor input object example

```json
{
  "portal": "krisha-kz",
  "filter": {
    "queries": [
      "sale:apartment:almaty"
    ],
    "max_items": 3,
    "max_pages": 1
  },
  "watch_name": "apify-daily-test",
  "max_items": 20
}
```

# Actor output Schema

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

API URL for the default dataset items produced by this run.

# 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 = {
    "portal": "krisha-kz",
    "filter": {
        "queries": [
            "sale:apartment:almaty"
        ],
        "max_items": 3,
        "max_pages": 1
    },
    "watch_name": "apify-daily-test"
};

// Run the Actor and wait for it to finish
const run = await client.actor("zinin/re-new-listing-alert").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 = {
    "portal": "krisha-kz",
    "filter": {
        "queries": ["sale:apartment:almaty"],
        "max_items": 3,
        "max_pages": 1,
    },
    "watch_name": "apify-daily-test",
}

# Run the Actor and wait for it to finish
run = client.actor("zinin/re-new-listing-alert").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 '{
  "portal": "krisha-kz",
  "filter": {
    "queries": [
      "sale:apartment:almaty"
    ],
    "max_items": 3,
    "max_pages": 1
  },
  "watch_name": "apify-daily-test"
}' |
apify call zinin/re-new-listing-alert --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,zinin/re-new-listing-alert"
        }
    }
}

```

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/SweKSwXU6V0sdkz1e/builds/0dxwpu6Gzsqxs8zpt/openapi.json
