# Century 21 Real Estate Scraper (`crawlerbros/century21-real-estate-scraper`) Actor

Scrape homes for sale and rent from Century21.com. Search by city, county, neighborhood or ZIP with price/beds/baths/sqft/year-built filters, look up a specific property by street address, or fetch full listing details by ID - price, photos, agent, schools, taxes, HOA, and more.

- **URL**: https://apify.com/crawlerbros/century21-real-estate-scraper.md
- **Developed by:** [Crawler Bros](https://apify.com/crawlerbros) (community)
- **Categories:** Real estate, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 results

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

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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

## Century 21 Real Estate Scraper

Scrape homes for sale and for rent from **Century21.com** — one of the largest real estate brokerage networks in the US. Search by city, county, neighborhood or ZIP code with rich filters (price, beds, baths, square footage, lot size, year built), look up a specific property by street address, or fetch full listing details (description, taxes, HOA, schools, appliances) by listing ID. No login, no API key, no proxy required.

### What this actor does

- **Three modes:** `search` (by location + filters), `byAddress` (direct property lookup), `byListingId` (fetch by internal listing ID)
- **For sale or for rent** — toggle with `listingType`
- **Filters:** property type, listing status, price range, min beds/baths, sqft range, lot size range, year-built range, sort order
- **Full detail enrichment** — optionally fetch description, taxes, HOA dues, schools, appliances, utilities and every photo for each search result
- **Empty fields are omitted** — every record only contains fields the source actually returned

### Output per listing

- `listingId`, `mlsNumber`, `listingUrl`
- `listingType` (For Sale / For Rent), `listingStatus`
- `price`, `pricePerSquareFoot` *(detail mode)*
- `propertyType`, `propertyTypeLabel`
- `bedrooms`, `bathrooms`, `fullBathrooms`, `halfBathrooms`
- `livingAreaSqFt`, `lotSize`, `lotSizeUnits`, `yearBuilt` *(detail mode)*
- `address`, `city`, `state`, `stateCode`, `postalCode`, `neighborhood`, `latitude`, `longitude`
- `elementarySchool`, `middleSchool`, `highSchool` *(detail mode)*
- `photoUrl`, `photoUrls[]`, `photosCount`, `virtualTourUrl`
- `listingOfficeName`, `agentName`, `agentPhone`, `officePhone` *(phone in detail mode)*
- `description`, `taxAnnualAmount`, `taxYear`, `hoaDuesMonthly` *(detail mode)*
- `heating`, `cooling`, `roof`, `flooring`, `appliances`, `amenities`, `lotFeatures`, `sewer`, `water` *(detail mode)*
- `openHouses[]`, `daysOnMarket`, `lastUpdated` *(detail mode)*
- `recordType: "listing"`, `scrapedAt`

### Input

| Field | Type | Console prefill | Description |
|---|---|---|---|
| `mode` | string | `search` | `search` / `byAddress` / `byListingId` |
| `location` | string | `Austin, TX` | City, county, neighborhood or ZIP (mode=search). No forced default via API - required in `search` mode |
| `addresses` | array | – | Full street addresses (mode=byAddress); deduplicated automatically |
| `listingIds` | array | – | Listing IDs from a previous run (mode=byListingId); deduplicated automatically |
| `listingType` | string | `forSale` | `forSale` / `forRent`. No forced default via API - falls back to `forSale` in code if omitted |
| `propertyTypes` | array | all | Single family, Multi-family, Co-op, Mobile/Manufactured, Lots/Land, Condominium, Townhouse, Farm |
| `statuses` | array | all | Active, Pending/Under contract, Coming soon |
| `minPrice` / `maxPrice` | int | – | Price range in USD |
| `minBedrooms` | select | – | Studio – 5+ |
| `minBathrooms` | select | – | 1+ – 5+ |
| `minSqft` / `maxSqft` | select | – | Living area range |
| `minAcreage` / `maxAcreage` | select | – | Lot size range |
| `minYearBuilt` / `maxYearBuilt` | select | – | Year-built range |
| `sortBy` | string | `newest` | `newest` / `priceHighToLow` / `priceLowToHigh`. No forced default via API - falls back to `newest` in code if omitted |
| `includeFullDetails` | bool | `false` | Fetch full property detail (description, taxes, schools, all photos) for every search result — one extra request per listing |
| `maxItems` | int | `30` | Hard cap (1–1000) |

> Note: only `mode`, `propertyTypes`/`statuses` (default to "all"), `maxItems`, and non-listed numeric/proxy fields have a real schema default. `location`, `listingType`, and `sortBy` list a "Console prefill" only - it pre-populates the Console *Start* button/daily test run and is **not** injected when the field is omitted from a programmatic `POST /runs` call.

#### Example: homes for sale in Austin, TX under $500k

```json
{
  "mode": "search",
  "location": "Austin, TX",
  "listingType": "forSale",
  "maxPrice": 500000,
  "minBedrooms": "3",
  "maxItems": 50
}
```

#### Example: rentals in Miami, FL with full details

```json
{
  "mode": "search",
  "location": "Miami, FL",
  "listingType": "forRent",
  "includeFullDetails": true,
  "maxItems": 20
}
```

#### Example: lookup a specific address

```json
{
  "mode": "byAddress",
  "addresses": ["13521 Sea Biscuit Dr, Del Valle, TX"]
}
```

#### Example: fetch by listing ID

```json
{
  "mode": "byListingId",
  "listingIds": ["P00800000HF6cD2iLtM7DTj91VD8KUzhnfCsy0Wx"]
}
```

### Use cases

- **Real estate market research** — track pricing trends by city/neighborhood
- **Investment analysis** — filter by price, lot size, and year built to find deals
- **Lead generation** — pull agent/office contact info from active listings
- **Rental market comparison** — compare rents across neighborhoods
- **Portfolio monitoring** — periodically re-fetch known listings by ID for price/status changes

### FAQ

**Does this need a proxy or login?** No. Century21.com's own listings API is public and returns real MLS-syndicated data with a plain HTTP request — the same endpoint the century21.com website itself calls.

**How do I find a `listingId` for `byListingId` mode?** Every record from `search` or `byAddress` mode includes a `listingId` field you can reuse.

**Why does `search` mode return fewer fields than `byAddress`/`byListingId`?** The location-search endpoint returns a lighter summary object (used for map/list views). Set `includeFullDetails: true` to enrich every search result with the full property detail (description, taxes, schools, all photos) — this makes one extra request per listing, so it's slower.

**What area does this cover?** All US markets that Century 21 syndicates through its MLS/IDX feeds — coverage varies by MLS availability in each area.

**Are "For Rent" listings the same fields as "For Sale"?** Mostly yes; some fields specific to home sales (e.g. HOA dues, taxes) are less commonly populated on rental listings depending on what the source MLS provides.

**How fresh is the data?** Listings are pulled live from Century21.com's current MLS/IDX feed at the time the actor runs — no caching.

# Actor input Schema

## `mode` (type: `string`):

What to fetch.

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

City, county, neighborhood or ZIP code, e.g. `Austin, TX`, `Miami-Dade County, FL`, `78617`.

## `addresses` (type: `array`):

Full street addresses to look up, e.g. `13521 Sea Biscuit Dr, Del Valle, TX`.

## `listingIds` (type: `array`):

Century 21 internal listing IDs (from a previous run's `listingId` field), e.g. `P00800000HF6cD2iLtM7DTj91VD8KUzhnfCsy0Wx`.

## `listingType` (type: `string`):

Search for-sale or for-rent listings.

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

Restrict to these property types. Leave empty for all types.

## `statuses` (type: `array`):

Restrict to these listing statuses. Leave empty for all statuses.

## `minPrice` (type: `integer`):

Only listings priced at or above this amount.

## `maxPrice` (type: `integer`):

Only listings priced at or below this amount.

## `minBedrooms` (type: `string`):

Only listings with at least this many bedrooms (0 = studio).

## `minBathrooms` (type: `string`):

Only listings with at least this many bathrooms.

## `minSqft` (type: `string`):

Only listings at or above this living area.

## `maxSqft` (type: `string`):

Only listings at or below this living area.

## `minAcreage` (type: `string`):

Only listings with a lot size at or above this many acres.

## `maxAcreage` (type: `string`):

Only listings with a lot size at or below this many acres.

## `minYearBuilt` (type: `string`):

Only listings built in or after this year.

## `maxYearBuilt` (type: `string`):

Only listings built in or before this year.

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

Order in which listings are returned/paginated.

## `includeFullDetails` (type: `boolean`):

Fetch the full property detail (description, taxes, HOA, schools, appliances, all photos) for every search result. Slower — makes one extra request per listing.

## `maxItems` (type: `integer`):

Hard cap on emitted records.

## Actor input object example

```json
{
  "mode": "search",
  "location": "Austin, TX",
  "addresses": [],
  "listingIds": [],
  "listingType": "forSale",
  "propertyTypes": [],
  "statuses": [],
  "sortBy": "newest",
  "includeFullDetails": false,
  "maxItems": 30
}
```

# Actor output Schema

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

Dataset containing all scraped Century 21 real estate listings.

# 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 = {
    "mode": "search",
    "location": "Austin, TX",
    "addresses": [],
    "listingIds": [],
    "listingType": "forSale",
    "propertyTypes": [],
    "statuses": [],
    "sortBy": "newest",
    "includeFullDetails": false,
    "maxItems": 30
};

// Run the Actor and wait for it to finish
const run = await client.actor("crawlerbros/century21-real-estate-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 = {
    "mode": "search",
    "location": "Austin, TX",
    "addresses": [],
    "listingIds": [],
    "listingType": "forSale",
    "propertyTypes": [],
    "statuses": [],
    "sortBy": "newest",
    "includeFullDetails": False,
    "maxItems": 30,
}

# Run the Actor and wait for it to finish
run = client.actor("crawlerbros/century21-real-estate-scraper").call(run_input=run_input)

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

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

```

## CLI example

```bash
echo '{
  "mode": "search",
  "location": "Austin, TX",
  "addresses": [],
  "listingIds": [],
  "listingType": "forSale",
  "propertyTypes": [],
  "statuses": [],
  "sortBy": "newest",
  "includeFullDetails": false,
  "maxItems": 30
}' |
apify call crawlerbros/century21-real-estate-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=crawlerbros/century21-real-estate-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

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