# Rental Deal Alerts — New Listings & Price Drops, No Login (`flamboyant_liner/rental-deal-alerts`) Actor

Watch Zillow and Zumper rentals by city, ZIP, price and beds and get only NEW listings and PRICE DROPS since the last run, with previous price, days on market and specials. Schedule it every few hours. No login. MCP-ready. $10 per 1,000 alerts.

- **URL**: https://apify.com/flamboyant\_liner/rental-deal-alerts.md
- **Developed by:** [Khrystyna Skotte](https://apify.com/flamboyant_liner) (community)
- **Categories:** Real estate, E-commerce, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 alerts

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Rental Deal Alerts — new listings & price drops from Zillow and Zumper

Schedule this actor and get **only what changed**: rentals that appeared since the last run and match your
city, budget, bedrooms and home type, plus **price drops** on listings it has already seen. It remembers every
listing it reported, so a run every few hours emits just the delta (`changeType: new` or `price_drop`), posts a
summary to your webhook, and costs you only for actual alerts.

Built for renters hunting a specific budget, investors tracking rent softening in a submarket, and relocation or
property-management firms who need a feed rather than a spreadsheet to diff.

### How it works

1. Geocodes each location (city, ZIP or neighborhood) and searches **Zillow** and **Zumper** rentals inside it,
   newest first, with your rent, bedroom and home-type filters applied server-side.
2. Compares every listing against the monitor's saved state (`source:listingId → last price`).
3. Emits a record when the listing is unseen (`new`) or its rent is lower than last time (`price_drop`,
   with `previousPrice` and `priceChangePct`). `price_increase` alerts are off by default.
4. Saves the updated state, then POSTs a run summary to `webhookUrl` if set.

State lives in a named key-value store `rental-alerts-<hash of monitorId>` in your Apify account, capped at
50,000 listings (least recently seen are dropped). Delete the store to reset a monitor.

### Input

| Field | Default | Notes |
|---|---|---|
| `locations` | `["Austin, TX"]` | Cities, ZIPs or neighborhoods; each is searched on every source |
| `sources` | `["zillow","zumper"]` | Either or both |
| `minPrice` / `maxPrice` | `0` / `3000` | Monthly rent in USD; `0` = no bound |
| `minBeds` | `1` | `0` includes studios |
| `homeTypes` | `[]` | `house`, `apartment`, `townhouse`, `condo`, `multiFamily`; empty = all |
| `maxNewPerLocation` | `5` | Cap on `new` alerts per location per run; the rest stay unseen and come out next run |
| `alertOnPriceDrops` | `true` | Emit `price_drop` when a seen listing is now cheaper |
| `alertOnPriceIncreases` | `false` | Also emit `price_increase` |
| `firstRunMode` | `emitAll` | `emitAll` reports current matches on the first run; `baseline` records them silently |
| `webhookUrl` | `""` | Optional POST target for the run summary |
| `monitorId` | `default` | One state store per ID — run several watchlists side by side |
| `maxItems` | `10` | Total alerts per run (new + price changes) |
| `proxyConfiguration` | Apify residential, US | Required for Zillow on the Apify platform |

### Recommended setup for a live alert feed

1. Create a task with your filters and a meaningful `monitorId` (`austin-2br-under-2k`).
2. **First run: set `firstRunMode` to `baseline`.** This records everything currently listed (up to 500 per
   source per location), emits nothing, and stops your first alert from being a 500-row backlog.
3. Switch `firstRunMode` back to `emitAll` (it only matters while the state is empty), raise
   `maxNewPerLocation` and `maxItems` to what you want per run.
4. **Schedule the task every 2–6 hours.** Both sites post throughout the day; a 4-hour cadence catches new
   listings within the window that matters for a competitive rental market. Daily is fine for price-drop
   tracking only.
5. Point `webhookUrl` at Slack (incoming webhook), Zapier, Make, or your own endpoint.

The default settings (`{}`) run `emitAll` for Austin, TX so you see real output on the first try.

### Example: investor watching rent cuts on houses in two suburbs

```json
{
  "locations": ["Round Rock, TX", "Pflugerville, TX"],
  "sources": ["zillow", "zumper"],
  "minPrice": 1500,
  "maxPrice": 3500,
  "minBeds": 3,
  "homeTypes": ["house"],
  "maxNewPerLocation": 20,
  "alertOnPriceDrops": true,
  "firstRunMode": "baseline",
  "webhookUrl": "https://hooks.slack.com/services/XXX/YYY/ZZZ",
  "monitorId": "north-austin-sfh",
  "maxItems": 200
}
```

### Output

One record per alert:

```json
{
  "source": "zillow",
  "listingId": "29547445",
  "address": "12716 Margit Dr",
  "city": "Austin",
  "state": "TX",
  "zip": "78729",
  "latitude": 30.445044,
  "longitude": -97.7621,
  "price": 2100,
  "previousPrice": 2300,
  "priceChangePct": -8.7,
  "beds": 3,
  "baths": 3,
  "sqft": 1725,
  "homeType": "house",
  "daysOnMarket": 6,
  "listedAt": "2026-09-22",
  "specialOffer": null,
  "url": "https://www.zillow.com/homedetails/12716-Margit-Dr-Austin-TX-78729/29547445_zpid/",
  "imageUrl": "https://photos.zillowstatic.com/fp/29d480fff38872098ef462d569dd55e6-p_e.jpg",
  "location": "Austin, TX",
  "changeType": "price_drop",
  "firstSeenAt": "2026-09-22T14:00:03.118Z",
  "monitorId": "default"
}
```

`previousPrice` and `priceChangePct` are `null` on `new` records. `firstSeenAt` is when this monitor first
recorded the listing.

### Webhook payload

POSTed once per run as `application/json`, also saved as the `SUMMARY` record in the run's key-value store:

```json
{
  "monitorId": "north-austin-sfh",
  "runAt": "2026-09-29T10:00:03.118Z",
  "newCount": 4,
  "priceDropCount": 2,
  "priceIncreaseCount": 0,
  "scanned": 1000,
  "seenTotal": 1812,
  "baseline": false,
  "alerts": [ { "...first 50 records, same shape as the dataset..." } ]
}
```

### Source notes

- **Zillow**: price is the listed monthly rent; for buildings with several floorplans it is the cheapest unit.
  `specialOffer` carries Zillow's concession text ("1 month free") when the card shows one. Zillow needs the
  residential proxy on the platform.
- **Zumper**: price is the entry rent of the listing or building (`min_price`). Home-type filtering covers
  houses, apartments and townhouses; condo/multi-family selections fall back to all types on this source.
  `specialOffer` is not available from Zumper's search feed.
- Each run examines up to 500 newest listings per source per location when looking for price changes, so a
  price cut on a listing deeper than that in a very large market is caught once it re-sorts nearer the top or
  the filters are narrowed. A first `emitAll` run stops as soon as it has `maxNewPerLocation` new listings.
- Rent comparisons use the listing's headline price. A floorplan swap in a large building can register as a
  drop or increase; `alertOnPriceIncreases` stays off by default for that reason.

### Pricing

Pay per event: a small start fee plus a per-alert fee **only for records emitted**. A run that finds nothing
new costs just the start fee.

# Actor input Schema

## `locations` (type: `array`):

Cities, ZIP codes or neighborhoods to watch, e.g. "Austin, TX", "78704", "Capitol Hill, Seattle, WA". Each location is searched on every source.

## `sources` (type: `array`):

Rental sites to pull from.

## `minPrice` (type: `integer`):

Lowest rent to include, in USD per month. 0 = no minimum.

## `maxPrice` (type: `integer`):

Highest rent to include, in USD per month. 0 = no maximum.

## `minBeds` (type: `integer`):

Minimum number of bedrooms. 0 includes studios.

## `homeTypes` (type: `array`):

Property types to include. Empty = all. Zillow supports every option; Zumper can filter houses, apartments and townhouses.

## `maxNewPerLocation` (type: `integer`):

Cap on NEW listings reported per location per run. Listings beyond the cap stay unseen and are reported on the next run. Price-change alerts are not capped by this.

## `alertOnPriceDrops` (type: `boolean`):

Emit a price\_drop alert when a listing seen on an earlier run is now cheaper.

## `alertOnPriceIncreases` (type: `boolean`):

Also emit a price\_increase alert when a listing seen earlier got more expensive.

## `firstRunMode` (type: `string`):

What to do when the monitor has no saved state yet. emitAll: report the current matches as new (good for a first test). baseline: silently record every current match and emit nothing, so the next scheduled run reports only what changed since.

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

Optional. After each run a JSON summary {monitorId, runAt, newCount, priceDropCount, alerts\[first 50]} is POSTed here (Slack/Zapier/Make/your API).

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

Name of this watchlist. Each ID keeps its own seen-state in a key-value store named rental-alerts-<hash>, so you can run several profiles (e.g. "austin-2br", "denver-houses") side by side.

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

Stop after emitting this many alerts in total (new listings plus price changes).

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

Zillow blocks datacenter IPs. Residential proxy is required on the Apify platform and is the default.

## Actor input object example

```json
{
  "locations": [
    "Austin, TX"
  ],
  "sources": [
    "zillow",
    "zumper"
  ],
  "minPrice": 0,
  "maxPrice": 3000,
  "minBeds": 1,
  "homeTypes": [],
  "maxNewPerLocation": 5,
  "alertOnPriceDrops": true,
  "alertOnPriceIncreases": false,
  "firstRunMode": "emitAll",
  "webhookUrl": "",
  "monitorId": "default",
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `records` (type: `string`):

Dataset of new rentals and price changes found in this run (JSON).

# 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 = {
    "locations": [
        "Austin, TX"
    ],
    "sources": [
        "zillow",
        "zumper"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("flamboyant_liner/rental-deal-alerts").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 = {
    "locations": ["Austin, TX"],
    "sources": [
        "zillow",
        "zumper",
    ],
}

# Run the Actor and wait for it to finish
run = client.actor("flamboyant_liner/rental-deal-alerts").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 '{
  "locations": [
    "Austin, TX"
  ],
  "sources": [
    "zillow",
    "zumper"
  ]
}' |
apify call flamboyant_liner/rental-deal-alerts --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,flamboyant_liner/rental-deal-alerts"
        }
    }
}
```

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/dLVDj68Rpb5VnY23S/builds/qZvwZjbhfj0QxUuf2/openapi.json
