# Redfin Scraper — US Homes for Sale, Price Cuts & New Listings (`northbell/redfin-homes-scraper`) Actor

Redfin homes for sale in any US city, ZIP or neighborhood, one row per listing: price, beds, baths, size, lot, year built, HOA, days on market, map position. Run it again or on a schedule for price cuts, new and removed listings since the last run. Price, bedroom and type filters. No login.

- **URL**: https://apify.com/northbell/redfin-homes-scraper.md
- **Developed by:** [Northbell](https://apify.com/northbell) (community)
- **Categories:** Real estate, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 homes

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?

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

## Redfin Scraper — US Homes for Sale, Price Cuts & New Listings

Give it US places — a city (`Austin, TX`), a ZIP code, a borough or neighborhood, or a Redfin page URL — and get one clean row per home for sale: **price, beds, baths, size, price per sq ft, lot, year built, HOA, days on market, status, map position and the Redfin link**. **$1.00 per 1,000 homes**, no login, no API key.

Run it again — or put it on a daily schedule — and every row also tells you **what changed since the last run**: which homes are **new**, which had a **price cut** (amount and percent), and a free row for each listing that **disappeared**. Redfin only shows you today's list; this keeps yesterday's. Every place also gets a free summary row with the counts and the median price.

### What you get

| Field | What it is |
|---|---|
| `type` | `home` (charged), `summary` (one per place, free), `removed` (free), or `error` (free) |
| `location`, `place` | what you typed, and the place that was searched (for example `ZIP 78701`, `Austin, TX`) |
| `propertyId`, `listingId`, `url` | the home and its `redfin.com` link |
| `address`, `city`, `state`, `zip`, `neighborhood` | where it is. `neighborhood` is the neighborhood or subdivision name Redfin prints. `address` is `null` when the seller hides it |
| `price`, `previousPrice`, `priceChange`, `priceCutPct` | list price, and the change since your previous run. `priceChange` is negative for a cut, `priceCutPct` is the cut in percent (only filled for cuts) |
| `isNew`, `firstSeenDate` | `true` when no earlier run of this search (in the last 90 days) had seen the home, `false` for a home you have seen before. `null` on the first run. `firstSeenDate` is the first day any run of this search saw it |
| `beds`, `baths`, `sqFt`, `pricePerSqFt`, `lotSize`, `yearBuilt` | as Redfin shows them (`lotSize` in square feet). `null` when Redfin has no value, and beds/baths are `null` for land |
| `hoa` | monthly HOA dues in dollars, when the home has them |
| `daysOnMarket`, `status` | days on the market, and Redfin's status: `Active`, `Coming Soon`, `Price Change`… (`daysOnMarket` is `null` for homes not on the market yet) |
| `propertyType` | `house`, `condo` (co-ops included), `townhouse`, `multi-family`, `land`, `mobile` or `other` |
| `latitude`, `longitude` | map position |
| `mlsId` | the MLS number (or Redfin's id for early-access listings) |
| `newConstruction`, `listedByRedfin` | `true` for new-construction listings; `true` when Redfin itself is the listing brokerage |
| `nextOpenHouseStart`, `nextOpenHouseEnd` | the next open house, in UTC, when one is scheduled |
| `observedAt` | when this row was read |

The `summary` row has `homesRead`, `homesReturned`, `newSinceLastRun`, `removedSinceLastRun`, `priceCuts`, `medianPrice`, `medianPricePerSqFt`, `complete`, `homesScannedInArea`, `comparedWithRunAt` and a `note`. The medians are taken over the `homesRead` homes, so when `complete` is `false` (a home limit cut the list) they describe the newest homes, not the whole area. The `removed` row has `propertyId`, `url`, `address`, `lastPrice` and `lastSeenAt`.

### Use it for

- **Price-cut alerts** — schedule it daily for your target ZIP codes and filter `priceCutPct` above 0
- **New listing monitoring** — `isNew` is `true` only for homes no earlier run of that search had seen; with *Only new listings and price changes* on, you pay only for those
- **Investors and agents** — compare median price and price per sq ft across ZIPs, spot listings that left the market, and export to Sheets or your BI tool
- **Lead lists and market reports** — a clean, deduplicated list of what is for sale, by area and price band

### Input

```json
{
  "locations": ["Austin, TX", "78701", "Brooklyn, NY", "https://www.redfin.com/city/30818/TX/Austin"],
  "maxHomesPerLocation": 200,
  "minPrice": 300000,
  "maxPrice": 800000,
  "minBeds": 3,
  "propertyTypes": ["house", "townhouse"],
  "onlyChanges": false
}
```

Places can be a city (`Austin, TX`), a borough or neighborhood (`Brooklyn, NY`, `Hyde Park, Austin, TX`), a ZIP code, or a Redfin city / neighborhood / county / ZIP page URL. A city, neighborhood or county URL returns exactly the homes Redfin lists for that place and is the way to read a whole county. Only the place in the URL is used: filters, sorting and sold or rental pages in the URL are ignored (set the price, bedroom and type inputs here instead). Counties and states cannot be typed by name.

The previous run is remembered per search (the place plus your price, bedroom and type filters) in a named key-value store in your Apify account, so the second run of the same search already shows changes. Schedule it (Apify → Schedules) for a daily history. Changing the max-homes limit or the changes-only switch keeps the history; changing a filter starts a new one. Set `includeRemoved` to `false` if you do not want the free removed-listing rows.

### Pricing

**$1.00 per 1,000 homes**, plus $0.01 per run. Summary rows, removed-listing rows and error rows are free. Put all your places in one run and you pay the run fee once. The $0.01 run-start fee is the one charge every run pays, even one that returns nothing.

### Notes

- Public data only: what anyone sees on redfin.com without signing in. Agent names, phone numbers and listing descriptions are not returned.
- **Newest first.** Homes come newest-on-Redfin first, and the read stops as soon as it has *Max homes per location* matching homes (up to 2,000). A big city lists thousands of homes, so raise the limit or split it into ZIP codes to read everything. Areas with more than about 25,000 listings are read only partly; `summary.note` says so.
- **Price, bedroom and type filters are applied after reading** the area's list, because Redfin's list does not filter by itself. A tight filter in a big city reads many listings first, but you are charged only for the rows returned.
- **Only homes for sale** (active and coming soon). A home that goes under contract or sells leaves the list, so it shows up as removed.
- **Removed listings** are counted only when every matching home was read (`summary.complete` is `true`), so a limit that cuts the list short gives `removedSinceLastRun: null`. A removed row means the home left your search: under contract, sold, withdrawn, or no longer matching your filters. At most 500 removed rows are written per place; the count in the summary is complete. A run where part of the list could not be read is also `complete: false`.
- When your previous run did not read every home, `isNew` is not set for homes that were already listed before that run. First run of a search: all comparison fields are `null`. A home that left and comes back within 90 days is not new again (it keeps its `firstSeenDate` and shows the price change).
- **Where a typed place comes from.** Redfin has no public place search, so the Actor first finds the outline of the place, then reads Redfin's lists for points inside it:
  - **ZIP codes** (`78701`): the US Census Bureau's ZIP Code Tabulation Area outline (TIGERweb).
  - **`City, ST`** (`Austin, TX`, `Cambridge, MA`, `Spring, TX`, `Brooklyn, NY`): the Census Bureau's outline of that city, town, village, township, borough or census-designated place. Merged city-county governments are found under their usual name (`Louisville, KY`, `Nashville, TN`, `Indianapolis, IN`). The state can be written `TX`, `Texas`, or left glued on (`Austin TX`); a name without a state (`Seattle`) is also answered by the Census Bureau when only one state has a place with that name.
  - **Neighborhoods and anything the Census Bureau does not list as a place** (`Hyde Park, Austin, TX`, `Capitol Hill, Seattle, WA`): OpenStreetMap's Nominatim search, asked at most once per second with an identifying user agent, and at most 50 such lookups per run. A name that exists in several states and has no state (`Springfield`) goes there too and returns the best-known one; the `place` field shows which, so add the state when you want a specific one.
  - **Redfin page URLs** need no lookup at all.
  - If the Census Bureau service does not answer, a typed place falls back to OpenStreetMap (a ZIP code cannot), and that fallback answer is remembered for one day only, so the next run asks the Census Bureau again. Every other lookup is remembered in your store for 180 days, so a schedule does not repeat it.
  - Data credit: this product uses the US Census Bureau's TIGERweb boundary services but is not endorsed or certified by the Census Bureau. Place outlines are simplified. It also uses OpenStreetMap data (© OpenStreetMap contributors, ODbL).
- **Reading a place.** Redfin's lists overlap near city borders, so the Actor looks up several points inside the place and merges the lists they return; a ZIP that crosses city lines is read the same way. For unincorporated communities (census-designated places such as `Spring, TX`) the Census outline is only a statistical area, narrower than the community Redfin lists, so the points are spread over the box around it and homes are kept when they sit inside the outline or when Redfin names the same city. A typed city takes 5 to 20 seconds. A city that Redfin splits into many overlapping areas (for example Cambridge, MA) is probed at up to about 140 points and takes one to four minutes (a community next to a big metro such as `The Woodlands, TX` reads several large lists), as does a ZIP code inside a very large city (for example Manhattan, whose whole list of about 19,500 homes has to be read). Homes along such borders can still be missed: for an exact list of a city, neighborhood or county, paste its Redfin page URL. If a name is ambiguous, add the state (`Paris, TX`). Boundaries are simplified, so a home within a few hundred meters of a border can land on the wrong side.
- Some fields are filled only sometimes: `hoa` (homes with dues), `lotSize` (not for most condos), `sqFt` and `pricePerSqFt` (not for land or when the seller does not give a size), `nextOpenHouse*` (only when scheduled), `price` (a few sellers hide it; such homes drop out when you set a price limit), `address` (hidden by some sellers).
- New-construction floor plans (`newConstruction: true`) often have the plan name instead of a street address, for example `Camden Plan`.
- Not affiliated with Redfin. Listing data belongs to Redfin and the listing MLSs.

Looking at the UK instead? See [Rightmove Property Scraper](https://apify.com/northbell/rightmove-property-scraper).

### For AI agents

`{"locations": ["Austin, TX"], "maxHomesPerLocation": 5}` returns 5 `home` rows and 1 `summary` row. Rows have `type`: `home`, `summary`, `removed` or `error`. Call it again with the same input to get `isNew`, `priceChange` and `priceCutPct` filled in.

# Actor input Schema

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

One place per line: a city ("Austin, TX"), a borough or neighborhood ("Brooklyn, NY", "Hyde Park, Austin, TX"), a ZIP code ("78701"), or a Redfin page URL (redfin.com/city/…, /neighborhood/…, /county/…, /zipcode/…). A city, neighborhood or county URL gives exactly the homes Redfin lists for that place (filters in the URL are ignored, use the fields below), and is the way to read a whole county. Counties and states cannot be typed by name.

## `maxHomesPerLocation` (type: `integer`):

How many homes to return for each location, newest listings first. Redfin lists thousands of homes in a big city, so raise this (up to 2,000) or split the city into ZIP codes if you want everything. Price cuts and new listings are found among the homes read, and removed listings are only counted when every matching home was read.

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

Only homes listed at this price or more. Homes with no price shown are left out when a price limit is set.

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

Only homes listed at this price or less. Homes with no price shown are left out when a price limit is set.

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

Only homes with at least this many bedrooms. Land has no bedrooms and is left out when this is above 0.

## `propertyTypes` (type: `array`):

Only these kinds of property. Leave empty for all of them.

## `onlyChanges` (type: `boolean`):

From the second run of a search, return only homes that are new since your last run or whose price changed. Unchanged homes are skipped and not charged. The first run of a search always returns everything.

## `includeRemoved` (type: `boolean`):

From the second run, add a free row for each home that was in your last run but is no longer listed (sold, withdrawn, or no longer matching your filters). Only given when every matching home was read.

## Actor input object example

```json
{
  "locations": [
    "Austin, TX"
  ],
  "maxHomesPerLocation": 200,
  "onlyChanges": false,
  "includeRemoved": true
}
```

# Actor output Schema

## `homes` (type: `string`):

Homes for sale with price, size and the change since the last run.

## `summaries` (type: `string`):

One row per location: homes read, new, removed and price cuts since the last run, median price.

# 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"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("northbell/redfin-homes-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 = { "locations": ["Austin, TX"] }

# Run the Actor and wait for it to finish
run = client.actor("northbell/redfin-homes-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 '{
  "locations": [
    "Austin, TX"
  ]
}' |
apify call northbell/redfin-homes-scraper --silent --output-dataset

```

## MCP server setup

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