Redfin Scraper - MLS Property Listings, Rentals, Market Stats avatar

Redfin Scraper - MLS Property Listings, Rentals, Market Stats

Pricing

from $1.90 / 1,000 listings

Go to Apify Store
Redfin Scraper - MLS Property Listings, Rentals, Market Stats

Redfin Scraper - MLS Property Listings, Rentals, Market Stats

Redfin scraper with no pagination needed: 5876 Austin listings in one request where Redfin's own Download All export stops at 350. An unknown region answers HTTP 200 with homes in Seattle, so the state and ZIP of every row are checked against your address. Redfin property data, rentals.

Pricing

from $1.90 / 1,000 listings

Rating

0.0

(0)

Developer

Snow Leo Data

Snow Leo Data

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

7 days ago

Last modified

Share

Redfin Scraper: listings, rentals, property cards and market stats

Scrape Redfin by city, county, neighborhood or ZIP code and get one flat table: price, beds, baths, living area, lot, year built, status, days on market, MLS number, MLS description, agent, coordinates and the listing URL. Add the property card and the same row also carries the parcel number, county tax rate, schools, climate risk, walk and transit scores, building permits, zoning and the MLS feature list. No proxy, no browser, no API key.

Every number on this page comes from a run you can repeat. Where a number came from a specific Apify run, the run id is printed next to it.

One request returns the whole region, not one page

Redfin's search endpoint has no pagination at all. page_number=2 returns the first page byte for byte — checked in tests/test_live.py, which compares the property ids of both responses. The only lever that changes the answer is how many listings you ask for, and it goes far past what the website offers:

WhatListings
Redfin's own Download All CSV export350 (asking for more returns an 86-byte error)
Redfin's website search pages9 pages
This Actor, one request, Austin TX5,876 (run RwMCBkbuydliUVLHl)

Austin's whole for-sale inventory arrived in a single HTTP response and 5,876 rows were written in 11.7 seconds. That is 16.8 times the ceiling of the export Redfin gives you in the browser, and it costs one request, not 17.

Sixty-three columns, already unwrapped

Redfin wraps almost every number in an object:

{"price": {"value": 769000, "level": 1}}
, {"sqFt": {"value": 3081}}, {"latLong": {"value": {...}}}. Dumped straight into a spreadsheet those cells read [object Object], and in pandas every column needs unpacking by hand.

This Actor unwraps them once: price, price_per_sqft, sqft, lot_size_sqft, beds, baths, year_built, latitude, longitude and the rest arrive as plain numbers and strings. A live Austin row carries 63 columns, 47 of them filled; across 350 Austin listings 62 of the 63 columns were filled on at least one row. The untouched Redfin object is still available under raw if you switch it on.

Two details that decide whether a number can be trusted:

  • A price the MLS refuses to publish becomes null, never 0. Redfin marks it with hideSalePrice, and turning that into a zero would quietly drag down every average you compute.
  • listing_remarks — the MLS description — arrives with HTML entities expanded and whitespace squeezed. On a live Austin response 332 of 350 listings carried a description, so you rarely need the property card just for text.

The property card: 97 columns instead of 63

Switch on Fetch the full property card and each listing is also read from its own Redfin page. A measured Austin card row carried 97 columns, 83 of them filled (run yIzgvb1E2Hd1DB7Pl), adding data that the search response simply does not have:

  • parcel number (apn) and FIPS code;
  • county name and the county property tax rate (1.6488% on the measured listing), plus a home insurance estimate;
  • listing agent, brokerage, MLS feed name, when the listing was last updated;
  • the agent's full description;
  • schools serving the address with grades and distance;
  • flood, fire, heat, wind and air-quality risk scores;
  • walk, bike, transit, car, quiet and greenery scores;
  • building permits on the parcel (18 on the measured listing) and zoning;
  • the MLS feature list, flattened (24 entries on the measured listing);
  • photo links and price history where Redfin publishes them.

The strongest Redfin Actor in the store has no property card at all: its own README carries a commented-out line promising a detail scraper "when we get it". That is the single biggest gap this Actor closes — with an honest ceiling: Redfin's WAF locks the address after the first handful of pages, so 11 of 15 cards arrived in a 61-second measured run and the rest were delivered without cards. The full story is under Limitations.

Rentals and regional market statistics

Rentals come from Redfin's separate rental feed: rent range, bedroom and bathroom range, area range, units available, building name, the leasing phone number and the feed source. The source caps this feed at 350 buildings per region.

Region market statistics are one extra row per location, from Redfin's own regional numbers rather than anything computed here: median list price, median sale price, median list and sale price per square foot, median sale-to-list ratio, average offers, average down payment, homes sold, homes on market, average days on market, Redfin's compete score, the number of Redfin and partner agents with their review rating, and today's mortgage rates (30-year fixed, 15-year fixed, FHA, VA). Measured for Austin: 4,772 homes on market, median sale price $535K, compete score 47, 30-year fixed 7.125%.

The source lies when you get the region wrong, so the Actor checks

Ask Redfin for a region id that does not exist and it does not say so. It answers HTTP 200, errorMessage: "Success" — and homes in Seattle. Measured with probe run WEi9cAcqZcKvbcaEf and again in tests/test_live.py: an unknown region id returned 20 listings, every one of them in Washington.

That is the worst kind of data corruption, because it looks like success. So every region you paste is checked: the state and, for ZIP codes, the ZIP of the returned listings are compared against the address you gave, and mismatched rows are dropped with a named reason instead of being handed to you as your market. The check can be switched off, and then you get exactly what Redfin said.

Filters run inside the Actor, before you are charged

Redfin ignores filter parameters sent to its open search endpoint. 8 different combinations — min_price, max_price, num_beds, uipt, sold_within_days, poly, include=sold-3mo, sf — returned a body identical to the byte: 1,041,701 bytes each time. Sending those parameters and calling them filters would be selling you a switch that is not wired to anything.

So every filter here runs in the Actor, on the collected rows, before a row is written to the dataset. With pay-per-result pricing that is in your favour: a row dropped by a filter is never written and never charged.

Available filters: price range, bedrooms range, minimum bathrooms, living area range, minimum lot, year built range, property type (Redfin's own 8), max days on market, only with an open house, only new construction, only with photos, address contains, description contains, label contains, and three that need the property card — minimum walk score, minimum transit score and minimum permits.

Two rules the filters obey, each one written after a measured accident on a neighbouring Actor:

  1. A missing field passes the filter. Absence of data is not a mismatch. A listing whose price the MLS withholds is not the same thing as a listing priced below your minimum.
  2. The row limit counts delivered rows, not collected ones. Ask for 30 rows with a narrow filter and you get 30 rows, not 30 candidates of which two survive.

Monitor mode: pay for what changed, not for the same table again

Switch on Only new or changed listings and the Actor remembers every listing it has delivered in a named key-value store. On the next run it writes only the listings that are new or whose price, status, beds, baths, area, price per square foot, HOA, open house, agent or rent range moved. Each row carries change_type (NEW / UPDATED / UNCHANGED) and, when something moved, changed_fields with the value before and after.

Measured in the cloud on ZIP 78704: the first run delivered 358 listings (run hKHGwuPHN3VQjlgLC), the second run delivered 0 rows and said why (run fPeW7fNZRcIIK6IDa) — nothing-changed, written in the log and in the REPORT record. A monitoring run that legitimately has nothing to report is not a failure, and it should not cost you a second full table.

The fingerprint deliberately ignores noisy fields. Redfin's timeOnRedfin counter grows every second; hashing the whole row would mark every listing as changed on every run and turn monitor mode back into a plain dump.

An empty dataset always says why

A green run with an empty dataset is the worst outcome for a buyer: the start was paid for and nothing explains the silence. This Actor names the reason in the log and in the empty_reason field of the REPORT record, and the reasons that can be worked out from your input alone are decided before a single byte is fetched:

There are 17 named reasons in all, and 12 of them are decided from the input alone, before the first request:

no-location-given, all-locations-invalid, price-range-is-empty, beds-range-is-empty, sqft-range-is-empty, year-range-is-empty, property-type-filter-in-rental-mode, open-house-filter-in-rental-mode, detail-only-filter-without-details, property-type-not-recognised, property-mode-without-property-urls, charge-limit-reached.

And the ones that only become visible after the fetch: filtered-out, nothing-changed, source-returned-nothing, all-locations-unreachable, region-check-failed.

The three input pairs worth naming, because each one guarantees zero rows: a property-type filter in rental mode (Redfin's rental feed has no property type), an open-house filter in rental mode, and a walk-score, transit-score or permit filter with the property card switched off. Each is refused up front with a sentence saying what to change — not after downloading several megabytes on your time.

What you paste in, and what you get back

Locations accepts:

  • a city page — https://www.redfin.com/city/30818/TX/Austin;
  • a county page — https://www.redfin.com/county/2866/TX/Travis-County;
  • a neighborhood page — https://www.redfin.com/neighborhood/.../Allandale;
  • a ZIP page — https://www.redfin.com/zipcode/78704 — or just 78704;
  • a single property — /TX/Austin/3915-Idalia-Dr-78749/home/31804526;
  • a Redfin search URL with filters on it, such as /city/30818/TX/Austin/filter/min-price=800k — the region is taken from it;
  • an explicit type:id pair, e.g. 6:30818, for a region whose page you do not have at hand.

A bare ZIP code is resolved by reading Redfin's own ZIP page and taking the region id out of it, because Redfin's address autocomplete endpoint answers 403 to every datacenter address — measured with browser headers and without.

You can also chain this Actor behind another one: give it a dataset id and the field holding a URL, and every item becomes a location.

How to use it in three steps

  1. Open Redfin in your browser, search the area you care about, and copy the address bar. That URL is the input.
  2. Choose what to collect: homes for sale, rentals, property cards, or region market statistics. Set Max rows; leave it at 0 for everything.
  3. Run it. Export to CSV, Excel, JSON or hook the dataset into your own code through the Apify API.

For a daily watch, set Only new or changed listings, put the run on a schedule, and read change_type and changed_fields.

Limitations, stated plainly

  • Sold and off-market homes are not available. Redfin's open search endpoint drops every filter parameter, sold_within_days and include=sold-3mo included — measured, identical response bytes. This Actor returns what that endpoint returns: homes currently on the market. It does not pretend to filter server-side.
  • Property cards are rate limited by Redfin, and the Actor stops rather than grind. After the first handful of property pages, Redfin's WAF answers HTTP 202 with a 2,448-byte challenge page and the header x-amzn-waf-action: challenge. Browser-shaped headers change nothing — 12 header fields were tried, same refusals (probe run Lmn01ZLPoLPCM2eFm). The Actor paces itself at one page every two seconds, retries once, and after three refusals in a row stops asking for cards and keeps delivering listings with their search fields. Measured on the finished build (run xJxWTKXRKWVVA7hTE): 11 cards of 15 requested arrived in 61 seconds, then the address was locked and the remaining rows were delivered without cards. An earlier build that kept retrying spent 537 seconds to get 6 cards (run L7TsznKdX8gywSb4V), which is why it now stops. Use the card mode for shortlists — a few dozen addresses — not for a whole city.
  • City by name is not supported, because Redfin's autocomplete is closed to datacenter addresses (403) and so are its sitemaps. Paste the city page URL or a ZIP code instead.
  • Rentals are capped at 350 buildings per region by the source, not by this Actor, and rental rows have no property type, no open house and no MLS number.
  • Price history and photo links appear only where Redfin publishes them. In non-disclosure states much of the history is withheld, and the property card will show fewer fields there.
  • The region check needs a hint. If you pass an explicit type:id pair there is no city or ZIP to compare against, so the check passes by default.
  • This Actor is not affiliated with, endorsed by or connected to Redfin. It reads pages and endpoints that any visitor can read, and it collects no personal data beyond what the MLS publishes about a listing: the agent's name and brokerage.

Frequently asked questions

How many listings can I get from one city? As many as Redfin has on the market there. Austin returned 5,876 in a single request. The only cap is Listings to ask Redfin for, per location, which defaults to 2,000 and goes to 20,000.

Is there a page limit like the website's nine pages? No. The website's paging does not exist at the endpoint level: page two returns page one. This Actor asks for the whole region at once.

Why are the filters applied by the Actor and not by Redfin? Because Redfin ignores them. 8 filter combinations returned byte-identical responses. Filtering here means filtering before billing, which is cheaper for you than filtering after.

Does it need proxies or a browser? No. Every endpoint it uses answers a plain HTTPS request from Apify's own addresses. That is why the run costs cents and finishes in seconds.

Can I monitor a ZIP code every morning? Yes. Switch on Only new or changed listings and schedule the run. A morning with no changes writes zero rows and says nothing-changed in the REPORT record.

What happens if I paste something that is not a Redfin address? It is skipped, listed in the REPORT record with the reason, and the run continues with whatever else you gave. If nothing is left, the run stops before any request with all-locations-invalid.

Can I get the agent's phone number? For rentals, yes — the leasing phone is part of the feed. For homes for sale Redfin publishes the agent's name and brokerage, not a direct phone, and this Actor does not invent one.

How do I pull everything into my own system? Every run writes a dataset you can read through the Apify API in JSON, CSV, Excel or XML, and the last row is a REPORT record with counts, the filters that were active, the regions used and, when the dataset is empty, the reason why.

Output example

{
"source": "redfin",
"mode": "for_sale",
"property_id": 31487394,
"url": "https://www.redfin.com/TX/Austin/2701-Richcreek-Rd-78757/home/31487394",
"address": "2701 Richcreek Rd, Austin, TX 78757",
"city": "Austin",
"state": "TX",
"zip": "78757",
"neighborhood": "Allandale Park",
"latitude": 30.3519645,
"longitude": -97.7379262,
"price": 1999000,
"price_per_sqft": 644,
"beds": 4,
"baths": 3,
"sqft": 3104,
"year_built": 2022,
"property_type": "House",
"status": "Coming Soon",
"days_on_market": 1,
"mls_number": "2192874970196828361",
"photo_count": 19,
"key_facts": ["Garage", "Pool", "Built 2022"],
"labels": ["EARLY ACCESS", "COMPASS COMING SOON"],
"region_label": "Austin, TX"
}

What else is this called?

Other names for the fields in a row: Redfin estimate versus list price (redfin_estimate), income restricted housing data (is_income_restricted), military housing listings (is_military_housing), wildfire risk home data (risk_fire_score), lot size acreage data (lot_size_sqft), housing market statistics export (includeMarketStats), cumulative days on market, student housing and senior living listings, 3D tour listings (has_3d_tour), HOA monthly fee (hoa_month), zoning code lookup, hot home indicator (is_hot), garage spaces parking data, school ratings near a listing (schools).