Redfin Property Listings Scraper
Pricing
Pay per event
Redfin Property Listings Scraper
Scrape normalized US Redfin listings — for-sale, sold, and pending — with full MLS/geo field coverage and reliable pagination past Redfin's 350-result cap via price-bucket bisection, deduped by property ID.
Pricing
Pay per event
Rating
0.0
(0)
Developer
DevilScrapes
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
a day ago
Last modified
Categories
Share
🎯 What this scrapes
tri_angle/redfin-search is the Apify Store's volume leader for Redfin (36,722 runs / 633 users) but sits at 3.59★ on 7 reviews — a durable execution gap, not a fluke. The rest of the field is thinner still: rigelbytes/redfin-scraper (1,008 runs / 122 users, 0★) and lulzasaur/redfin-scraper (898 runs / 47 users, 0★) round out a weak set of alternatives with no meaningful traction to validate reliability at scale. We built this Actor to close the gap on the two failure modes that show up over and over in that 3.59★: (1) reliable pagination past Redfin's hard 350-result-per-call cap, via a price-bucket bisection technique with per-bucket fault isolation, so a dense metro doesn't truncate silently at 350; and (2) full confirmed-field coverage per listing — MLS id, days-on-market, exact geo, HOA presence, remarks/tags, open-house info, photos — not just price/beds/baths. Redfin search pages carry real anti-bot posture; we run every request through Redfin's own stingray/api/gis search endpoint the way a real browser session would, so you get the data without wiring up the retry and rotation logic yourself.
🔥 What we handle for you
- 🛡️ We rotate browser fingerprints —
curl-cffiimpersonates real Chrome / Firefox / Safari TLS handshakes so Redfin's search endpoint sees a browser, not Python. - 🌐 We rotate proxy sessions through Apify Proxy on every block or geo-mismatch — fresh session ID, fresh exit IP.
- 🔁 We retry with exponential backoff on
408 / 429 / 5xxand network errors — up to 5 attempts per request,Retry-Afterhonoured. - 🧱 We back off when Redfin rate-limits or geo-splashes us — a mismatched city/state response gets a session rotation and one retry before we skip it and move on, never silently returning wrong-city data.
- 🧊 We keep the dataset clean — Pydantic-validated rows, deduped by
property_idacross price buckets, ISO-8601 timestamps, JSON / CSV / Excel export straight from the Apify Console. - 💰 You pay only for results that land — Pay-Per-Event pricing, no data no charge (only the small
actor-startwarm-up fee).
💡 Use cases
- Investment deal screening — pull normalized for-sale listings across any Redfin metro, with days-on-market and price-per-sqft ready for comparables analysis.
- Sold-comp research — reconstruct recent sold prices for a neighborhood without the 350-listing cap silently truncating dense ZIP codes.
- iBuyer / PropTech analytics — feed a normalized MLS-status/geo/HOA schema straight into an acquisition or valuation pipeline.
- Agent lead-gen — track pending listings and open-house schedules across target markets.
⚙️ How to use it
- Click Try for free at the top of the page.
- Fill in the input form — most fields have sensible defaults.
- Click Start. Output streams into the run's dataset.
- Export from Storage → Dataset as JSON, CSV, or Excel — or fetch via the API.
📥 Input
| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
searchUrls | array | no | ['https://www.redfin.com/city/17420/CA/San-Francisco'] | Redfin search-page URLs copied from redfin.com (/city/, /zipcode/, /neighborhood/, /county/ shapes). Up to 25. One of… |
regionId | string | no | '—' | Direct region_id override — skips the search-page fetch. Required together with Region type + Market if Search URLs is… |
regionType | string | no | '—' | Direct region_type override. Required together with Region ID + Market if Search URLs is unset. |
market | string | no | '—' | Direct market slug override. Required together with Region ID + Region type if Search URLs is unset. |
status | string | no | 'for-sale' | for-sale, sold, or pending listings. |
maxResultsPerSearch | integer | no | 1000 | Cap on rows per Search URLs / direct-override entry; triggers price-bucket bisection past Redfin's 350-home cap. |
priceBucketMinWidthUsd | integer | no | 25000 | Bisection floor — stop splitting a price bucket further once its width would drop below this. |
proxyConfiguration | object | no | {'useApifyProxy': True, 'countryCode': 'US'} | Apify Proxy, pinned to the US. Default (datacenter) group only — never RESIDENTIAL (unavailable on the FREE plan). |
Example input
{"searchUrls": ["https://www.redfin.com/city/17420/CA/San-Francisco"],"status": "for-sale","maxResultsPerSearch": 8,"priceBucketMinWidthUsd": 25000,"proxyConfiguration": {"useApifyProxy": true,"countryCode": "US"}}
📤 Output
Every row is one dataset item.
| Field | Type | Notes |
|---|---|---|
property_id | string | propertyId — dedup key. |
listing_id | ['string', 'null'] | listingId. |
mls_id | ['string', 'null'] | mlsId.value. |
mls_status | ['string', 'null'] | mlsStatus. |
search_status | ['string', 'null'] | searchStatus. |
listing_type | ['string', 'null'] | listingType. |
property_type | ['string', 'null'] | propertyType. |
ui_property_type | ['string', 'null'] | uiPropertyType. |
price_usd | ['number', 'null'] | price.value. |
price_per_sqft_usd | ['number', 'null'] | pricePerSqFt.value. |
sqft | ['number', 'null'] | sqFt.value. |
lot_size_sqft | ['number', 'null'] | lotSize. |
beds | ['number', 'null'] | beds. |
baths | ['number', 'null'] | baths. |
hoa_fee_usd | ['number', 'null'] | hoa (often absent, non-condo). |
hoa_frequency_known | ['boolean', 'null'] | isHoaFrequencyKnown. |
year_built | ['integer', 'null'] | yearBuilt.value. |
days_on_market | ['integer', 'null'] | dom.value. |
time_on_redfin_ms | ['integer', 'null'] | timeOnRedfin.value. |
neighborhood | ['string', 'null'] | location.value. |
street_address | ['string', 'null'] | streetLine.value. |
unit_number | ['string', 'null'] | unitNumber. |
city | string | city. |
state | string | state. |
zip_code | ['string', 'null'] | postalCode.value. |
latitude | ['number', 'null'] | latLong.value.latitude. |
longitude | ['number', 'null'] | latLong.value.longitude. |
num_photos | ['integer', 'null'] | numPictures. |
photo_urls | array | photos.value, best-effort (empty OK). |
listing_url | string | https://www.redfin.com + url. |
status_ribbons | array | sashes[] (empty OK). |
key_facts | array | keyFacts[] (empty OK). |
listing_tags | array | listingTags[] (empty OK). |
listing_remarks | ['string', 'null'] | listingRemarks. |
is_redfin_listing | boolean | isRedfin. |
is_new_construction | boolean | isNewConstruction. |
sold_date | ['string', 'null'] | soldDate, ISO YYYY-MM-DD. |
open_house_start | ['string', 'null'] | openHouseStart. |
open_house_end | ['string', 'null'] | openHouseEnd. |
source_search_url | string | Which search_urls entry yielded this row. |
scraped_at | string | ISO-8601 UTC row-creation timestamp. |
Example output
{"property_id": "12345678","listing_id": "98765432","mls_id": "SF123456","mls_status": "Active","search_status": "Active","listing_type": "for-sale","property_type": "Single Family Residential","ui_property_type": "House","price_usd": 1250000.0,"price_per_sqft_usd": 850.5,"sqft": 1470.0,"lot_size_sqft": 3200.0,"beds": 3.0,"baths": 2.0,"hoa_fee_usd": null,"hoa_frequency_known": false,"year_built": 1948,"days_on_market": 12,"time_on_redfin_ms": 1036800000,"neighborhood": "Noe Valley","street_address": "123 Example St","unit_number": null,"city": "San Francisco","state": "CA","zip_code": "94114","latitude": 37.7502,"longitude": -122.4337,"num_photos": 32,"photo_urls": ["https://ssl.cdn-redfin.com/photo/1/bigphoto/example.jpg"],"listing_url": "https://www.redfin.com/CA/San-Francisco/123-Example-St-94114/home/12345678","status_ribbons": ["COMING SOON"],"key_facts": ["Central Air"],"listing_tags": [],"listing_remarks": "Charming Noe Valley home...","is_redfin_listing": false,"is_new_construction": false,"sold_date": null,"open_house_start": null,"open_house_end": null,"source_search_url": "https://www.redfin.com/city/17420/CA/San-Francisco","scraped_at": "2026-08-12T12:00:00+00:00"}
💰 Pricing
Pay-Per-Event — you pay only when these events fire:
| Event | USD | What it is |
|---|---|---|
actor-start | $0.02 | One-off warm-up charge per run |
result-row | $0.0025 | Per unique dataset item |
Example: 1 000 results at the rates above ≈ $2.52. No subscription, no minimum, no card to start — Apify gives every new account $5 of free credit.
🚧 Limitations
v1 covers US Redfin search results only — no Canada. Price history, tax/assessment records, and full agent-contact fields are not available in v1: they simply don't ship in the search-page payload this Actor reads, and pulling them means fetching Redfin's property-detail pages, which sit behind a real anti-bot challenge that a plain HTTP client can't clear. Rather than ship a flaky, half-working detail fetch, we scoped v1 to the rich search/listings endpoint only — every field confirmed there ships reliably, every field that isn't ships as null instead of a guess. Detail-page enrichment is a tracked v2 candidate once we've validated a browser-based path against it. Free-text/city-name search isn't supported (Redfin's autocomplete endpoint 403s); paste a search-page URL instead.
❓ FAQ
Do I need a Redfin account or API key?
No. This Actor scrapes Redfin's own publicly listed search-result data via the search page's embedded API call — no login, no API key.
How does this avoid Redfin's 350-result cap?
Every gis call is capped server-side at 350 homes regardless of what's requested. We bisect the price range into buckets (mpt=99 + min_price/max_price) and recurse until every bucket returns fewer than 350 homes, deduping by property ID across buckets.
Can I target a ZIP code or neighborhood instead of a city?
Yes — paste any /city/, /zipcode/, /neighborhood/, or /county/ search-page URL from redfin.com.
Does one bad search URL stop the whole run?
No — each entry is fault-isolated. A geo-mismatch or fetch failure on one entry is logged and skipped; the rest of the run continues.
💬 Your feedback
Spotted a bug, hit a weird edge case, or need a new field? Open an issue on the Actor's Issues tab on Apify Console — we ship fixes weekly and we read every report.