Realtor.com Scraper
Realtor.com listings as JSON, by city, ZIP or county. Fields: address, price, beds, baths, sqft, year built, days on market, agent, broker. $0.68/1k.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
location,startUrls,listingStatus(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.00068 per property listing = $0.68 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Property listing | Charged once per property listing returned. $0.68 per 1,000 listings. Diagnostics and empty results are never charged. | $0.00068 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2020-01-01, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
location | Where to search on Realtor.com. One per line. Accepts "City, ST" (Austin, TX), a 5-digit ZIP (78704), a county ("Travis County, TX"), a neighborhood ("Zilker, Austin, TX") or a state code (TX). United States only. | array |
startUrls | Optional. Paste Realtor.com search pages (https://www.realtor.com/realestateandhomes-search/Austin_TX) or single property pages (https://www.realtor.com/realestateandhomes-detail/..._M84963-61588). Filters written into the URL (price-, beds-, type-, show-recently-sold) are honoured. Works alongside "location". | array |
listingStatus | Which listings to return. "sold" covers recently sold homes; "off_market" covers homes no longer listed. | string |
propertyTypes | Optional. Leave empty for every type. Note that Realtor.com's own value is "condos" (plural), "condo" matches nothing. | array |
maxItems | Hard cap on rows returned across every location and URL. You are charged once per listing returned. Realtor.com's API cannot page deeper than 10,000 results per search, split by ZIP code to go beyond that. | integer |
sortBy | Order the listings come back in. | string |
includePropertyDetails | Adds the listing description text, tax history, price history, nearby schools and value estimates to every row. Costs one extra request per listing, so the run is slower. It adds fields, never extra rows, so it does not change what you are charged. | boolean |
maxPhotos | How many photo URLs to keep per listing (0-50). Realtor.com returns up to 50. | integer |
priceMin | Optional lowest list price. | integer |
priceMax | Optional highest list price. | integer |
bedsMin | Skip anything with fewer bedrooms than this. Leave empty for no lower bound. | integer |
bedsMax | Skip anything with more bedrooms than this. Leave empty for no upper bound. | integer |
bathsMin | Skip anything with fewer bathrooms than this. Leave empty for no lower bound. | integer |
sqftMin | Smallest living area to keep, in square feet. Listings that do not publish a size are kept either way. | integer |
sqftMax | Largest living area to keep, in square feet. Listings that do not publish a size are kept either way. | integer |
lotSqftMin | Optional. 1 acre = 43,560 sqft. | integer |
yearBuiltMin | Keep only homes built in this year or later. Leave empty to ignore the build year. | integer |
yearBuiltMax | Keep only homes built in this year or earlier. Leave empty to ignore the build year. | integer |
listedWithinDays | Optional. Only listings first posted in this window. Use with status "For sale". | integer |
soldWithinDays | Optional. Only homes sold in this window. Use with status "Recently sold". | integer |
hasOpenHouse | Keep only listings with an open house already on the calendar. Off returns everything. | boolean |
newConstruction | Keep only new builds. Off returns new and resale together. | boolean |
foreclosure | Keep only foreclosures. Off returns everything, foreclosures included. | boolean |
keywords | Optional. Words that must appear in the listing, for example "pool", "waterfront", "garage". | array |
What you get
A structured dataset — each result includes fields like:
addresscitystateCodepostalCodepricebedsbathssqftlotSqftpropertyTypeyearBuiltlistingStatusdaysOnMarketagentNamebrokerNamelatitudelongitudephotoCounturlExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
Related tools in Real Estate & Classifieds
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
Craigslist Scraper
Scrape Craigslist listings by city, category and keyword: id, title, price, neighborhood, date, images and URL. No account or API key. $0.85 per 1,000.
Airbnb Listings Scraper
Scrape Airbnb listings by location, dates and guests. Get listing ID, name, room type, price, rating, reviews and host. No account, no API key.
Avito Listings Scraper
Scrape Avito.ru listings by keyword, category or city. Get id, title, price, seller name and type, publish date and photos. $0.30 per 1,000 listings.
Facebook Marketplace Scraper
Scrape Facebook Marketplace listings by keyword and city. Rows carry title, price, currency, location, link, posted date, sold status.
Zillow Scraper
Scrape Zillow search results and full listing details: price, beds, baths, sqft, photos, price history, schools. No login or API key. $0.0008 per property.
Where this tool sits
- Categories
- Real Estate & Classifieds
- Platforms
- Realtor.com
Realtor.com Scraper: US home listings by city, ZIP, county or a URL you paste
Type a location and every matching listing comes back as a row: address, price, beds, baths, square feet, lot size, property type, year built, status, days on market, the listing agent and broker, and the photos. For sale, for rent, recently sold, off market or ready to build.
The awkward part first. daysOnMarket counts from the list date on every row, whatever the status. On a sold or off-market listing that number keeps growing after the sale, so it is days since listing rather than days it was actually on the market. Use listDate and lastSoldDate when the difference matters.
| Input | Cities, ZIPs, counties, neighbourhoods or state codes, or Realtor.com URLs |
| Output | One row per listing |
| Ceiling | 10,000 listings per run, and Realtor.com will not page deeper than 10,000 per search |
| Account needed | None, and nothing to install |
| Price | $0.68 per 1,000 listings, flat on every plan |
🏷️ What Realtor.com Scraper does
Location takes Austin, TX, a five-digit ZIP, Travis County, TX, a neighbourhood like Zilker, Austin, TX, or a bare state code. One per line, and the whole run shares one budget and one duplicate check, so the same home found under two of your searches is delivered once.
Do not put a street address in there. It gets resolved to the area around it and searched as an area, so you would be billed for a neighbourhood's listings instead of the one house. Paste the property URL into Realtor.com URLs instead, which looks that one property up.
Pasted URLs keep their own filters. Price, beds, type and show-recently-sold written into a Realtor.com search URL are honoured, and search pages and single property pages both work.
Then there are the filters, and there are a lot of them: status, property type, price, beds, baths, living area, lot size, year built, how recently it was listed or sold, open houses, new builds, foreclosures, and keywords that have to appear in the listing.
One gotcha worth knowing: Realtor.com's own value is condos, plural. condo matches nothing.
📥 What you give it
{
"location": ["Austin, TX"],
"listingStatus": "for_sale",
"propertyTypes": ["single_family"],
"priceMax": 600000,
"bedsMin": 3,
"sortBy": "newest",
"maxItems": 200
}
| Field | Default | What it is |
|---|---|---|
location | box starts at Austin, TX | Where to search. City, ZIP, county, neighbourhood or state code. US only. |
startUrls | none | Realtor.com search pages or single property pages, pasted from the site. |
listingStatus | for_sale | Also for_rent, sold, off_market, ready_to_build. |
propertyTypes | every type | single_family, condos, townhomes, multi_family, mobile, land, farm and the combined condo_townhome_rowhome_coop. |
sortBy | newest | Also oldest, price_low, price_high, sold_date, most_photos. |
priceMin, priceMax | none | List price bounds in dollars. |
bedsMin, bedsMax, bathsMin | none | Room counts. |
sqftMin, sqftMax, lotSqftMin | none | Living area and lot size in square feet. One acre is 43,560. |
yearBuiltMin, yearBuiltMax | none | Build year bounds. |
listedWithinDays | none | Only listings first posted in this window. Pair it with For sale. |
soldWithinDays | none | Only homes sold in this window. Pair it with Recently sold. |
hasOpenHouse, newConstruction, foreclosure | off | Each keeps only that kind when switched on. |
keywords | none | Words that must appear in the listing, like pool or waterfront. |
includePropertyDetails | off | Adds description, tax history, price history, schools and value estimates. One extra request per listing, no extra charge. |
maxPhotos | 30 | Photo URLs to keep per listing, 0 to 50. |
maxItems | 50 | Total listings across every location and URL, up to 10,000. |
proxyConfiguration | leave it alone | Optional, under Network. Only the proxyUrls you type in are read. |
📤 What you get back
A real row from a run on 14 September 2026, with the feature list cut short:
{
"propertyId": "9843409442",
"listingId": "3000701603",
"url": "https://www.realtor.com/realestateandhomes-detail/5009-Monarda-Mint-Dr_Austin_TX_78754_M98434-09442",
"address": "5009 Monarda Mint Dr",
"addressWithheld": false,
"city": "Austin",
"stateCode": "TX",
"state": "Texas",
"postalCode": "78754",
"county": "Travis",
"countyFips": "48453",
"latitude": 30.367015769780284,
"longitude": -97.62425231789224,
"price": 490222,
"pricePerSqft": 199,
"priceReducedAmount": null,
"lastSoldPrice": null,
"lastSoldDate": null,
"estimatedValue": null,
"hoaFee": null,
"beds": 4,
"baths": 3,
"bathsFull": 2,
"bathsHalf": 1,
"sqft": 2466,
"lotSqft": null,
"yearBuilt": null,
"propertyType": "single_family",
"stories": 2,
"garage": 2,
"listingStatus": "for_sale",
"listDate": "2026-09-14T00:01:29.000000Z",
"daysOnMarket": 0,
"lastUpdateDate": "2026-09-14T00:01:29Z",
"isNewListing": true,
"isPending": false,
"isForeclosure": false,
"isNewConstruction": true,
"agentName": "Cameron Place",
"agentEmail": null,
"brokerName": null,
"brokerPhone": null,
"mlsSourceId": "PULB",
"mlsSourceType": "new_home",
"photoCount": 1,
"primaryPhoto": "http://nh.rdcpix.com/9c50d77ff4f6b0ce0b3c083f6a478599l-f1836003418s.jpg",
"photos": ["http://nh.rdcpix.com/9c50d77ff4f6b0ce0b3c083f6a478599l-f1836003418s.jpg"],
"virtualTourUrl": null,
"hasMatterport": false,
"openHouses": [],
"features": ["new_construction", "two_or_more_stories", "garage_2_or_more", "kitchen_island", "..."],
"searchLocation": "Austin, TX",
"resolvedLocation": "Austin, TX",
"position": 1,
"scrapedAt": "2026-09-14T05:46:06.308Z"
}
| Field | What it is |
|---|---|
address / addressWithheld | null when the listing hides the address. The flag tells you which it is. |
lastSoldPrice, lastSoldDate | Empty in non-disclosure states, where sale prices are not public at all. |
daysOnMarket | Days since listDate, on every status. See the note at the top. |
agentEmail, brokerEmail, brokerPhone | Present only when the listing carries them, which is not often. agentName and brokerName are far more reliable. |
features | Realtor.com's own tag list, like kitchen_island and covered_patio. |
searchLocation / resolvedLocation | What you asked for, and what Realtor.com decided that meant. Worth checking when a result set looks wrong. |
propertyDetails, taxHistory, priceHistory, schools, valueEstimates, descriptionText | Only with includePropertyDetails on. |
🧾 Reading the output
| Row | How to spot it | Billed |
|---|---|---|
| A listing | It has a propertyId and no ok key | yes |
| The sample row | _sample: true and charged: false | no |
| A diagnostic | ok: false, _diagnostic: true and an errorCode | no |
Listing rows carry no charged field. The flag is only on the sample and diagnostic rows, to mark them as not real results.
| Code | What it means |
|---|---|
LOCATION_NOT_FOUND | Realtor.com did not resolve that location. |
NO_RESULTS | The search ran and matched nothing. |
RESULT_CAP | The search matched more than Realtor.com will page through. Narrow it. |
PROPERTY_NOT_FOUND | A pasted property is no longer on the site. |
BAD_URL | A link that is not a Realtor.com search or property page. |
UNKNOWN_PROPERTY_TYPE | A property type that is not one of Realtor.com's own values. |
BLOCKED, NETWORK_ERROR, API_ERROR, GRAPHQL_ERROR, BAD_SEARCH_ERROR | Realtor.com did not answer with usable data. |
A failure part way through paging keeps the rows already delivered and adds a diagnostic, so you can tell a short result from a complete one.
▶️ How to run it
1. Open Realtor.com Scraper and click Try for free. 2. Type a city, ZIP or county into Location, one per line. 3. Pick a Listing status and any filters you want under Filters. 4. Set Maximum listings. Start around 25 to see what the rows look like. 5. Click Start, then download the dataset as JSON, CSV or Excel, or read it from the Apify API.
💰 How much does it cost?
$0.68 per 1,000 listings. Flat on every Apify plan, with no volume tiers.
One billed row per listing delivered. The sample row is not billed, diagnostic rows are not billed, the same home found under two of your searches is billed once, and includePropertyDetails adds fields rather than rows so it does not change the price.
💡 What people use it for
- Comps and valuation work, pulling sold listings in one ZIP with
soldWithinDaysset. - Agent and broker lead lists, grouped on
brokerNameacross a metro. - Watching new supply daily with
listedWithinDaysat 1, diffing onpropertyId. - Investment screens:
foreclosureon, a price ceiling, andpricePerSqftto rank what comes back. - Rental market snapshots by switching status to For rent and holding the rest of the filters.
🚧 What it does not do
- United States only. Realtor.com does not cover anywhere else.
- No more than 10,000 results per search. That is Realtor.com's paging depth, not ours. Split by
ZIP to go deeper, and watch for the RESULT_CAP row.
daysOnMarketis days since listing on every status, so it keeps counting after a sale.- No sale prices in non-disclosure states.
lastSoldPriceis empty there because the number is
not public.
- Agent and broker emails are rarely published. Do not plan an email campaign around them.
- A street address in Location is treated as an area. Paste the property URL instead.
- A location lookup that fails comes back as not found. If you know the place exists, re-run
rather than concluding Realtor.com has never heard of it.
🧭 Which property scraper do you need?
| If you want | Use |
|---|---|
| US listings, sold prices and agents from Realtor.com | This one |
| US listings from Zillow, search and full details | Zillow Scraper |
| Homes in Spain, Italy and Portugal | Idealista Scraper |
| Homes in Spain from Fotocasa | Fotocasa Scraper |
| Brazilian listings from VivaReal and ZAP | VivaReal & ZAP Imóveis Scraper |
❓ Questions people ask
How do I get recently sold homes? Set Listing status to Recently sold and use Sold within the last N days. Read lastSoldPrice and lastSoldDate, not daysOnMarket.
How do I get more than 10,000 listings for a city? Split the city into its ZIP codes and put them all in Location in one run. The duplicate check is shared, so overlapping areas cost once.
Can I look up one specific home? Yes. Paste its Realtor.com property URL into Realtor.com URLs.
Why did my condo filter return nothing? Realtor.com's value is condos, plural. Pick it from the list rather than typing it.
Can I schedule it? Yes. propertyId is stable, so diffing one run against the next shows what came on and what went under contract.
Is this legal? These are public listing pages. Agent names are personal data, so have a reason for collecting them. Apify's write-up on scraping and the law is a good starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the location or URL you used and the run ID. The errorCode on the diagnostic row usually names the problem on its own.