# Redfin Property Scraper — Schools, Risk & Parcels (`thenetaji/redfin-property-scraper`) Actor

Read any Redfin home in full from its page address. Twelve sections come back per home: the listing record, the long-form property history and public records, the agent and brokerage panel, assigned schools, flood, fire, heat and wind risk scores, the county parcel record and comparable sales.

- **URL**: https://apify.com/thenetaji/redfin-property-scraper.md
- **Developed by:** [The Netaji](https://apify.com/thenetaji) (community)
- **Categories:** Real estate, Automation, Business
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $5.10 / 1,000 property records

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 Property Scraper

The full Redfin record for a home, read from its page address. Twelve named sections come
back per property: the listing record, the long-form property history and public records,
the agent and brokerage panel, assigned and nearby schools, flood, fire, heat and wind risk
scores, the county parcel record, the history of Redfin's own value estimate, the listing's
activity, the neighbourhood context, Redfin's comparable sales, nearby listings and nearby
open houses.

Several of those exist nowhere else on a listing. A search row states the price, the size
and the address; it states nothing about the flood risk, the assessed value on the county's
parcel record, or which homes Redfin considers comparable.

### Accepted input

`propertyUrls` is required and takes one or more Redfin property pages, one per line, given
either as full links or as paths ending in `/home/<number>`. Both forms are accepted and may
be mixed in one list. A link and a path for the same home count as one entry.

The address is the key and it cannot be assembled. A Redfin property path carries a
street-address slug in the middle of it — `/CA/San-Francisco/331-Bartlett-St-94110/home/801881`
— and that slug is part of the address rather than decoration, so the page cannot be reached
from the number at the end. Every row
[Redfin Search Scraper](https://apify.com/thenetaji/redfin-search-scraper) produces carries
exactly this value in its `url` field, which is the intended way to obtain one.

```json
{
  "propertyUrls": [
    "https://www.redfin.com/CA/San-Francisco/331-Bartlett-St-94110/home/801881"
  ]
}
```

### Response fields

Each home is one row. Four fields identify it and twelve carry the record.

```json
{
  "property_id": "801881",
  "url": "https://www.redfin.com/CA/San-Francisco/331-Bartlett-St-94110/home/801881",
  "requested_url": "/CA/San-Francisco/331-Bartlett-St-94110/home/801881",
  "sections_present": [
    "above_the_fold",
    "below_the_fold",
    "main_house_info",
    "schools",
    "risk_factors",
    "parcel_info",
    "similar_listings"
  ],
  "above_the_fold": { "…": "Redfin's own shape" },
  "below_the_fold": { "…": "Redfin's own shape" },
  "main_house_info": { "…": "Redfin's own shape" },
  "schools": { "…": "Redfin's own shape" },
  "risk_factors": { "…": "Redfin's own shape" },
  "parcel_info": { "…": "Redfin's own shape" },
  "avm_history": null,
  "activity": null,
  "around_this_home": null,
  "similar_listings": { "…": "Redfin's own shape" },
  "nearby_listings": null,
  "nearby_open_houses": null
}
```

`above_the_fold` holds the price, address, beds, baths, area and listing status.
`below_the_fold` holds the long-form record: property history, public records, listing
details and amenities. `main_house_info` is the agent and brokerage attribution panel.
`schools` carries assigned and nearby schools with their ratings and distances.
`risk_factors` carries flood, fire, heat and wind scores. `parcel_info` is the county parcel
record matched to the address, with lot, APN and assessment data. `avm_history` is the
history of Redfin's own estimate of the home's value. `activity` is views, favourites and
tour requests. `around_this_home` is the neighbourhood context. `similar_listings`,
`nearby_listings` and `nearby_open_houses` are the surrounding market, and each entry in
them carries a Redfin address of its own, which this Actor takes.

Every section is republished in Redfin's own shape under its own name rather than renamed
into fields of this Actor's choosing. That is deliberate and it is the opposite of what a
flat export usually does, so it is worth stating why: renaming fields that have not been
observed populated would publish a column of permanent nulls and call it a schema.

`sections_present` lists the sections that actually arrived, counted from the response
rather than from a list of what was asked for. It is the field that makes a null column
readable: a home with eleven sections and no `parcel_info` is an address no county record
was matched to, and a home with two is a page that came back thin. The count is also
written to the run log for each home.

`property_id` is read off the address rather than lifted out of a section, because the
sections are the part with no guaranteed shape and an identifier taken from one would be
null exactly when that section was. `requested_url` echoes the path the row was read for, so
a run given pasted links can be matched to the paths they resolved to.

### Behaviour on partial results

A home that Redfin no longer serves — withdrawn between a search and this run — is skipped
with a line in the log and the run continues. Twenty addresses taken from a search last week
will not all still be listed, and losing nineteen good rows to one dead one is the wrong
trade. An entry that is not a Redfin property address at all is refused before the request
rather than after it, with a message naming the shape.

A section the page did not carry is null. Null means the page did not carry it, not that the
home has none of what it describes.

### Frequently asked questions

**Why does this Actor take an address rather than a property identifier?**
Because on Redfin the address is the key. A property path contains a street-address slug
that is not derivable from the numeric identifier at the end of it, so `property_id` alone
cannot reach the page. That identifier is still published on every row, because it is what
joins a row to anything else on the site — it is simply not what opens the page.

**How many rows does one home produce?**
One. All twelve sections belong to the same home and are read in the same request, so
splitting them across rows would produce a spreadsheet where the schools no longer line up
with the house they are assigned to.

**Why did some homes come back with far fewer sections than others?**
Because the page carried fewer. A new-construction listing with no sale history, an address
with no matched county parcel record, and a home with no comparable sales nearby all return
fewer sections than an established resale in a dense market, and every one of those is a
complete answer. `sections_present` says which arrived.

**Is there a way to read a whole market this way?**
Not economically. This Actor spends one request per home, which is why a row here costs
several times what a listing row costs. The market read is
[Redfin Search Scraper](https://apify.com/thenetaji/redfin-search-scraper), which returns an
entire region in a single request and already carries the price, the size, the address, the
MLS status and the listing agent's own description. The usual shape of a job is a region
read there, filtered down, and then a shortlist read here.

**Are sold homes covered?**
No. Redfin does not serve sold listings through the surface these Actors read, which is a
measurement rather than a choice — a request built exactly as Redfin's own sold search
builds it returns the for-sale listings unchanged. `below_the_fold` does carry a home's own
past sales where Redfin publishes them, but that is one home's history rather than a way to
enumerate a market's sales.

**Is a Redfin account, cookie or API key required?**
No. No account, session cookie or key of any kind is supplied to the Actor or needed by it.

### Related Actors

[Redfin Search Scraper](https://apify.com/thenetaji/redfin-search-scraper) reads every home
for sale in a city, ZIP code, neighbourhood, county, state or school district in one
request, and every row it produces carries the exact address this Actor takes. It is where
a job on this site starts.

# Actor input Schema

## `propertyUrls` (type: `array`):

Redfin property pages to read, one per line, as full links or as paths ending in /home/<number>. Every row a search run produces carries exactly this value in its `url` field, so a search export feeds straight in. Paste the address from Redfin's own URL bar, or use the `url` a search row already carries — a Redfin address cannot be assembled from an identifier.

## Actor input object example

```json
{
  "propertyUrls": [
    "/CA/San-Francisco/331-Bartlett-St-94110/home/801881"
  ]
}
```

# Actor output Schema

## `dataset` (type: `string`):

All records scraped 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 = {
    "propertyUrls": [
        "https://www.redfin.com/CA/San-Francisco/331-Bartlett-St-94110/home/801881"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("thenetaji/redfin-property-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 = { "propertyUrls": ["https://www.redfin.com/CA/San-Francisco/331-Bartlett-St-94110/home/801881"] }

# Run the Actor and wait for it to finish
run = client.actor("thenetaji/redfin-property-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 '{
  "propertyUrls": [
    "https://www.redfin.com/CA/San-Francisco/331-Bartlett-St-94110/home/801881"
  ]
}' |
apify call thenetaji/redfin-property-scraper --silent --output-dataset

```

## MCP server setup

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