# Redfin scraper (`lukass/redfin-scraper`) Actor

Scrapes real-estate data from a provided location.

- **URL**: https://apify.com/lukass/redfin-scraper.md
- **Developed by:** [Lukáš Širhal](https://apify.com/lukass) (community)
- **Categories:** Real estate
- **Stats:** 190 total users, 0 monthly users, 75.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?

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

## Redfin Scraper

Scrapes real-estate listings from [Redfin](https://www.redfin.com/) — homes for sale and rentals — and returns them as structured data.

Give it a Redfin search URL (or just a location name), optionally narrow the results with filters, and get back every matching listing with price, size, address, coordinates, status and description.

### Features

- **Homes for sale and rentals** — pick either category.
- **Search by URL or by location** — paste a Redfin region URL, or type a city, ZIP code or neighborhood.
- **Server-side filters** — price, beds, baths, square footage, property type, sold-within-days and sort order are applied by Redfin itself, so filtering makes runs *cheaper*, not slower.
- **Whole regions in one request** — a full metro (7,000+ listings) is fetched in a single API call.
- **No duplicates** — listings are deduplicated by property id within and across runs.
- **Only downloads what you need** — a `maxItems` of 20 fetches roughly 20 listings, not the whole city.

### Input

Everything is optional, but you must give either **Redfin search URLs** or a **location**.

| Field | Type | Description |
|---|---|---|
| `startUrls` | Array | Redfin search URLs to scrape, e.g. `https://www.redfin.com/city/16163/WA/Seattle`. **The fastest and cheapest option** — it needs no browser. Use search/region URLs, not individual property pages. |
| `location` | String | A city, ZIP code, neighborhood or address, e.g. `"Philadelphia"`. Only used when no start URLs are given. Slower and more expensive, because Redfin's location lookup may require a browser. |
| `category` | Enum | `forSale` (default) or `forRent`. A start URL must match the category you pick. |
| `maxItems` | Integer | Maximum listings to return. `0` (default) means every listing in the search. Lower values make runs cheaper. |
| `propertyTypes` | Array | Restrict to `house`, `condo`, `townhouse`, `multiFamily`, `land`, `other`, `coop`. Empty means all types. |
| `minPrice` / `maxPrice` | Integer | Price range in US dollars. |
| `minBeds` / `maxBeds` | Integer | Bedroom count range. |
| `minBaths` | Integer | Fewest bathrooms. |
| `minSqFt` / `maxSqFt` | Integer | Interior size range in square feet. |
| `soldWithinDays` | Integer | Also include homes sold in the last N days. Leave empty for on-market listings only. |
| `sortBy` | Enum | `relevance` (default), `newest`, `oldest`, `priceAsc`, `priceDesc`, `sqftDesc`, `pricePerSqftAsc`. Matters when combined with `maxItems`. |
| `proxyConfig` | Object | Proxy configuration. See below. |

#### Example input

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

#### Proxy

A proxy is strongly recommended. Redfin blocks datacenter IP addresses on its web pages, so **if you search by `location`, use the `RESIDENTIAL` proxy group** — the location lookup may need to load a real page. Scraping from `startUrls` is far more tolerant.

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

### Output

Each listing becomes one dataset item.

#### For sale

| Field | Type | Description |
|---|---|---|
| `propertyId` | Number | Redfin's unique id for the property. |
| `url` | String | Link to the listing on Redfin. |
| `price` | Number | Asking price in US dollars. |
| `beds` | Number | Number of bedrooms. `null` when not disclosed. |
| `baths` | Number | Number of bathrooms, halves included (e.g. `2.5`). |
| `sqft` | Number | Interior size in square feet. |
| `status` | String | MLS status — `Active`, `Coming Soon`, `Pending`, `Closed`, … |
| `type` | String | Property type — `House`, `Condo`, `Townhouse`, `Vacant Land`, … |
| `address` | String | Street line, e.g. `1710 Montrose St`. |
| `city` / `state` / `zip` | String | Address components. |
| `lat` / `lon` | Number | Coordinates in decimal degrees. |
| `yearBuilt` | Number | Year of construction. |
| `community` | String | Neighborhood or community name. |
| `hoa` | Number | HOA dues per month, when published. |
| `mls` | String | MLS listing number. |
| `timeOnRedfin` | Number | Minutes since the listing appeared on Redfin. |
| `description` | String | Listing remarks written by the agent. |
| `yearBuild` | Number | Deprecated misspelling of `yearBuilt`, kept for backwards compatibility. |

Fields Redfin does not publish for a given listing come back as `null` — this is common for `hoa`, and for `sqft` and `yearBuilt` on land and new construction.

#### For rent

Rentals return the same shape, minus `yearBuilt`, `community`, `hoa`, `mls` and `timeOnRedfin`. Because a rental building lists several units, `price`, `beds`, `baths` and `sqft` are **ranges given as strings** (e.g. `"1100 - 1350"`) when the units differ, and a plain number when they don't.

#### Example output

```json
{
  "propertyId": 38798295,
  "url": "https://www.redfin.com/PA/Philadelphia/1710-Montrose-St-19146/home/38798295",
  "price": 925000,
  "beds": 3,
  "baths": 4,
  "sqft": 2178,
  "status": "Coming Soon",
  "type": "Townhouse",
  "address": "1710 Montrose St",
  "city": "Philadelphia",
  "state": "PA",
  "zip": "19146",
  "lat": 39.9400914,
  "lon": -75.1716835,
  "yearBuilt": 2006,
  "community": "Graduate Hospital",
  "hoa": null,
  "mls": "2187927345424205529",
  "timeOnRedfin": 37,
  "description": "Welcome to 1710 Montrose Street, a beautifully renovated 3-bedroom, 3.5-bath home with GARAGE parking…"
}
```

### Notes and limits

- A start URL must match the `category`. A rentals URL with `category: "forSale"` returns nothing useful.
- Redfin caps very large searches. If a region exceeds the cap, the scraper automatically splits it into smaller map viewports and keeps going.
- `soldDate` on Redfin refers to a property's *previous* sale and appears on active listings too, so it is not exposed as a "sold" flag. Use `status` to tell sold listings apart, and `soldWithinDays` to include them.
- Rental results overlap between pages; the scraper deduplicates them, so a run may report fewer new listings than the page size.

### Support

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

# Actor input Schema

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

Redfin search URLs to scrape, e.g. https://www.redfin.com/city/16163/WA/Seattle. This is the fastest and cheapest way to run the scraper — it needs no browser. Use search/region URLs, not individual property pages.

## `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`):

Whether to scrape homes for sale or rentals. A start URL must match the category you pick.

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

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

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

Also include homes sold in the last N days. Leave empty to return only listings that are currently on the market.

## `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,
  "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/FS4sRmDSsTEJjJ3gg/openapi.json
