# Real Estate Aggregator (`tri_angle/real-estate-aggregator`) Actor

Multi-source scraper for real estate data. Supports rent and sale listings and details, deduplication, and consistent output from Zillow, Realtor, Zumper, Apartments.com, and Redfin.

- **URL**: https://apify.com/tri_angle/real-estate-aggregator.md
- **Developed by:** [Tri⟁angle](https://apify.com/tri_angle) (Apify)
- **Categories:** Real estate
- **Stats:** 591 total users, 17 monthly users, 100.0% runs succeeded, 12 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $1.50 / 1,000 extracted listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

### Scrape US real estate listings from Zillow, Redfin, Realtor.com, Zumper, and Apartments.com at once

Real Estate Aggregator searches five US listing sites for one location in a single run and returns every result in the same format: Realtor.com, Apartments.com, Zumper, Zillow, and Redfin. Give it a ZIP code or a city and choose rent or sale. It queries each site that covers that offer type, normalizes the listings into one schema, and can remove the same home when it appears on several sites.

### What you get

One dataset row per listing, with the same fields whichever site it came from:

| Field | What it holds |
|---|---|
| `source` | The `provider` it came from, the listing `url` there, its `localId`, and `scrapedAt` |
| `offerType`, `propertyType`, `propertyTypeRaw` | Rent or sale, the normalized property type, and the site's own label |
| `price` | The asking price or rent |
| `bedrooms`, `bathrooms`, `livingArea`, `landArea`, `areaUnit` | Size, in square feet or square meters |
| `address`, `gps` | Street, city, state, ZIP, county, and coordinates |
| `title`, `description`, `pictures` | The listing text and photos |
| `extras` | Days on market, HOA, and the site-specific data that does not fit the shared fields |

With `includeDetails` on, each site reads the listing's own page and adds:

| Field | What it holds |
|---|---|
| `yearBuilt`, `numberOfStories`, `numberOfUnits` | Building facts |
| `schools` | Nearby schools with rating and distance |
| `amenities` | Features grouped the way the site groups them |

Some sites also add site-specific data under `extras.providerData`, such as price history and tax records (Redfin), sale history (Realtor.com), open houses (Redfin, Realtor.com), and agent contacts (Redfin, Realtor.com, Zumper). Which fields are filled depends on the site and the listing.

### Which sites cover what

| Site | Rent | Sale | Details |
|---|---|---|---|
| Realtor.com | Yes | Yes | Yes |
| Zillow | Yes | Yes | Yes |
| Redfin | Yes | Yes | Yes |
| Apartments.com | Yes | No | Yes |
| Zumper | Yes | No | Yes |

For a sale search, Apartments.com and Zumper are skipped and the run log says so.

### How to run it in Apify Console

1. Open Real Estate Aggregator and enter a `location`, such as `90210` or `Austin, TX`.
2. Choose `offerType`: `rent` or `sale`.
3. Optionally pick the `providers`, set `maxResults` per site, and turn on `includeDetails` or `deduplicateResults`.
4. Start the run and export the dataset as JSON, CSV, or Excel.

It searches one location per run. For several locations, start one run for each.

### Input

| Field | Type | What it does |
|---|---|---|
| `location` | string | One place name, ZIP code, or postcode. Required |
| `offerType` | string | `rent` or `sale`. Default `sale`. Required |
| `providers` | array | Which sites to search: `realtor`, `apartments`, `zumper`, `zillow`, `redfin`. Default all five |
| `maxResults` | integer | The most listings from each site. Default `100` |
| `includeDetails` | boolean | Read each listing's own page for richer records. Default `false` |
| `deduplicateResults` | boolean | Remove listings that appear on several sites, matched on offer type, country, ZIP, and street, keeping the first. Default `false` |
| `units` | string | `imperial` (square feet, the default) or `metric` (square meters) |
| `propertyTypes` | array | Any of `house`, `condo`, `apartment`, `townhouse`, `land`, `multifamily`, `other`. Applied on Realtor.com and Redfin; other sites return all property types |
| `radiusMiles` | number | Search radius around the location. Applied on Realtor.com only; other sites ignore it |

The smallest input that works:

```json
{
  "location": "90210",
  "offerType": "sale"
}
```

Rentals in one city, all sites, duplicates removed:

```json
{
  "location": "Austin, TX",
  "offerType": "rent",
  "maxResults": 200,
  "deduplicateResults": true
}
```

### Call it from code, or from an AI agent

Start a run with the Apify API and read the listings when it finishes:

```bash
curl -X POST "https://api.apify.com/v2/acts/tri_angle~real-estate-aggregator/runs" \
  -H "Authorization: Bearer $APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"location": "90210", "offerType": "sale", "deduplicateResults": true}'
```

The response carries the run's `defaultDatasetId`. Read the listings from `https://api.apify.com/v2/datasets/{defaultDatasetId}/items` once the run has finished. A run queries several sites, so start it asynchronously like this.

To let an agent use it, connect Apify's MCP server at `https://mcp.apify.com` in Claude, Cursor, or any MCP client and add Real Estate Aggregator as a tool. The agent gets one comparable set of listings for an area instead of five different formats.

### What it costs

You pay per event, at the price of your Apify plan:

| Event | Free plan | Diamond plan |
|---|---|---|
| Actor start | $0.0012 | $0.00084 |
| Listing | $0.002 | $0.0015 |
| Detailed listing (with `includeDetails`) | $0.002 | $0.0015 |
| Deduplication add-on, once per run | $0.005 | $0.003 |

Five sites with the default 100 listings each can return up to 500 listings, about $1 on the Free plan. Deduplication is charged once per run, however many duplicates it removes.

### Limitations

- US listings only, from the five sites above, as they show them at run time.
- One location per run.
- Each site has its own coverage and fields, so some values are empty for some sites.
- Deduplication matches on the address, so a home listed with two different street spellings can survive as two rows.

### Troubleshooting

These cover what usually goes wrong.

- **No rows from Apartments.com or Zumper.** They cover rentals only. Set `offerType` to `rent`.
- **The same home appears twice.** Turn on `deduplicateResults`.
- **A filter seems ignored.** `propertyTypes` is applied only on Realtor.com and Redfin, and `radiusMiles` only on Realtor.com. Results from the other sites are not filtered. To get only matching types, filter the dataset on `propertyType`.

For anything else, open an issue on the Actor's Issues tab with your run ID.

### Frequently asked questions

These are the questions people ask before their first run.

#### Is the listing data live?

Yes. Every run searches the sites at the time it runs.

#### What is the smallest input that works?

A `location` and an `offerType`, for example `{"location": "90210", "offerType": "sale"}`.

#### What happens when a site has no listings for my search?

That site adds no rows to the dataset.

#### Can I use it as a real estate API?

Yes. Call it through the Apify API with a JSON input and read the listings back as JSON, in one format for all five sites.

#### Does it work with MCP and AI agents?

Yes. Add it to Apify's MCP server and any MCP client can run it as a tool.

#### How much does it cost to scrape 500 listings?

About $1 on the Free plan, plus the start fee, and $0.005 more if you remove duplicates.

#### Can I search several cities at once?

Not in one run. Start one run per location, for example from a loop in your code or from several saved tasks.

#### Can I get rentals and homes for sale together?

Run it twice, once with `offerType: rent` and once with `sale`.

#### Is it legal to scrape real estate listings?

Scraping publicly available listing data is generally legal. Agent names and phone numbers can be personal data, which laws such as GDPR protect. Follow each site's terms and ask a lawyer if you are unsure about your use case.

# Actor input Schema

## `location` (type: `string`):

A single place name, ZIP code, or postcode to search. Multi-location fan-out is a caller concern — invoke it once per location.

## `offerType` (type: `string`):

Whether to search for rentals or properties for sale. Apartments.com and Zumper are rent-only and will be skipped when 'sale' is selected.

## `providers` (type: `array`):

Which provider actors to call. Defaults to all providers. Providers whose capabilities don't match the requested offerType are silently skipped.

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

Maximum number of listings to fetch from each provider.

## `includeDetails` (type: `boolean`):

When true, providers fetch each listing's detail page and emit richer ListingDetail records where supported. Materially more expensive — charged as 'listing-detailed'.

## `deduplicateResults` (type: `boolean`):

When true, duplicate listings are removed across providers: items are matched by normalized (offerType, country, zip, street), and only the first occurrence is kept. Charged as a flat 'deduplicate-addon' fee.

## `units` (type: `string`):

Output area unit, applied by every sub-actor. Default `imperial` keeps each provider's native square feet; `metric` converts area to square meters. The output `areaUnit` field records which unit each record uses.

## `propertyTypes` (type: `array`):

Optional filter on property type. Providers silently drop types they don't support.

## `radiusMiles` (type: `number`):

Optional radius in miles around the location. Providers that don't honor radius silently ignore it.

## Actor input object example

```json
{
  "location": "90210",
  "offerType": "sale",
  "providers": [
    "realtor",
    "apartments",
    "zumper",
    "zillow",
    "redfin"
  ],
  "maxResults": 100,
  "includeDetails": false,
  "deduplicateResults": false,
  "units": "imperial"
}
```

# 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 = {
    "location": "90210"
};

// Run the Actor and wait for it to finish
const run = await client.actor("tri_angle/real-estate-aggregator").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 = { "location": "90210" }

# Run the Actor and wait for it to finish
run = client.actor("tri_angle/real-estate-aggregator").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 '{
  "location": "90210"
}' |
apify call tri_angle/real-estate-aggregator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,tri_angle/real-estate-aggregator"
        }
    }
}
```

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/7mcQAVcB4AKIoWrJR/builds/LaRguyt4m0XtsIqYA/openapi.json
