# Realtor.com Listings Scraper (`ammarbinfaisal/realtor-com-listings-scraper`) Actor

Search realtor.com for-sale listings by city, county, ZIP or state with price, beds and baths filters. Optionally enrich each listing with full property details, agent contacts and custom keyword detection.

- **URL**: https://apify.com/ammarbinfaisal/realtor-com-listings-scraper.md
- **Developed by:** [Malik Ammar Faisal](https://apify.com/ammarbinfaisal) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 listing results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Realtor.com Scraper — Extract Real Estate Listings, Property Details & Agent Contacts

**Realtor.com Listings Scraper** is a fast, reliable **Realtor.com scraper** that extracts for-sale and new-construction property listings from [realtor.com](https://www.realtor.com) by city, county, ZIP code or entire US state. Filter by price, bedrooms, bathrooms and listing date, then download clean, structured **real estate data** as JSON, CSV, Excel or XML — or pull it straight into your app through the API.

Use it as an unofficial **Realtor.com API** for lead generation, market research, comparable-sales analysis, investment sourcing, daily new-listing alerts and real estate data pipelines.

### What can you extract from Realtor.com with this scraper?

Every listing is returned as one structured record. With full property details enabled (the default) you get:

| Category | Fields |
|---|---|
| **Listing** | property ID, listing ID, realtor.com URL, status, list date, days on market, photo count, primary photo URL, full description |
| **Location** | street address, city, county, state, ZIP code, latitude, longitude |
| **Price & size** | list price, bedrooms, bathrooms, living area (sq ft), lot size (sq ft), year built, year renovated |
| **Property facts** | property type, construction, heating, cooling, exterior, roofing, plus the complete structured *details* list exactly as shown on realtor.com (utilities, interior, exterior, HOA, schools, taxes, …) |
| **Agent & brokerage** | listing agent name, phone, email, agent profile URL, brokerage name, office phone |
| **Keyword detection** | `keywordMatches` and `keywordScore` for any custom regex groups you define (optional) |

Turn off `fetchDetails` for a cheaper, search-only run that still returns address, coordinates, price, beds/baths/sqft, lot size, year built, property type, description, photo and listing agent name/phone.

### Why use this Realtor.com scraper?

- **Search any area** — pass any number of locations (`"Milwaukee, WI"`, `"Kenosha County, WI"`, `"53202"`, `"Brooklyn, NY"`) or scrape a whole state with a two-letter state code.
- **Server-side filters** — price range, bedrooms, bathrooms, listing status (for sale / ready to build) and *listed within the last N days*, applied by realtor.com itself so you only pay for listings you want.
- **Complete pagination** — goes past realtor.com's 200-results-per-page limit automatically and de-duplicates listings across overlapping locations.
- **Full property details** — one extra request per listing enriches the record with county, coordinates, structured details and agent email/brokerage.
- **Custom keyword detection** — define regular-expression groups to flag features (waterfront, pool, ADU, septic, solar, …) and rank listings by `keywordScore`.
- **Built for monitoring** — schedule it with `daysListed: 1` and get every new listing in your market each morning.
- **Robust against blocking** — Apify residential proxy rotation, automatic retries with exponential backoff and bot-challenge detection.
- **Pay per event** — you are charged per listing, not per compute minute; the run stops cleanly at `maxResults` or your cost limit.

### How to scrape Realtor.com listings

1. Open the Actor in Apify Console and click **Try for free**.
2. Enter one or more **Locations** (city, county, ZIP or neighborhood) — or leave it empty and set a **State code** to search an entire state.
3. Optionally set price, bedroom, bathroom and **Listed within the last N days** filters.
4. Choose **Max results** and whether to **Fetch full property details**.
5. Click **Start**. When the run finishes, open the **Output** tab to preview the data or **Export** it as JSON, CSV, Excel, XML, HTML or RSS.

You can also run it from the [Apify API](https://docs.apify.com/api/v2), the [Apify CLI](https://docs.apify.com/cli), or the JavaScript / Python clients — see [Use the scraper from code](#use-the-realtor-com-scraper-from-code) below.

### Input parameters

| Field | Type | Default | Description |
|---|---|---|---|
| `locations` | string\[] | `[]` | One search per entry: city, county, ZIP or neighborhood. |
| `stateCode` | string | – | Two-letter US state code; used only when `locations` is empty (state-wide search). |
| `status` | string\[] | `["for_sale","ready_to_build"]` | Listing types to include. |
| `daysListed` | integer | – | Only listings listed within the last N days. `1` = daily new-listing monitoring. |
| `priceMin` / `priceMax` | integer | – | List price range in USD. |
| `bedsMin` / `bedsMax` | integer | – | Bedroom range. |
| `bathsMin` / `bathsMax` | number | – | Bathroom range. |
| `sortBy` | `newest` | `oldest` | `price_asc` | `price_desc` | `newest` | Collection order (matters when `maxResults` is smaller than the match count). |
| `maxResults` | integer | `1000` | Stop after this many unique listings across all locations. |
| `fetchDetails` | boolean | `true` | One extra request per listing for the full property record. Turn off for a cheaper search-only run. |
| `keywordGroups` | object\[] | `[]` | Optional regex groups for feature detection (see [Keyword detection](#keyword-detection)). Leave empty to skip. Automatically enables `fetchDetails`. |
| `proxyConfiguration` | object | Apify RESIDENTIAL | Residential proxies strongly recommended. |
| `maxConcurrency` | integer | `10` | Parallel detail requests. |
| `maxRetries` | integer | `4` | Retries per request. |
| `debugLog` | boolean | `false` | Verbose logs + raw sample response in the key-value store. |

#### Example input

Scrape every 3+ bedroom home listed in the last week in two Wisconsin counties, priced between $200k and $600k, with full property details:

```json
{
  "locations": ["Kenosha County, WI", "Racine County, WI"],
  "daysListed": 7,
  "priceMin": 200000,
  "priceMax": 600000,
  "bedsMin": 3,
  "maxResults": 500,
  "fetchDetails": true
}
```

State-wide search-only run (cheapest option):

```json
{
  "stateCode": "NY",
  "daysListed": 1,
  "fetchDetails": false,
  "maxResults": 2000
}
```

### Output example

One dataset item per unique listing:

```json
{
  "propertyId": "8279116705",
  "listingId": "2986442139",
  "url": "https://www.realtor.com/realestateandhomes-detail/1234-Main-St_Kenosha_WI_53140_M82791-16705",
  "status": "for_sale",
  "address": "1234 Main St",
  "city": "Kenosha",
  "county": "Kenosha",
  "stateCode": "WI",
  "postalCode": "53140",
  "latitude": 42.573828,
  "longitude": -88.110104,
  "price": 249900,
  "beds": 2,
  "baths": 1,
  "sqft": 863,
  "lotSqft": 8276,
  "yearBuilt": 1930,
  "yearRenovated": null,
  "propertyType": "single_family",
  "construction": null,
  "heating": "Forced air",
  "cooling": "Central air",
  "exterior": null,
  "roofing": null,
  "listDate": "2026-08-28T21:30:56.000000Z",
  "photoCount": 24,
  "primaryPhotoUrl": "http://ap.rdcpix.com/....jpg",
  "description": "Charming ranch on a quiet lot close to schools and parks ...",
  "details": [
    { "category": "Utilities", "parentCategory": "Utilities", "text": ["Sewer: Public", "Water: Public"] }
  ],
  "agentName": "Jane Doe",
  "agentPhone": "2625551234",
  "agentEmail": "jane@example.com",
  "agentUrl": "https://www.realtor.com/realestateagents/...",
  "brokerageName": "Example Realty",
  "officePhone": "2625550000",
  "keywordMatches": {},
  "keywordScore": 0,
  "detailsFetched": true,
  "searchLocation": "Kenosha County, WI",
  "scrapedAt": "2026-08-29T12:00:00+00:00"
}
```

With `fetchDetails: false`, `county`, `details`, `agentEmail`, `brokerageName` and the keyword fields stay empty and `detailsFetched` is `false`.

A run summary (`listingsPushed`, `listingsWithDetails`, per-location totals, request stats, charged amount) is saved to the key-value store under `SUMMARY`. Both outputs are declared in the Actor output schema, so they appear in the run's **Output** tab and in the `GET run` API response, and every dataset field is documented in the dataset schema (readable by AI agents and MCP clients).

### Keyword detection

Need to find listings with a specific feature that realtor.com does not expose as a filter? Add one or more **keyword groups** — the field is empty by default and completely optional. Each group is a named set of case-insensitive Python regular expressions:

```json
{
  "name": "pool",
  "detailPatterns": ["\\bpool\\b"],
  "descriptionPatterns": ["\\b(in-?ground|heated)\\s+pool\\b"],
  "detailScore": 10,
  "descriptionScore": 5
}
```

- `detailPatterns` run against every row of the structured **details** list (e.g. `"Exterior: In Ground Pool"`). A match adds `detailScore` (default 10) per matching row and records `"<category>: <text>"` in `keywordMatches`.
- `descriptionPatterns` run against the free-text description. Each matching pattern adds `descriptionScore` (default 5) and records a short snippet.
- Use `\b` word boundaries to avoid false positives.
- If more than one group is defined and **all** of them match, `keywordScore` gets a +20 bonus — useful for "must have A *and* B" searches. Sort or filter the dataset by `keywordScore`.

### How much does it cost to scrape Realtor.com?

This Actor uses **pay-per-event** pricing, so you pay only for what you use:

| Event | Charged |
|---|---|
| Actor start | once per run |
| Listing result | per listing pushed to the dataset |
| Listing details | additionally per listing enriched with full property details |

Turn off `fetchDetails` for cheap, high-volume searches; turn it on when you need county, agent contacts, structured details or keyword detection. The run stops cleanly when `maxResults` or your run's **maximum cost** limit is reached, so you never pay for more than you asked for. Apify's free plan is enough to try it out.

### Use the Realtor.com scraper from code

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_API_TOKEN>")
run = client.actor("<ACTOR_ID>").call(run_input={
    "locations": ["Milwaukee, WI"],
    "daysListed": 1,
    "maxResults": 100,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(item["price"], item["address"], item["url"])
```

#### JavaScript / Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_API_TOKEN>' });
const run = await client.actor('<ACTOR_ID>').call({
    locations: ['Milwaukee, WI'],
    daysListed: 1,
    maxResults: 100,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

### Integrations and automation

- **Schedules** — run daily, hourly or on any cron expression to monitor new listings.
- **Webhooks** — trigger your own endpoint when a run finishes.
- **Google Sheets, Slack, email, Make, Zapier, n8n** — push new listings into your workflow with Apify's [integrations](https://docs.apify.com/platform/integrations).
- **AI agents & MCP** — the dataset schema documents every field, so LLM agents can query the output directly through the Apify MCP server.

### Tips for better results

- **Daily monitoring**: schedule the Actor with `daysListed: 1` and connect a webhook or integration to get new listings every morning.
- **Large areas**: prefer several counties over a single state-wide search — results are more relevant and you can stop early per county.
- **Blocks / retries**: keep the default residential proxy; lower `maxConcurrency` if the log shows many retries.
- **Cost control**: set `maxResults` and a run-level maximum cost so large searches never overrun your budget.

### FAQ

#### Is it legal to scrape Realtor.com?

The scraper collects only publicly available listing data — no login, no personal data behind authentication. Web scraping of public data is generally legal, but you are responsible for using the data in accordance with realtor.com's terms of service and applicable laws (including privacy laws such as GDPR and CCPA when handling agent contact details). See Apify's [guide to the legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

#### Does it return sold, pending or rental listings?

No. It covers **for-sale** and **ready-to-build (new construction)** listings. Sold history and rentals are not included.

#### How many listings can I scrape in one run?

Up to `maxResults` (max 10,000) across all locations. realtor.com caps individual searches, so for very large state-wide searches split the work by county or ZIP code.

#### Do I need proxies?

Yes — realtor.com rate-limits and blocks datacenter IPs. The Actor defaults to Apify **residential** proxies, which are included in your Apify subscription.

#### What if Realtor.com changes its website?

realtor.com can change its private API at any time. The Actor is actively maintained; if you notice missing fields or failing runs, open an issue on the Actor's **Issues** tab.

#### Can I get agent emails and phone numbers?

Yes. With `fetchDetails: true` each listing includes the listing agent's name, phone, email, profile URL, brokerage name and office phone when realtor.com publishes them.

### Related real estate scrapers

Looking for other sources? Search the Apify Store for Zillow, Redfin, Trulia, Homes.com and Apartments.com scrapers to combine data from multiple portals.

***

Scrapes publicly available listing data from realtor.com. Not affiliated with, endorsed by or sponsored by Realtor.com, Move Inc. or the National Association of REALTORS®.

# Actor input Schema

## `locations` (type: `array`):

One search per entry. Accepts a city ("Milwaukee, WI"), a county ("Kenosha County, WI"), a ZIP code ("53202") or a neighborhood. Leave empty to search a whole state via State code.

## `stateCode` (type: `string`):

Two-letter US state code (e.g. "WI"). Used only when Locations is empty — searches the entire state.

## `status` (type: `array`):

Which listing types to include.

## `daysListed` (type: `integer`):

Only listings whose list date is within the last N days. Leave empty for no date filter. Use 1 for daily monitoring of new listings.

## `priceMin` (type: `integer`):

Lowest list price to include.

## `priceMax` (type: `integer`):

Highest list price to include.

## `bedsMin` (type: `integer`):

Minimum number of bedrooms.

## `bedsMax` (type: `integer`):

Maximum number of bedrooms.

## `bathsMin` (type: `integer`):

Minimum number of bathrooms.

## `bathsMax` (type: `integer`):

Maximum number of bathrooms.

## `sortBy` (type: `string`):

Order in which listings are collected. Matters when Max results is smaller than the number of matching listings.

## `maxResults` (type: `integer`):

Stop after this many unique listings across all locations. Each pushed listing is billed as one result.

## `fetchDetails` (type: `boolean`):

Make one extra request per listing to get county, coordinates, year built, lot size, heating/cooling, the full structured details list, agent email and brokerage. Turn off for a faster, cheaper search-only run. Required for keyword detection.

## `keywordGroups` (type: `array`):

Detect features by regular expression. Each group has a name, patterns matched against the structured details rows (worth 10 points each by default) and patterns matched against the free-text description (5 points each). Results appear in `keywordMatches` and `keywordScore`. Leave empty to skip keyword detection. Automatically enables Fetch full property details.

## `proxyConfiguration` (type: `object`):

Apify residential proxies are strongly recommended — realtor.com rate-limits and blocks datacenter IPs.

## `maxConcurrency` (type: `integer`):

How many property-detail requests run in parallel. Lower this if you see many retries.

## `maxRetries` (type: `integer`):

Retries with exponential backoff and a fresh proxy session on blocks, rate limits and network errors.

## `debugLog` (type: `boolean`):

Verbose logs and a sample of the raw search response saved to the key-value store as DEBUG\_SEARCH\_RESPONSE.

## Actor input object example

```json
{
  "status": [
    "for_sale",
    "ready_to_build"
  ],
  "daysListed": 7,
  "sortBy": "newest",
  "maxResults": 1000,
  "fetchDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxConcurrency": 10,
  "maxRetries": 4,
  "debugLog": false
}
```

# Actor output Schema

## `listings` (type: `string`):

All scraped listings as dataset items (JSON, CSV, Excel or XML via the ?format= parameter). Field definitions are in the dataset schema.

## `summary` (type: `string`):

JSON record with listingsPushed, listingsWithDetails, per-location totals (searches\[{location,totalAvailable}]), failedSearches, request counts, totalChargedUsd, startedAt and finishedAt.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "status": [
        "for_sale",
        "ready_to_build"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ammarbinfaisal/realtor-com-listings-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "status": [
        "for_sale",
        "ready_to_build",
    ],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("ammarbinfaisal/realtor-com-listings-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "status": [
    "for_sale",
    "ready_to_build"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call ammarbinfaisal/realtor-com-listings-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ammarbinfaisal/realtor-com-listings-scraper"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/H3Swjs1Vng42HImC1/builds/GkmffHaQ6d6TQUiyl/openapi.json
