# Century 21 Scraper \[$1.90/1K💰] | Listings, MLS, Agent Leads (`ahmed_jasarevic/century21-scraper`) Actor

Scrape Century 21 listings with price, beds, baths, sqft, MLS number and photos, plus listing-agent phone and email. Search any US city, state or ZIP with price and size filters. No API licence needed - built for real estate leads and market research.

- **URL**: https://apify.com/ahmed_jasarevic/century21-scraper.md
- **Developed by:** [Ahmed Jasarevic](https://apify.com/ahmed_jasarevic) (community)
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.90 / 1,000 results

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

## Century 21 Scraper — US Property Listings, MLS Numbers and Listing-Agent Leads

Extract **Century 21 real-estate listings and listing-agent contact data** from `century21.com` for market analysis, agent lead generation and property monitoring. Search by **city, state or ZIP** with price, bed, bath and sqft filters.

Two modes: **fast mode** returns one compact row per listing straight from the search page with no extra requests, or **contact mode** visits each property page to add the listing agent's phone, email, office, description, MLS number and photos.

**Century 21 has no public developer API.** Its listings are only reachable through the site's own front-end, which is exactly what this Actor reads — as clean JSON or HTML, without a browser.

***

### Main use cases

- **Real-estate agent lead generation** — listing agent name, phone, email and brokerage, with MLS number and property context attached
- **Comparable-sales and pricing research** — price, beds, baths, sqft, lot size, year built and status per listing
- **Neighborhood and ZIP-level market tracking** — run the same search on a schedule and diff price and inventory
- **Property aggregator and portal builds** — photo URLs and listing URLs straight into your own catalog
- **Investor prospecting** — filter by price band, bedroom count or sqft to build a shortlist before outreach
- **Brokerage footprint analysis** — group by `agentOffice` to map which offices cover which markets

***

### Input

| Field | Type | Required | Default | Notes |
|---|---|---|---|---|
| `startUrls` | array | no | `[]` | Direct `century21.com/homes/list` or `/homes/detail` URLs. Leave empty and use `city` / `state` / `zip` below instead. Takes priority over the location fields. |
| `city` | string | no | `""` | e.g. `"Austin"`. Combined with `state` to build a search URL. |
| `state` | string | no | `""` | Two-letter code, e.g. `"TX"`. Required for city and ZIP searches. |
| `zip` | string | no | `""` | If set, the ZIP is used **instead of** city/state. |
| `maxListings` | integer | no | `200` | Hard cap on dataset rows (capped at 1000). |
| `includeDetails` | boolean | no | `false` | **OFF (default) — fast mode:** one compact row per listing from the search page, no extra requests. **ON — contact mode:** visits each property page and stores rows with agent phone/email, description, MLS number, photos and year built. Contact-mode rows are billed as a separate pay-per-event once the Actor is monetized. |
| `minPrice` / `maxPrice` | integer | no | unset | Listing price range in USD. |
| `minBeds` / `maxBeds` | number | no | unset | Bedroom range. |
| `minBaths` / `maxBaths` | number | no | unset | Bathroom range. |
| `minSqft` / `maxSqft` | number | no | unset | Living-area range in square feet. |
| `proxy` | object | no | `useApifyProxy: false` | Cheerio mode works without a proxy. Enable only if you hit rate-limiting. |

#### Examples

```json
{ "city": "Austin", "state": "TX", "maxListings": 200 }
```

```json
{ "zip": "33101", "minPrice": 400000, "maxPrice": 900000, "minBeds": 3 }
```

Fast inventory sweep (cheapest run):

```json
{ "city": "Miami", "state": "FL", "includeDetails": false, "maxListings": 500 }
```

Agent lead list with contact details:

```json
{
  "city": "Los Angeles",
  "state": "CA",
  "includeDetails": true,
  "maxListings": 100
}
```

Direct URLs (bypasses city/state/ZIP):

```json
{
  "startUrls": [
    { "url": "https://www.century21.com/homes/list/city/ca/los-angeles" }
  ]
}
```

***

### Output

One flat JSON dataset, with an `overview` view (main listing columns) and a `details` view (everything, including agent contact).

| Field | Type | Description |
|---|---|---|
| `url` | string | Link to the property page on century21.com |
| `listingId` | string | Century 21 listing identifier, extracted from the URL |
| `title` | string | Property page title (street + city) |
| `price` | number | Listing price in USD |
| `address` | string | Full street address |
| `street` | string | Street line only |
| `city`, `state`, `zip` | string | Location, `state` as a two-letter code |
| `bedrooms`, `bathrooms`, `sqft` | number | Core spec fields |
| `lotSize` | string | e.g. `"3.84 acres"` or `"5,250 sqft"` |
| `yearBuilt` | number | Construction year |
| `propertyType` | string | e.g. `Single Family Residence`, `Condo` |
| `status` | string | `Active`, `Pending`, `Sold`, `Coming Soon` … |
| `description` | string | Agent's public remarks |
| `mlsNumber` | string | MLS identifier |
| `photoCount` | number | Number of photo URLs |
| `photos` | array | Photo URLs |
| `agentId` | string | Listing agent identifier |
| `agentName` | string | Listing agent's name |
| `agentPhone` | string | Listing agent's phone |
| `agentEmail` | string | Listing agent's email |
| `agentOffice` | string | Brokerage / office |
| `placeName` | string | Resolved place name of the search term |
| `placeType` | string | `city` / `county` / `postalCode` / `neighborhood` |
| `source` | string | How the row was produced: `www.century21.com (ssr)`, `(html)` or `(api)` |
| `scrapedAt` | string | ISO timestamp |

`includeDetails: false` gives you the core listing columns only. `agentPhone`, `agentEmail`, `description`, `mlsNumber`, `photos` and `yearBuilt` are populated in contact mode.

***

### Example output

Fast-mode listing row:

```json
{
  "url": "https://www.century21.com/homes/detail/ca/los-angeles/1234-main-st/lid-P00800000HByraIABytsiE9GvyG2XEOFgKJpMlnv",
  "listingId": "P00800000HByraIABytsiE9GvyG2XEOFgKJpMlnv",
  "title": "1234 Main St, Los Angeles, CA 90019",
  "price": 1349998,
  "address": "1234 Main Street, Los Angeles, CA 90019",
  "street": "1234 Main Street",
  "city": "Los Angeles",
  "state": "CA",
  "zip": "90019",
  "bedrooms": 3,
  "bathrooms": 2,
  "sqft": 2816,
  "propertyType": "Single Family Residence",
  "status": "Active",
  "photoCount": 24,
  "agentName": "John Doe",
  "placeName": "Los Angeles",
  "placeType": "city",
  "source": "www.century21.com (ssr)",
  "scrapedAt": "2026-09-29T10:00:00.000Z"
}
```

Contact-mode listing row (adds the agent and detail fields):

```json
{
  "url": "https://www.century21.com/homes/detail/ca/los-angeles/1234-main-st/lid-P00800000HByraIABytsiE9GvyG2XEOFgKJpMlnv",
  "listingId": "P00800000HByraIABytsiE9GvyG2XEOFgKJpMlnv",
  "price": 1349998,
  "address": "1234 Main Street, Los Angeles, CA 90019",
  "city": "Los Angeles",
  "state": "CA",
  "zip": "90019",
  "bedrooms": 3,
  "bathrooms": 2,
  "sqft": 2816,
  "lotSize": "5,250 sqft",
  "yearBuilt": 2024,
  "propertyType": "Single Family Residence",
  "status": "Active",
  "description": "Beautifully updated home with brand new kitchen, quartz counters and a landscaped rear yard.",
  "mlsNumber": "7086493",
  "photoCount": 24,
  "photos": [
    "https://c21assets.century21.com/xxlarge/7086493-1.jpg",
    "https://c21assets.century21.com/xxlarge/7086493-2.jpg"
  ],
  "agentId": "C0123456",
  "agentName": "John Doe",
  "agentPhone": "(310) 555-0134",
  "agentEmail": "john.doe@century21.com",
  "agentOffice": "CENTURY 21 Preferred",
  "source": "www.century21.com (api)",
  "scrapedAt": "2026-09-29T10:01:12.000Z"
}
```

***

### Build a listing monitor and agent lead list on a schedule

Every Apify Actor is callable over HTTP, so the standard setup is a recurring run against the same search:

- **Daily** — same `zip` or `city` + `state`; diff `price` and `status` to catch price drops, new listings and status changes
- **Weekly** — contact mode on a smaller `maxListings` to keep an agent lead list warm with fresh phone and email
- **Monthly** — new ZIP codes to grow a market-coverage dataset
- **Wire it into your CRM** — Apify webhooks, Zapier, Make, Google Sheets and 100+ integrations fire on run completion; results export as JSON, CSV, Excel, XML, HTML or RSS

Pick one memory profile per mode: 256 MB is enough for both, since neither uses a browser.

***

### Related Actors

- [Century 21 Real Estate Scraper](https://apify.com/crawlerbros/century21-real-estate-scraper) (`crawlerbros/century21-real-estate-scraper`) — same source with county/neighborhood search, property-ID lookup and full-detail enrichment
- [MLS API](https://apify.com/api/mls-api) (`apify/api`) — aggregates Zillow, Realtor, Zumper, Apartments.com and Rightmove into one normalized multi-source real-estate feed
- [Homes.com Scraper](https://apify.com/ahmed_jasarevic/homes-scraper) (`ahmed_jasarevic/homes-scraper`) — agent leads and price monitoring on a competing US portal
- [Real Estate Search Property Details Scraper](https://apify.com/ahmed_jasarevic/real-estate-search-property-details-scraper) (`ahmed_jasarevic/real-estate-search-property-details-scraper`) — multi-source property detail pulls when you need more than one portal
- [Rightmove Scraper](https://apify.com/ahmed_jasarevic/rightmove-scraper) (`ahmed_jasarevic/rightmove-scraper`) — UK listings and sold prices, for transatlantic comparison

***

### FAQ

#### Is there an official Century 21 API?

No. Century 21 does not publish a public developer API for listing data. Its listings come from MLS feeds, and the clean official route — the RESO Web API / IDX — requires a licensed broker of record to sign a display agreement and typically $50–$500 per MLS per month. You cannot buy your way in with a credit card. This Actor reads the same public listing surface directly, with no licence in the chain.

#### What are the alternatives to this Actor?

- **RESO Web API / IDX providers** — the clean, licence-compliant route, but weeks of paperwork and a broker of record in the loop.
- **Zillow Group's MLS Listings platform** — invite-only, partner-by-partner, and normalised to the RESO dictionary.
- **Aggregator portals (Zillow, Realtor, Rightmove APIs)** — a different schema per source, so you rebuild normalisation yourself.
- **Browser-based scrapers** — unnecessary here, because this Actor's mode reads the site's own front-end payload directly.

#### Why is the Agent contact data behind `includeDetails`?

Because it costs extra requests. Fast mode reads the search result page, which already carries price, beds, baths, sqft, status and agent name — one request for the whole page of results. Agent phone, email, brokerage, description, MLS number and the full photo set only exist on the individual property page, so contact mode makes one extra request per listing. That is the trade-off: `includeDetails: false` for cheap inventory sweeps, `true` for lead lists.

#### How do I search by location?

Three ways. `city` + `state` (state is required for a city search), `zip` on its own, or `startUrls` with a raw `century21.com/homes/list/...` URL, which bypasses location building entirely. The resolved location comes back on every row as `placeName` and `placeType`, so you always know what was actually searched.

#### What do I get if I pass a direct listing URL?

`startUrls` accepts `/homes/detail` URLs as well as search URLs. Pass detail URLs and you get those specific properties (with agent contact, since there's no search page to shortcut from); pass a search URL and you get that search's result set.

#### Does it work without a proxy?

Yes. Cheerio mode reads the site's own front-end payload and works from a normal datacenter IP. `proxy` defaults to `useApifyProxy: false` — enable it only if you hit rate-limiting at high volume.

#### How much does it cost?

Listing rows are billed at **$0.0019–$0.002 per row**, so roughly **$1.90–$2.00 per 1,000 listings**. Agent contact details are a separate pay-per-event (`Contact detail`, $0.00085–$0.0009 each) charged only in contact mode. No browser is used, so compute cost is a fraction of a Playwright-based actor.

***

### For AI Agents & LLM Apps

Callable via the Apify MCP server and the Apify API. Returns US real-estate listings from century21.com, one flat row per property, with listing-agent contact fields when contact mode is on.

**Minimal valid input** — fastest possible run, one row per listing from the search page:

```json
{ "city": "Austin", "state": "TX" }
```

**Agent lead list** — one extra request per listing, adds phone, email and office:

```json
{ "city": "Los Angeles", "state": "CA", "includeDetails": true, "maxListings": 100 }
```

**ZIP-targeted inventory filter:**

```json
{ "zip": "33101", "minPrice": 400000, "maxPrice": 900000, "minBeds": 3 }
```

**Explicit URLs** — bypasses location building entirely:

```json
{ "startUrls": [{ "url": "https://www.century21.com/homes/list/city/ca/los-angeles" }] }
```

**Output fields** — `url`, `listingId`, `title`, `price`, `address`, `street`, `city`, `state`, `zip`, `bedrooms`, `bathrooms`, `sqft`, `lotSize`, `yearBuilt`, `propertyType`, `status`, `description`, `mlsNumber`, `photoCount`, `photos`, `agentId`, `agentName`, `agentPhone`, `agentEmail`, `agentOffice`, `placeName`, `placeType`, `source`, `scrapedAt`.

**Behaviors an agent should know**

- **`state` is required whenever you use `city` or `zip`.** `city` alone will not build a usable search URL.
- **`zip` overrides `city` and `state`.** If both are supplied, the ZIP wins.
- **`startUrls` overrides all location fields.** When set, `city` / `state` / `zip` are ignored.
- **`includeDetails` defaults to `false`.** Leaving it off is the cheap path — one request per results page. Turning it on makes one extra request per listing and bills a `Contact detail` event per row.
- **Fast mode does not populate `agentPhone`, `agentEmail`, `description`, `mlsNumber`, `photos` or `yearBuilt`.** Do not assume those fields exist unless `includeDetails` is `true`.
- **`maxListings` is hard-capped at 1000.** Setting it higher does nothing.
- **`price`, `bedrooms`, `bathrooms`, `sqft` and `yearBuilt` can arrive as numbers, strings or booleans** depending on which front-end surface produced the row (see `source`). Coerce before arithmetic.
- **`photos` is an array of URLs, not an image payload** — no image bytes are downloaded, so this stays cheap.

**Billing model** — pay per event: one `result` event per listing row ($0.0019–$0.002) and, in contact mode only, one `Contact detail` event per row with agent contact data ($0.00085–$0.0009).

***

### Legal & Compliance Disclaimer

This Actor is an independent third-party tool. It is not affiliated with, endorsed by, sponsored by, or connected to Century 21, Realogy Holdings, or any CENTURY 21 brokerage.

It reads **only publicly accessible listing and property pages** on `www.century21.com`. It does not log in, does not bypass authentication, does not solve CAPTCHAs, does not use proxies by default, and does not access MLS systems or any licensed feed.

Output includes **listing agent names, phone numbers, email addresses and brokerage names**. Those are personal data. Many US jurisdictions treat a real-estate agent's publicly listed business contact details as business information, but that is not true everywhere and CAN-SPAM, TCPA and state-level do-not-call and email-consent rules still apply to any outreach you send. Verify your own legal basis — and note that some MLS display agreements restrict how long listing data may be retained or redistributed, including data collected from public pages.

This Actor is a data-collection tool; it does not provide legal advice and makes no claim that any particular use is permitted.

***

### SEO Keywords

century 21 scraper, century21 api, real estate listing data, us property listings, mls listing data, real estate api alternative, real estate lead generation, real estate agent leads, listing agent contact data, property price monitoring, zip code property data, real estate market research, house for sale data, real estate comparable sales, realtor lead list, property aggregator data, real estate dataset, home sales data by city, rental and sale listings, real estate scraping, proptech data source, brokerage footprint analysis, investor property leads, real estate comps data

# Actor input Schema

## `startUrls` (type: `array`):

Optional. Direct century21.com /homes/list or /homes/detail URLs. Leave empty and use City/State or ZIP below instead.

## `city` (type: `string`):

e.g. "Austin". Combined with State to build a search URL.

## `state` (type: `string`):

e.g. "TX". Required for city/ZIP searches.

## `zip` (type: `string`):

If set, the ZIP is used instead of city/state.

## `maxListings` (type: `integer`):

Hard cap on dataset items (capped at 1000).

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

OFF (default): fast mode — pushes one compact row per listing from the search page, no extra requests. ON: contact mode — visits each property page and stores rows with agent phone/email (description, MLS, photos, year built, contact). Contact rows are billed per result via pay-per-event once the Actor is monetized.

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

Minimum listing price in USD.

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

Maximum listing price in USD.

## `minBeds` (type: `number`):

Minimum number of bedrooms.

## `maxBeds` (type: `number`):

Maximum number of bedrooms.

## `minBaths` (type: `number`):

Minimum number of bathrooms.

## `maxBaths` (type: `number`):

Maximum number of bathrooms.

## `minSqft` (type: `number`):

Minimum living area in square feet.

## `maxSqft` (type: `number`):

Maximum living area in square feet.

## `proxy` (type: `object`):

Optional. Cheerio mode works without a proxy. Enable only if you hit rate-limiting.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.century21.com/homes/list/city/ca/los-angeles"
    }
  ],
  "maxListings": 200,
  "includeDetails": false,
  "proxy": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped listing rows (and agent rows, when agent scraping is enabled) in the default dataset.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.century21.com/homes/list/city/ca/los-angeles"
        }
    ],
    "proxy": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("ahmed_jasarevic/century21-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 = {
    "startUrls": [{ "url": "https://www.century21.com/homes/list/city/ca/los-angeles" }],
    "proxy": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("ahmed_jasarevic/century21-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 '{
  "startUrls": [
    {
      "url": "https://www.century21.com/homes/list/city/ca/los-angeles"
    }
  ],
  "proxy": {
    "useApifyProxy": false
  }
}' |
apify call ahmed_jasarevic/century21-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,ahmed_jasarevic/century21-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/imGfB1EevxLfTGgTS/builds/XYMzesufHCK9bgNmZ/openapi.json
