๐ŸŽ‰ Premium Proxies ยท 24-Hour Free TrialClaim Now
Guides

How to Scrape Realtor.com Listings and Agent Data

Learn how to scrape Realtor.com listings at scale: extract properties, prices, agents, and market data from its hidden JSON and beat PerimeterX blocks.

S SparkProxy 0 28 min read
Share
How to Scrape Realtor.com Listings and Agent Data

To scrape Realtor.com listings at any real scale, parsing is the easy part. Two things decide whether your pipeline works: where Realtor.com hides its structured data, and how you survive its bot wall. The site ships every property, price, and agent record as JSON inside the page and behind a private GraphQL backend, and it runs PerimeterX, the same behavioral wall you meet on Zillow. This guide stays on the keyboard. You'll get the exact field map for properties, prices, and agents, where the data actually lives in the page, how to page through a full metro without slamming into the result window, how to clear the "Press and Hold" challenge, and working Python against SparkProxy's Scraping API. It's the Realtor.com-specific companion to our general guide to scraping real estate listings, so here we go deep on what makes this portal different.

What you'll build

  • A field map for list price, beds, baths, sqft, lot size, agent, brokerage, and MLS source
  • A parser that reads Realtor.com's embedded initialReduxState JSON instead of fighting selectors
  • A search sweep over realestateandhomes-search that survives the ~10,000-result window
  • Card extraction that anchors on data-testid, not class names that change every build
  • An anti-bot escalation ladder so a Press and Hold wall doesn't end the run

Scrape responsibly: public data, MLS licensing, and Fair Housing

Set the boundary before any code. Scraping listing data that any anonymous visitor can load on a public Realtor.com page sits on reasonably defensible ground, and US courts have repeatedly declined to treat access to public web pages as unauthorized access under the CFAA (the hiQ v. LinkedIn line of cases is the usual reference). That is not a blank check. Four rules keep you clear:

  • Public pages only. Don't touch anything behind a login, a saved-search account, or an agent dashboard. Bypassing authentication is a separate legal category with real exposure.
  • Realtor.com is an MLS licensee, not the source. The site is operated by Move, Inc., a News Corp subsidiary, and its inventory is licensed from hundreds of regional Multiple Listing Services under RESO and MLS rules. Those licenses restrict redistribution. Using price and inventory data for internal analysis is one risk profile. Rebuilding a competing listings portal from scraped MLS rows is a very different one.
  • Fair Housing attaches the moment data drives decisions. If scraped listings, prices, or neighborhood signals feed a model that screens tenants, sets rents, or targets housing ads, the Fair Housing Act and its disparate-impact standard apply. Keep protected-class proxies, including raw neighborhood demographics, out of any automated decision.
  • Agent contact data is personal data. Realtor.com attaches agent and broker names, phones, and emails to most listings. Sweeping those into a cold-outreach list runs into CAN-SPAM, state privacy law, and the site's own terms. Store what you need for provenance, not a marketing database.

The rest of this guide assumes you're collecting public listing data for internal analysis. For the broader compliance framework on MLS licensing and Fair Housing when scraped data feeds automated systems, see our real estate data aggregation guide. For anything you plan to publish or resell, get legal sign-off first.


What a Realtor.com listing exposes

Decide your schema up front. Retrofitting a field after you've scraped 200,000 pages means re-scraping. Realtor.com's internal data uses a vesta schema whose field names look nothing like Zillow's camelCase, so here's the reference most Realtor.com pipelines converge on, with the type and the gotcha that bites people.

FieldData typeExample valueNotes
`property_id`string`M1234-56789`Realtor.com's stable id (the `M...` token in the detail URL). Your primary key.
`listing_id`string`2960884471`The current MLS listing instance. It changes on relist, so key on `property_id`, not this.
`list_price`integer`459000`Current asking price. Null on some "contact for price" or off-market rows.
`status`string`for_sale``for_sale`, `ready_to_build`, `sold`, `off_market`, `other`. Drives whether the row is live.
`description.beds`integer`3`Bedroom count. Missing on land.
`description.baths_consolidated`string`2.5`Baths arrive as a string with the fraction. Keep the half bath, it matters for comps.
`description.sqft`integer`1840`Interior area. Do not confuse with `lot_sqft`.
`description.lot_sqft`integer`7405`Lot size in square feet. Convert to acres yourself.
`description.year_built`integer`1998`Missing on new construction and raw land.
`description.type`string`single_family``single_family`, `condos`, `townhomes`, `multi_family`, `land`, `mobile`. Already normalized.
`location.address`object`{line, city, state_code, postal_code}`Street, city, two-letter state, ZIP.
`location.coordinate`object`{lat, lon}`Exact coordinates, straight from the JSON. No geocoding needed.
`list_date` / `last_update_date`ISO datetime`2026-06-14T...`Days-on-market math and change detection.
`flags`object`{is_price_reduced, is_pending, is_new_listing, is_foreclosure}`Boolean demand signals in one bag.
`advertisers`array`[{name, type, email, phones, office}]`The agent and brokerage records. `type` is `agent`, `office`, or `builder`. Your "agents" payload.
`source` / `mls`object`{name, abbreviation, plan_id}`Which MLS the row came from. Provenance you'll want for licensing and dedupe.
`price_history`array`[{date, event_name, price}]`Listing, sold, and price-change events. The seller-motivation signal.
`tax_history`array`[{year, tax, assessment{building, land, total}}]`Annual tax and assessed value. A value anchor.
`schools`array`[{name, rating, distance_in_miles}]`Assigned and nearby schools with ratings.

Two clusters carry more weight than the rest. The advertisers array plus source.mls is the reason to scrape Realtor.com over Zillow specifically: you get the listing agent, the brokerage, and the originating MLS attached to each home, data Zillow largely strips from public view. If your goal is agent market-share analysis or lead-source attribution, that provenance is the whole point. The second cluster is price_history and tax_history together, which give you two independent value anchors per property. A home listed 15% above its last assessed value, or one cut twice in 60 days, is a different negotiation than a fresh listing at assessed value even at the same sticker.


Free trial

Scraping at scale? Skip the blocks.

Fast, unblockable datacentre proxies with unlimited bandwidth.

Where Realtor.com keeps its data: __NEXT_DATA__ and the RDC GraphQL backend

Here's the thing that trips up first-timers. A Realtor.com detail page is a Next.js React app. The HTML you see is a shell, and the real fields (price, agents, coordinates, history) arrive as a large JSON object embedded in a