Redfin Scraper - Homes for Sale & Sold Listings avatar

Redfin Scraper - Homes for Sale & Sold Listings

Pricing

from $1.20 / 1,000 listing results

Go to Apify Store
Redfin Scraper - Homes for Sale & Sold Listings

Redfin Scraper - Homes for Sale & Sold Listings

Scrape redfin.com home listings: price, beds, baths, sqft, lot, year built, coordinates, address, MLS, status, days on market, photos, schools, amenities, tax records, agent and brokerage plus 90+ fields. Search any city, ZIP, neighborhood, or county with sort and filters, or paste Redfin URLs.

Pricing

from $1.20 / 1,000 listing results

Rating

0.0

(0)

Developer

Abot API

Abot API

Maintained by Community

Actor stats

1

Bookmarked

4

Total users

0

Monthly active users

4 days ago

Last modified

Share

Redfin Scraper: Homes for Sale, Sold Listings & Property Data

Redfin Scraper pulls structured home listings from redfin.com at scale. Search any city, ZIP code, neighborhood, or county, narrow with sort and filters, and get a clean JSON record per home with price, beds, baths, square footage, lot size, year built, coordinates, address, MLS number, status, days on market, photo data, key facts, and listing remarks, plus the listing agent and brokerage when detail enrichment is on. Or paste Redfin region and listing URLs and let the scraper walk them for you, then export to JSON, CSV or Excel, or pull the results straight into your app through the API.

Why This Scraper?

  • 90+ fields per listing. Price, price per sq ft, beds, full and partial baths, square footage, lot size, stories, year built, HOA dues, coordinates, MLS number, status, days on market, photos, key facts, tags and the full listing remarks on every search result.
  • Search or paste URLs. Find homes by city, ZIP, neighborhood or county with sort and filters, or paste exact Redfin region and listing URLs and pull them verbatim.
  • For sale or recently sold. Switch between active listings and homes sold in the last three years.
  • Optional detail enrichment. Add the listing agent, brokerage, valuation label, nearby schools with ratings, structured amenities, home highlights, public and tax records, and the Redfin Estimate per home.
  • Predictable cost. One Max listings cap controls exactly how many records a run returns, with a separate Max pages safety stop for paging depth.
  • Built for schedules. Incremental mode returns only new and changed listings on recurring runs, and a genuinely blocked run fails loudly instead of returning an empty dataset.
  • MCP export. Optionally pipe results straight into Notion, Linear, Airtable, or Apify.

Use Cases

  • Real estate investors and analysts: track pricing, days on market and price-per-sqft trends across neighborhoods to spot value.
  • Agents and brokerages: monitor competing listings, new inventory and price changes in a farm area on a schedule.
  • Real estate data products and dashboards: feed structured listing data into your own search, map or comps tool.
  • Market researchers: build historical datasets of sold homes, including sale dates and property details, for trend analysis.
  • Lead generation tools: collect listing agent and brokerage details alongside property data for outreach lists.

Data You Get

Sample shape: values are illustrative placeholders, not from a live listing. Fields below come from a search result or a pasted region URL. A pasted single listing URL returns a narrower record; see "Paste a single listing URL" under How to Use.

FieldExample
id12345678
url"https://www.redfin.com/IL/Chicago/123-Example-St-60601/home/12345678"
price575000
priceType"List price" (when detail enrichment is on)
pricePerSqFt311
beds3
baths2.5
bathFull / bathPartial2 / 1
sqft1850
lotSize4200
yearBuilt1998
hoaDues250
propertyTypeLabel"Condo/Co-op"
status"Active"
daysOnMarket12
streetLine"123 Example St"
city / state / zip"Chicago" / "IL" / "60601"
latitude / longitude41.8781 / -87.6298
mlsId"mred00000000"
photos"0-24:0" (photo count descriptor)
listingTags["Hardwood flooring"]
listingRemarks"Bright corner unit with lake views and an updated kitchen."
listingAgent"Alex Example" (when detail enrichment is on)
brokerName"Example Realty Group" (when detail enrichment is on)
scrapedAt"2025-01-01T00:00:00+00:00"

With detail enrichment on, each record also carries mainHouseInfo (full street address plus canonical URL), schools (nearby schools with ratings, grade ranges and distance), amenities (structured group/value pairs), homeHighlights, publicRecords (APN, tax rate, county), and redfinEstimate (amount and label, only on homes where Redfin publishes one). Incremental mode additionally adds changeType, changedFields, firstSeenAt and lastSeenAt to every returned row.

How to Use

  1. Pick a mode: search (by location + filters) or url (paste Redfin links).
  2. Fill in the fields for that mode: locations, listing type, sort and filters for search, or region/listing links for url mode.
  3. Set Max listings (and optionally Max pages) to control run size and cost, then click Start.
  4. Download the dataset as JSON, CSV or Excel, or read it through the API.

Search a city for homes for sale (default):

{
"mode": "search",
"locations": ["Chicago, IL"],
"listingType": "for_sale",
"maxItems": 50
}

Filtered search, cheapest first, condos only:

{
"mode": "search",
"locations": ["Austin, TX", "78701"],
"propertyTypes": ["Condo"],
"sortBy": "price_low",
"minPrice": 300000,
"maxPrice": 700000,
"minBeds": 2,
"maxItems": 100
}

Recently sold homes with full detail:

{
"mode": "search",
"locations": ["Brooklyn, NY"],
"listingType": "sold",
"fetchDetails": true,
"maxItems": 40
}

Paste region and listing URLs:

{
"mode": "url",
"urls": [
"https://www.redfin.com/city/29470/IL/Chicago",
"https://www.redfin.com/IL/Chicago/123-Example-St-60601/home/12345678"
]
}

Listings mode (mode = "Addresses / previous dataset") fetches exact homes from addresses and/or the listing URLs of a previous run's dataset (searchResultsDatasetId). Each home is one dataset item, charged like any other row, plus the detail-enrichment event when fetchDetails is on. Listings mode never produces EXPIRED rows. New flat detail fields: avmSectionPreviewText, homeStatusLabel, fullStreetAddress.

Supported URL shapes (URL mode):

ShapeExample
Cityhttps://www.redfin.com/city/29470/IL/Chicago
ZIP codehttps://www.redfin.com/zipcode/60611
County (the id decides the county)https://www.redfin.com/county/727/IL/Cook-County
Statehttps://www.redfin.com/state/Illinois
Paginated (starts at that page of 40, partial scope)https://www.redfin.com/city/29470/IL/Chicago/page-2
Filtered (min-price, max-price, min-beds, min-baths, min-sqft, max-sqft applied; others are skipped with a warning)https://www.redfin.com/city/29470/IL/Chicago/filter/max-price=500k,min-beds=2
Recently sold (returns sold homes)https://www.redfin.com/city/29470/IL/Chicago/recently-sold
Sold in the last 3 years (filter)https://www.redfin.com/city/29470/IL/Chicago/filter/include=sold-3yr
Category: property typehttps://www.redfin.com/city/29470/IL/Chicago/condos
Category: price bandhttps://www.redfin.com/city/29470/IL/Chicago/homes-for-sale-under-150000
Neighborhoodhttps://www.redfin.com/neighborhood/28211/IL/Chicago/Lincoln-Park
Single listinghttps://www.redfin.com/IL/Chicago/123-Example-St-60601/home/12345678

Behaviour change: the urls field now defaults to the first seven region examples above (the single-city example stays first), so a run started with URL mode and no edits scrapes all seven. Any URL that is not a supported shape is skipped with a warning in the log. Search mode still resolves plain city names, and stops with an error when nothing matches.

Run it from your code

Python:

from apify_client import ApifyClient
client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("abotapi/redfin-scraper").call(run_input={"mode": "search", "locations": ["Chicago, IL"], "maxItems": 50})
for home in client.dataset(run["defaultDatasetId"]).iterate_items():
print(home["streetLine"], home["price"])

JavaScript:

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('abotapi/redfin-scraper').call({ mode: 'search', locations: ['Chicago, IL'], maxItems: 50 });
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Or connect it to Make, Zapier, n8n, Google Sheets or webhooks from the Integrations tab.

How Max listings and Max pages interact

Max listings (maxItems) is the only cap on total results; it defaults to 20 and 0 means unlimited. Max pages (maxPages) is an optional safety stop on the number of result pages fetched per location (350 listings per page) and does not by itself cap your totals; Max listings still decides when a run stops. Leave Max pages at 0 (the default) for uncapped paging.

Detail enrichment and its cost

Turn on Fetch full listing details to add the listing agent, brokerage, a valuation label, nearby schools, structured amenities, public and tax records, and the Redfin Estimate. Each listing enriched this way bills a separate detail-enrichment charge in addition to the per-listing result charge; the Pricing tab shows the current rates. This toggle governs search-mode results, pasted region URLs, and a pasted single listing URL (a link containing /home/<id>), which needs it on (the default) to return anything more than its id and URL. With it off, a pasted listing URL is still billed the per-listing result charge, but the row carries only id, propertyId, a fallback URL and scrapedAt, with no detail fields and no detail-enrichment charge.

Paste a single listing URL

A pasted listing URL fetches that home's detail panels directly; it never re-walks the search page the listing came from. That means the record it returns carries the listing agent, brokerage, full address (under mainHouseInfo), schools, amenities, public records and the Redfin Estimate when available, but it does not carry price, beds, baths, sqft, lotSize, yearBuilt, streetLine/city/state/zip, latitude/longitude, photos, keyFacts, listingTags or listingRemarks - those only come from a search-result card. To get the full field set for one specific property, search by its address or ZIP instead of pasting its listing URL; paste the URL only when you already have the fields above from elsewhere and just need the detail-only data.

Resume and incremental mode

  • Resume (resumeFromRunId) continues one interrupted run: paste its run or dataset ID and the actor skips every listing already collected there, so you don't pay twice.
  • Incremental mode (incrementalMode) is for scheduled runs over the same search or URL list. Each listing is classified NEW, UPDATED (with changedFields), UNCHANGED (suppressed and not billed unless emitUnchanged is on), or EXPIRED (only after a run that completely covered every selected location/URL, and only with emitExpired on). Counters that tick on their own (days on market, time on Redfin, the scrape timestamp) are ignored when deciding whether a listing changed, so an unchanged listing never looks "updated" just because a day passed. Every other scraped field is compared, and the fields stay in the output either way. Use ignoreFieldsForChanges to exclude more noisy fields (a name matches at any depth; a dotted path such as schools.rating targets one nested spot). Pasted /page-N and /filter/... URLs are treated as partial scopes and never produce EXPIRED rows.
  • REAPPEARED is not something that happens "by default": it can only be reported for a listing this actor has already tombstoned EXPIRED in an earlier run (which itself required a prior complete, uncapped, non-resumed scan with emitExpired on). A listing dropping out of one run and coming back in a later one, without ever having been marked EXPIRED first, is reported as NEW or UPDATED like any other change, not REAPPEARED.
  • emitExpired only fires after a run that resolved every given location/URL, was not truncated by Max listings or Max pages, was not a resumed or checkpoint-continued run, and hit no rejected or failed requests. If any of that is not true, expiry reporting is skipped for that run (with a log line explaining why) and previously tracked listings stay as they were.
  • One-time fresh baseline for ZIP scopes. An incremental task that targets a ZIP code (a pasted /zipcode/<zip> URL or a bare 5-digit location) starts a fresh baseline on its first run after the ZIP region fix, so it reports that ZIP's listings as NEW instead of marking the previously tracked rows EXPIRED. If you set a manual stateKey on such a task, switch to a new State key once for the same reason. City, county, neighborhood and state tasks keep their baselines.
  • Leave stateKey empty unless you want to control the baseline yourself: it is otherwise derived from your search settings, so changing a filter starts a separate baseline instead of reporting your whole result set as new.

Send results into your apps (MCP connectors)

Optionally pipe each run's results into the apps you already use through Model Context Protocol (MCP) connectors. This is an extra delivery step after the scrape: the Apify dataset is never changed.

What gets written to the connector: a condensed, human-readable summary of each listing, not the full JSON. Each item becomes one entry with a title and its key fields flattened to plain text. The complete record always stays in the Apify dataset.

  1. Authorize a connector once under Apify, Settings, Integrations (Notion, Linear, Airtable, or Apify).
  2. Select it in the "Pipe results into your apps" input field. (If the picker is empty, you haven't authorized a connector yet.)
  3. For Notion, also set notionParentPageUrl to the page where records should be created.

The connection is mediated by Apify's MCP proxy, so this actor never sees your third-party credentials. Leave the field empty to skip.

Input Parameters

ParameterTypeDefaultDescription
modestringsearchsearch (location + filters) or url (paste Redfin links).
locationsarray["Chicago, IL"]Search mode only. Cities, ZIPs, neighborhoods or counties, e.g. "Chicago, IL".
listingTypestringfor_salefor_sale or sold (last 3 years).
sortBystringrecommendedrecommended, newest, price_low, price_high, sqft, lot_size, or price_per_sqft.
propertyTypesarray[] (all types)Keep only these property types (House, Condo, Townhouse, Multi-Family, Land, Manufactured).
minPriceintegerno default (optional)Only listings priced at or above this amount (search mode).
maxPriceintegerno default (optional)Only listings priced at or below this amount (search mode).
minBedsintegerno default (optional)Only listings with at least this many bedrooms (search mode).
minBathsintegerno default (optional)Only listings with at least this many bathrooms (search mode).
minSqftintegerno default (optional)Only listings with at least this much interior area (search mode).
urlsarrayone example of each supported shapeURL mode only. Redfin region or listing URLs; run-level filter fields are ignored (facets in a pasted /filter/... URL are applied). Running URL mode with this field untouched now scrapes the seven example URLs below instead of a single city.
fetchDetailsbooleantrueFetch each listing's detail panels for the agent, brokerage, valuation label, schools, amenities and public records. See "Detail enrichment and its cost" above for how this interacts with pasted listing URLs.
maxItemsinteger20The only cap on total results. Set 0 for unlimited.
maxPagesinteger0 (unlimited)Optional safety stop on result pages per location (350 listings per page). Does not cap totals; Max listings still decides.
resumeFromRunIdstringno default (empty)Optional. ID of a previous run or dataset of this actor; listings already there are skipped.
addressesarraynoneListings mode only. Street addresses; each is matched to its Redfin listing, and an address with no match is logged as an error (the run fails if nothing matches).
searchResultsDatasetIdstringnoneListings mode only. Dataset ID of a previous run; every listing URL in it is fetched again.
incrementalModebooleanfalseTrack this exact search or URL list across scheduled runs and classify every listing NEW / UPDATED / UNCHANGED / REAPPEARED / EXPIRED.
stateKeystringno default (auto-derived)Optional name for the saved baseline. Leave empty and one is derived from your search settings.
emitUnchangedbooleanfalseAlso return (and bill) listings that did not change since the last run.
emitExpiredbooleanfalseAlso return (and bill) a row for listings tracked before that are gone this run, once a complete scan proves it.
ignoreFieldsForChangesarray[]Field names or dotted paths excluded from UPDATED detection (incremental mode only).
proxyobjectApify ProxyConnection settings. Region pages, pasted URLs and detail enrichment need a residential connection (see Plan Requirement).
maxResidentialMBinteger0 (unlimited)Cap residential traffic in MB; the run auto-downgrades to the lower-cost tier after the cap.
mcpConnectorsarrayno default (empty)Optional. Pipe results into Notion, Linear, Airtable, or Apify via MCP.
notionParentPageUrlstringno default (empty)Optional. Parent page for a selected Notion connector.
maxNotifyListingsinteger50Optional. Cap how many listings are pushed to the connectors.

Output Example

Sample shape: values are illustrative placeholders, not from a live listing.

{
"id": 12345678,
"propertyId": 12345678,
"listingId": 200000000,
"url": "https://www.redfin.com/IL/Chicago/123-Example-St-60601/home/12345678",
"mlsId": "mred00000000",
"mlsStatus": "Active",
"status": "Active",
"price": 575000,
"priceType": "List price",
"pricePerSqFt": 311,
"hoaDues": 250,
"beds": 3,
"baths": 2.5,
"bathFull": 2,
"bathPartial": 1,
"sqft": 1850,
"lotSize": 4200,
"stories": 2,
"yearBuilt": 1998,
"streetLine": "123 Example St",
"city": "Chicago",
"state": "IL",
"zip": "60601",
"latitude": 41.8781,
"longitude": -87.6298,
"propertyTypeLabel": "Condo/Co-op",
"daysOnMarket": 12,
"photos": "0-24:0",
"hasVirtualTour": false,
"keyFacts": [{ "description": "Large windows", "rank": 0 }],
"listingTags": ["Hardwood flooring"],
"listingRemarks": "Bright corner unit with lake views and an updated kitchen.",
"listingAgent": "Alex Example",
"brokerName": "Example Realty Group",
"mainHouseInfo": {
"fullStreetAddress": "123 Example St, Chicago, IL 60601",
"url": "https://www.redfin.com/IL/Chicago/123-Example-St-60601/home/12345678"
},
"schools": [{ "name": "Example Elementary", "rating": 8, "distanceMiles": 0.4 }],
"scrapedAt": "2025-01-01T00:00:00+00:00"
}

Output views

The dataset has three views in the Console: Listings overview (price, beds, baths, size, status, address), Listing detail (agent, brokerage, schools, amenities, public records, Redfin Estimate) and Changes (incremental) (changeType, changedFields, first and last seen).

Plan Requirement

Residential access is needed for part of the data. Redfin's region pages and listing detail pages sit behind a bot-verification wall that datacenter connections do not pass (they get a verification page or an empty answer). The bulk search feed answers on the lower-cost datacenter tier, but region pages, pasted URLs and detail enrichment need a residential connection, and results on those pages can be intermittent, so the actor retries on fresh connections inside a per-request time limit. Apify free plans do not include residential proxies; on a free plan the actor continues on a backup connection and some pages may still be unavailable. For full coverage use a paid Apify plan or supply your own proxy URLs.

What you will see in the run log and the failure message when access is limited:

  • Warning when the selected connection is unavailable: "The selected connection is unavailable to this run. Apify free plans do not include residential proxies. Continuing on a backup connection; some pages may still be unavailable."
  • Notice when pages were served over the backup: "Served over the backup connection (the default connection was unavailable)."
  • Failure when the proxy connection is refused: "The proxy connection was refused for this account, so no page could be read. Your Apify plan does not include proxy access; a paid plan is required."
  • Failure when residential is unavailable and the backup also fails: "No results: residential proxies are unavailable on this run (Apify free plans do not include them), and the backup connection could not load the requested Redfin pages."
  • Failure when every request failed: "Could not load any results page (the requests failed), so nothing was collected. This is a connection problem, not an empty search. Please try again later."

A blocked run fails loudly with one of these messages rather than finishing with an empty dataset. Use Residential traffic budget (MB) to cap residential traffic.

Billing

Three pay-per-event charges apply, each shown on the Pricing tab:

  • Listing result: once per dataset row returned.
  • Detail enrichment: once per listing that received full detail treatment (only when Fetch full listing details is on).
  • Actor Start: once per GB of run memory, minimum one, when the run starts.

Rows are charged when they are delivered. Unchanged listings in incremental mode are not returned or charged unless Emit unchanged rows is on. Use Max listings to cap a run.

FAQ

How much does it cost?

You pay per listing returned, plus a separate detail-enrichment charge for any listing that was given full detail treatment, which includes a pasted single-listing URL only when Fetch full listing details is on (the default). The Pricing tab shows the current rates. Use Max listings to cap the cost of any run.

This actor collects only publicly available listing data. You are responsible for how you use it: follow Redfin's terms and the laws that apply to you, and get legal advice if you plan commercial redistribution. Facts like price, beds and square footage are generally not protected, but photos, remarks and agent/brokerage details may be subject to third-party rights.

Can I get only new or changed listings on a schedule?

Yes. Schedule the actor from the Schedules tab and turn on Incremental mode. Each run then returns only new and updated listings, and unchanged ones are not billed unless you turn on Emit unchanged rows.

Why does a pasted listing URL return fewer fields than a search result?

Because fetching a single listing's detail panels is the only way to identify it directly, a pasted listing URL needs Fetch full listing details on (the default) to return anything beyond its id and URL; with it on, you get the detail-only fields (agent, brokerage, address, schools, amenities, public records, Redfin Estimate) but never the search-card fields (price, beds, baths, sqft, lot size, year built, city/state/zip, coordinates, photos, tags, remarks). Search by the address or ZIP instead if you need the full field set for one property.

Why did my run fail instead of returning an empty dataset?

If every request to Redfin was rejected, the run stops with a clear message so "no listings for this search" is never confused with "nothing could be read". Retry in a few minutes, or switch to a residential proxy group under Connection. If the site answered but genuinely has no matching listings, the run still succeeds and reports "No listings found" without billing anything for it.

Can I use it with AI agents or MCP?

Yes. Call it from any Apify integration or MCP client, and use the connector field to push results into Notion, Linear or Airtable.

๐Ÿ”— Want more real estate data?

Pair this actor with these related scrapers from the same team:

๐Ÿงฉ Zillow Scraper
Scrape zillow.com properties for sale, for rent and recently sold across the US: price...
๐Ÿงฉ Homes.com Scraper
Scrape US property records from Homes.com. Pick a city, state or ZIP and a channel (for...
๐Ÿ  Realtor.com
Extract property listings from realtor.com. Get comprehensive data, including prices...
๐Ÿ  Trulia Scraper
Scrape Trulia.com property listings by location, filters, or URL. Extract prices, beds...
๐Ÿ  Crexi Scraper
Scrape crexi.com commercial listings: asking price, cap rate, square footage, units, year...
๐Ÿ  NewHomeSource
Scrape new homes, floor plans, builders and communities from NewHomeSource.com. Search by...

๐Ÿ‘‰ Browse all abotapi scrapers

๐Ÿ’ฌ Support

  • ๐Ÿž Found a bug or a missing field? Open a ticket on the Issues tab. We usually reply within hours.
  • ๐Ÿ› ๏ธ Need another site, extra fields or a private build? Email contact@abotapi.com.
  • โญ Enjoying it? A quick review on the actor page helps other users find it.