# Redfin Scraper 💰 $1/1K – For Sale, Sold Comps & Rentals (`lukass/redfin-scraper`) Actor

Scrape Redfin homes for sale, recently sold comps and rentals in any US city, ZIP or county. A whole metro in one request, with price, beds, baths, sqft, price per sqft, lot size, photos, MLS# and sold date. Monitoring mode returns only new listings. No login.

- **URL**: https://apify.com/lukass/redfin-scraper.md
- **Developed by:** [Lukáš Širhal](https://apify.com/lukass) (community)
- **Categories:** Real estate
- **Features:** Limited permissions
- **Stats:** 192 total users, 0 monthly users, 100.0% runs succeeded, 4 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.65 / 1,000 results

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

Scrape [Redfin](https://www.redfin.com/) real-estate data for any US city, ZIP code, county or neighborhood: **homes for
sale, recently sold homes (sold comps) and rentals**. Paste a Redfin search URL or type a location, add filters, and get
every matching home with price, beds, baths, square feet, price per square foot, lot size, photos, MLS number, sold date
and the agent's description. No login or API key needed.

### Why this Redfin scraper

- 🏙️ **A whole metro in one request.** Redfin's search API returns thousands of listings at once, so there is no
  350-result or 9-page limit to work around. Very large searches are split into map areas automatically.
- 💰 **Sold comps.** Homes sold in the last 7 days to 5 years, with sold price and date, including public-record sales
  that never went through an MLS.
- 🔔 **Monitoring mode.** Schedule a search and get only the listings that appeared since the last run, paying only
  for new ones.
- 🎯 **Redfin's own filters.** Price, beds, baths, square feet, property type, sold window and sort order are applied
  by Redfin, so filtering makes a run cheaper, not slower.
- 📸 **Rich records at no extra cost.** Photos, price per sq ft, lot size, badges (Hot Home, Price Drop, Open House),
  key facts and the listing description come straight from the search, without a request per home.
- 🏷️ **Redfin Estimate on demand.** Turn on property details for each home's Redfin Estimate, the comparable sales
  behind it, Walk/Transit/Bike Score and the parcel number (APN).
- 🔗 **Paste a filtered search.** Filters in a Redfin URL (price, beds, property type, year built, lot size, HOA,
  sort) are applied, so a search set up in your browser runs as is.
- ⚡ **Only downloads what you need.** `maxItems: 20` fetches about 20 listings, not the whole city.

#### Who uses it

- **Investors and wholesalers**: pull sold comps for a ZIP, spot underpriced listings by price per sq ft, and get new
  multi-family or land listings every morning.
- **Agents and brokers**: track new listings, price drops and open houses in your farm area.
- **Analysts and proptech**: build price, inventory and rent datasets for any US market.
- **Home buyers and renters**: get a daily list of new homes that match your filters.

### How to scrape Redfin

1. Open Redfin, search for a city, ZIP or county and copy the URL from the address bar, or just type the place into
   **Location**.
2. Choose **For sale**, **Recently sold** or **For rent**, and add filters if you like.
3. Click **Start**. Download the results as JSON, CSV, Excel or HTML, or connect them to Google Sheets, Zapier or
   your own app through the API.

### Input examples

Homes for sale in Philadelphia between $300k and $750k, 3+ bedrooms, cheapest first:

```json
{
  "startUrls": [{ "url": "https://www.redfin.com/city/15502/PA/Philadelphia" }],
  "category": "forSale",
  "minPrice": 300000,
  "maxPrice": 750000,
  "minBeds": 3,
  "sortBy": "priceAsc",
  "maxItems": 200
}
```

Sold comps: every house sold in Phoenix in the last 6 months:

```json
{
  "startUrls": [{ "url": "https://www.redfin.com/city/14240/AZ/Phoenix" }],
  "category": "sold",
  "soldWithinDays": 180,
  "propertyTypes": ["house"]
}
```

A sold search pasted from Redfin works too: `https://www.redfin.com/city/14240/AZ/Phoenix/filter/include=sold-3mo`
is read as sold within 90 days, and `.../apartments-for-rent` as rentals.

New Seattle listings only, for a daily schedule:

```json
{
  "startUrls": [{ "url": "https://www.redfin.com/city/16163/WA/Seattle" }],
  "monitoringMode": true,
  "maxItems": 300
}
```

### Input

Give either **Redfin search URLs** or a **location**; everything else is optional.

| Field | Type | Description |
|---|---|---|
| `startUrls` | Array | Redfin search URLs, e.g. `https://www.redfin.com/city/16163/WA/Seattle`. **Fastest and cheapest**: city and county URLs need no browser at all. Filters in the URL are applied (see below). Use region URLs, not single property pages. |
| `location` | String | A city, ZIP code, neighborhood or address, e.g. `"Philadelphia"`. Used when no start URLs are given. Slower, because Redfin's location lookup sometimes needs a browser. |
| `category` | Enum | `forSale` (default), `sold` (recently sold comps) or `forRent`. A rentals or sold URL keeps its own category. |
| `maxItems` | Integer | Maximum listings to return. `0` (default) means every listing in the search. Lower values make runs cheaper. |
| `monitoringMode` | Boolean | Return only listings earlier runs of the same search did not return. See below. |
| `includeDetails` | Boolean | Adds Redfin Estimate, estimate comparables, Walk/Transit/Bike Score, APN and FIPS code. One extra request and one extra charge per home. Not for rentals. |
| `propertyTypes` | Array | `house`, `condo`, `townhouse`, `multiFamily`, `land`, `other`, `coop`. Empty means all types. |
| `minPrice` / `maxPrice` | Integer | Price range in US dollars. |
| `minBeds` / `maxBeds` | Integer | Bedroom range. |
| `minBaths` | Integer | Fewest bathrooms. |
| `minSqFt` / `maxSqFt` | Integer | Interior size range in square feet. |
| `minYearBuilt` / `maxYearBuilt` | Integer | Construction year range. |
| `minLotSize` / `maxLotSize` | Integer | Lot size range in square feet (1 acre = 43,560 sq ft). |
| `maxHoa` | Integer | Highest monthly HOA dues. `0` returns only homes without HOA dues. |
| `soldWithinDays` | Integer | With `sold`: how far back to go (default 90; e.g. 30, 365, 1825). With `forSale`: also mixes in a few recently sold homes. |
| `sortBy` | Enum | `relevance` (default), `newest`, `oldest`, `priceAsc`, `priceDesc`, `sqftDesc`, `pricePerSqftAsc`. Matters with `maxItems`. |
| `proxyConfig` | Object | Proxy configuration. See below. |

#### Filters in pasted URLs

Set up a search on Redfin, copy the URL and paste it: the `/filter/` part is applied. For example
`https://www.redfin.com/city/16163/WA/Seattle/filter/property-type=house+townhouse,min-price=500k,max-price=1.2M,min-beds=3,min-year-built=1990`
returns Seattle houses and townhouses from $500k to $1.2M with 3+ bedrooms built since 1990. Supported: property type,
price, beds, baths, square feet, year built, lot size, HOA, sort and the sold window. Filters this scraper doesn't
support (e.g. pool, garage) are listed in the run log and not applied. URL filters win over the input's.

#### Monitoring mode: only new listings

Turn on `monitoringMode` and schedule the task (daily, hourly). Each run remembers the listings it returned, and the
next run of the **same search** skips them, so you get, and pay for, only what is new.

- For-sale searches are sorted newest first and stop at the first listing an earlier run returned, so a daily run
  downloads very little.
- Sold and rental searches are filtered the same way: you get homes sold, or rentals listed, since the last run.
- The first run returns everything (up to `maxItems`), which sets the starting point. Sold and rental searches aren't
  ordered by date, so with a `maxItems` limit they also catch up, run by run, on homes the limit left out before.
- Changing the URLs, location, category or filters starts a fresh list. `maxItems` does not.

To get alerts, connect the task to email, Slack or a webhook with Apify's
[integrations](https://docs.apify.com/platform/integrations).

#### Proxy

Redfin's search API works with the default Apify Proxy. Searching by `location` may need to load a real Redfin page,
which Redfin blocks on datacenter IPs, so use the `RESIDENTIAL` group for location searches:

```json
{ "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
```

### Output

One dataset item per home. Download it as JSON, CSV, Excel or HTML.

```json
{
  "propertyId": 26839412,
  "url": "https://www.redfin.com/AZ/Scottsdale/5312-E-Anderson-Dr-85254/home/26839412",
  "price": 1699000,
  "pricePerSqft": 438,
  "beds": 5,
  "baths": 4,
  "sqft": 3879,
  "lotSize": 13696,
  "status": "Closed",
  "type": "House",
  "address": "5312 E Anderson Dr",
  "city": "Scottsdale",
  "state": "AZ",
  "zip": "85254",
  "lat": 33.6439953,
  "lon": -111.965927,
  "yearBuilt": 1997,
  "community": "ARABIAN CREST TWO",
  "hoa": null,
  "mls": "7067457",
  "listingId": 222465250,
  "isSold": true,
  "soldDate": "2026-09-15",
  "soldPrice": 1699000,
  "lastSoldDate": null,
  "badges": ["Sold"],
  "openHouse": null,
  "isHot": false,
  "isNewConstruction": null,
  "hasVirtualTour": false,
  "keyFacts": [],
  "photoCount": 59,
  "mainPhoto": "https://ssl.cdn-redfin.com/photo/86/bigphoto/457/7067457_0.jpg",
  "photos": ["https://ssl.cdn-redfin.com/photo/86/bigphoto/457/7067457_0.jpg", "…"],
  "description": "Absolutely stunning home that…"
}
```

| Field | Description |
|---|---|
| `propertyId`, `url` | Redfin's id for the home and the link to it. |
| `price`, `pricePerSqft` | Asking price (sold price for sold homes) and price per square foot, in US dollars. |
| `beds`, `baths`, `sqft`, `lotSize` | Bedrooms, bathrooms (halves included), interior size and lot size in square feet. |
| `status` | `Active`, `Coming Soon`, `Pending`, `Closed`, or `Sold` for public-record sales. |
| `type` | `House`, `Condo`, `Townhouse`, `Vacant Land`, … |
| `address`, `city`, `state`, `zip`, `lat`, `lon` | Location. |
| `yearBuilt`, `community`, `hoa`, `mls`, `listingId` | Year built, neighborhood, monthly HOA dues, MLS number, Redfin listing id. |
| `isSold`, `soldDate`, `soldPrice` | Sale date and price of a sold home. |
| `lastSoldDate` | Previous sale date of a home that is on the market now. |
| `badges`, `openHouse`, `isHot`, `isNewConstruction`, `hasVirtualTour`, `keyFacts` | Redfin's badges (Price Drop, Open House, Hot Home…), open house times and listing highlights. |
| `photoCount`, `mainPhoto`, `photos` | Full-size photo URLs. Public-record sales have none. |
| `description` | The agent's listing remarks. |
| `daysOnMarket`, `timeOnRedfin` | Shown only when Redfin publishes them without a login, which is rare. |
| `redfinEstimate`, `estimateComparables` | With `includeDetails`: Redfin's estimated value and the comparable sales behind it (address, price, sold date, beds, baths, sqft). Empty when Redfin shows "Estimate not available", e.g. on brand-new construction. |
| `walkScore`, `transitScore`, `bikeScore` | With `includeDetails`: Walk Score ratings 0-100. |
| `apn`, `fipsCode` | With `includeDetails`: assessor parcel number and county FIPS code, for matching with county records. |

Fields Redfin doesn't publish for a home come back as `null`, most often `hoa`, and `sqft` or `yearBuilt` on land and new
construction. `yearBuild` is a deprecated alias of `yearBuilt`, kept for existing integrations.

**Rentals** return the same location fields plus `price`, `beds`, `baths` and `sqft`. A building with several units
reports them as ranges, e.g. `"1100 - 1350"`.

### How much does it cost?

You pay **$1.00 per 1,000 listings** (as low as $0.65 on higher Apify plans) plus $0.01 per run. Property details
(`includeDetails`) add **$0.50 per 1,000 homes**. Platform and proxy costs are included. Apify's free plan gives you $5 of credit every month, enough for about **5,000 listings**.

With `monitoringMode`, a scheduled run pays only for new listings, often a few cents a day. You can also cap a run's
cost with the maximum charge setting; the scraper stops cleanly when it is reached.

### Notes and limits

- A rentals URL needs `category: forRent` (or is detected automatically when it ends in `/apartments-for-rent`).
- Redfin caps very large searches; the scraper splits the map into smaller areas and keeps going.
- Within a run every home is returned once, even when several start URLs overlap.

### Is it legal to scrape Redfin?

The scraper collects only publicly available listing data. Listing descriptions and photos may be copyrighted, and
personal data is protected by laws such as GDPR and CCPA, so use the data responsibly. If you're unsure, consult a
lawyer. See also [is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

### Support

Found a bug or need a field that isn't here? Open an issue on the **Issues** tab.

# Changelog

This Actor's version history is a separate document: https://apify.com/lukass/redfin-scraper/changelog.md

# Actor input Schema

## `startUrls` (type: `array`):

Redfin search URLs, e.g. https://www.redfin.com/city/16163/WA/Seattle. Filters in the URL (price, beds, baths, size, property type, year built, lot size, HOA, sort, sold window) are applied too, so you can paste a filtered search straight from your browser. City and county URLs need no browser, which makes them the fastest and cheapest option.

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

A city, ZIP code, neighborhood or address to search for, e.g. "Philadelphia". Only used when no start URLs are given. Slower and more expensive than a start URL, because Redfin's location lookup may require a browser.

## `category` (type: `string`):

For sale, recently sold homes (sold comps, with sold price and date) or rentals. A pasted Redfin URL that is itself a rentals or sold search (/apartments-for-rent, include=sold-3mo) keeps its own category.

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

Limit how many listings to scrape. Set to 0 for every listing in the search. Lower values also make the run cheaper — the scraper only downloads what it needs.

## `monitoringMode` (type: `boolean`):

Return only listings that earlier runs of this same search have not returned, so a scheduled run pays only for new listings. For-sale searches are sorted newest first and stop at the first listing seen before. Changing the URLs, location, category or filters starts a fresh list.

## `includeDetails` (type: `boolean`):

One extra request per home for its Redfin Estimate and the comparable sales behind it, Walk/Transit/Bike Score, and parcel number (APN) with county FIPS code. Billed as a separate event per home. Not available for rentals.

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

Only return these property types. Leave empty for all types.

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

Lowest listing price to include.

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

Highest listing price to include.

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

Fewest bedrooms to include.

## `maxBeds` (type: `integer`):

Most bedrooms to include.

## `minBaths` (type: `integer`):

Fewest bathrooms to include.

## `minSqFt` (type: `integer`):

Smallest interior size to include.

## `maxSqFt` (type: `integer`):

Largest interior size to include.

## `minYearBuilt` (type: `integer`):

Oldest construction year to include.

## `maxYearBuilt` (type: `integer`):

Newest construction year to include.

## `minLotSize` (type: `integer`):

Smallest lot to include, in square feet (1 acre = 43,560 sq ft).

## `maxLotSize` (type: `integer`):

Largest lot to include, in square feet.

## `maxHoa` (type: `integer`):

Highest monthly HOA dues to include. 0 returns only homes without HOA dues.

## `soldWithinDays` (type: `integer`):

With 'Recently sold': how far back to go, e.g. 30, 90 (default), 365, 1825. With 'For sale': also mixes in a few recently sold homes.

## `sortBy` (type: `string`):

Order Redfin returns listings in. Matters when combined with a maximum result count.

## `proxyConfig` (type: `object`):

Redfin blocks datacenter IPs on its pages — use the RESIDENTIAL group if searching by location.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.redfin.com/city/15502/PA/Philadelphia"
    }
  ],
  "category": "forSale",
  "maxItems": 100,
  "monitoringMode": false,
  "includeDetails": false,
  "propertyTypes": [],
  "sortBy": "relevance",
  "proxyConfig": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `listings` (type: `string`):

Every scraped property listing, as JSON.

## `listingsCsv` (type: `string`):

The same listings as a CSV file, ready for a spreadsheet.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.redfin.com/city/15502/PA/Philadelphia"
        }
    ],
    "category": "forSale",
    "maxItems": 100,
    "proxyConfig": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("lukass/redfin-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 = {
    "startUrls": [{ "url": "https://www.redfin.com/city/15502/PA/Philadelphia" }],
    "category": "forSale",
    "maxItems": 100,
    "proxyConfig": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("lukass/redfin-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 '{
  "startUrls": [
    {
      "url": "https://www.redfin.com/city/15502/PA/Philadelphia"
    }
  ],
  "category": "forSale",
  "maxItems": 100,
  "proxyConfig": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call lukass/redfin-scraper --silent --output-dataset

```

## MCP server setup

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