# Realtor Lead Scraper (`logical_vivacity/realtor-lead-scraper`) Actor

Pull verified real estate leads - name, email, phone, license #, brokerage - from Realtor.com, Compass, Sotheby's, Redfin, Apartments.com, Craigslist, REALTOR.ca and Rightmove in one run. Deduped output ready for CRM import. Built for agent prospecting and lead-gen automation.

- **URL**: https://apify.com/logical\_vivacity/realtor-lead-scraper.md
- **Developed by:** [Logical Vivacity](https://apify.com/logical_vivacity) (community)
- **Categories:** Lead generation, Real estate, Automation
- **Stats:** 22 total users, 3 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 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.

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

## Real Estate Lead Scraper — Multi-Site Realtor & Property Manager Contact Extractor

Pull verified contact information for real estate agents, brokers, FSBO sellers, and property managers across **10 major real estate sites in one run**. Built on Apify and Crawlee, ships deduped lead records with name, **email, phone, license number, brokerage**, and source URL — ready for direct CRM import or outreach automation.

If you're prospecting agents, building a real-estate CRM, enriching listings, training a model on real estate market data, or automating cold outreach, this actor replaces 10+ separate scrapers with one unified pipeline and a single output schema.

### Supported sources

| Source | Region | Lead type | Fields extracted |
|---|---|---|---|
| **Realtor.com** | US | Listing agent | Name, email, phone, license #, NRDS ID, brokerage, listing |
| **Realtor.com agent directory** | US | Agent profile | Name, mobile phone, license #, brokerage, office, website |
| **Redfin** | US | Listing agent | Name, phone, brokerage, broker phone, MLS# |
| **Compass.com listings** | US | Listing agent | Name, email, phone, license #, brokerage, listing |
| **Compass.com agent roster** | US | Agent profile | Name, email, phone, license #, profile URL |
| **Sotheby's International Realty** | Global | Luxury agent | Name, mobile + office phone, email, brokerage |
| **Apartments.com** | US | Property manager / landlord | Property name, phone, address |
| **Craigslist real estate** | US | FSBO seller / landlord | Title, phone (when posted), price, address |
| **REALTOR.ca** | Canada | Listing REALTOR® | Name, phone, brokerage, broker phone |
| **Rightmove** | UK | Estate agency | Branch name, address, profile, listing price |

Each adapter is independent — pick any subset and the actor fans out in parallel, then dedupes the results by NRDS ID → license # → email → name+phone, so the same agent surfacing on Compass + Realtor.com merges into one enriched record.

### Quick start

1. Pick sources under **Sites to scrape**
2. Add target cities under **Target locations** (e.g. `[{"city":"Austin","state":"TX"}]`)
3. Click **Start** — leads land in the dataset, viewable as a table or downloadable as JSON / CSV / Excel

The default proxy is **Apify Residential** because Realtor.com, Redfin, Apartments.com and Zillow WAF non-proxied requests aggressively. You won't get useful volume from these without it.

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `sites` | string\[] | `["compass","compassagents"]` | Which adapters to run. See full enum in `INPUT_SCHEMA.json`. |
| `locations` | object\[] | `[{"city":"Austin","state":"TX"}]` | Cities to query. State as 2-letter code (US/CA), `GB` for UK. |
| `listingType` | `"sale"` | `"rent"` | `"sale"` | Selects sale-side or rent-side adapters where the source supports both. |
| `freshnessDays` | integer | `7` | Listing-side adapters skip listings older than this. Lower = more responsive agents. |
| `maxLeadsPerLocation` | integer | `200` | Cap per adapter per location. Total = sites × locations × this, less dedupe. |
| `proxyConfiguration` | proxy | Apify Residential | Required for Realtor.com/Redfin/Apartments.com volume. |

### Output

Every lead row conforms to `dataset_schema.json`:

```json
{
  "source": "compassagents",
  "sourceListingId": "https://www.compass.com/agents/david-aceves",
  "detailUrl": "https://www.compass.com/agents/david-aceves",
  "leadType": "agent",
  "agentName": "David Aceves",
  "agentEmail": "david.aceves@compass.com",
  "agentPhone": "512-360-8788",
  "agentLicense": null,
  "agentNrdsId": null,
  "agentWebsite": "https://www.compass.com/agents/david-aceves",
  "brokerName": "Compass",
  "brokerPhone": null,
  "brokerAddress": null,
  "listing": {},
  "scrapedAt": "2026-05-06T19:01:37.309Z"
}
```

The dataset ships with three preconfigured table views in the Apify UI:

- **Leads** (default, all rows)
- **Agents** (filtered to licensed-agent rows)
- **Rental landlords** (Apartments.com / Craigslist landlord rows)

### Use cases

- **Real estate CRM seeding** — pull every active listing agent in your service area on a daily cron, dedupe against existing contacts, push new ones into HubSpot/Salesforce
- **Cold outreach for agent-targeting tools** (CRMs, lead-gen software, mortgage products, transaction platforms) — Realtor.com agents + Compass agents alone yields 30k+ verified emails per metro
- **Market research** — combine listing-side adapters with `freshnessDays=1` to track which agents are most active week-over-week in a market
- **Lead enrichment** — hit any of the agent-directory adapters with a known agent name and merge the license #, NRDS ID, and direct contact back onto your existing record
- **Recruiting for brokerages** — Sotheby's, Compass and Realtor.com agent rosters contain tenure, sales volume and brokerage affiliation, useful for poaching campaigns

### Architecture

The actor uses a pluggable adapter pattern — each source is a self-contained module under `src/adapters/`. Adding a new source means writing one file conforming to the `Adapter` interface, registering it in `src/adapters/index.ts`, and adding it to the enum in `INPUT_SCHEMA.json`. Three adapter shapes are supported:

- **API-first** (e.g. Redfin) — direct calls to the site's internal JSON API after a one-time cookie warmup
- **Browser + structured data extraction** (e.g. Realtor.com, Rightmove, Compass) — Playwright + parse `__NEXT_DATA__`, `PAGE_MODEL`, or schema.org JSON-LD
- **Plain HTML** (e.g. Craigslist) — `gotScraping` + regex/cheerio for sites without anti-bot

Stealth is enabled by default via `playwright-extra` + `puppeteer-extra-plugin-stealth`. Output dedupe cascades by identity strength: NRDS → license # → email → name+phone → URL.

### FAQ

**Q: Will this work for Zillow?**
Zillow uses PerimeterX with aggressive challenge ratcheting. The agent search page sometimes loads but profile-detail pages get blocked instantly even with stealth + residential proxy. We mark Zillow as "in development" and recommend Realtor.com agent directory + Compass as substitutes — between them you get higher coverage with cleaner data.

**Q: Why are some Apartments.com phones the same area code (737)?**
Those are CoStar tracking numbers that forward to the actual property manager. They're real working contacts but routed through CoStar's call platform.

**Q: Do FSBO leads from Craigslist include the seller's name?**
Craigslist hides poster identity by default. We extract whatever phone or email the seller put in the body of the post — for real estate posts that's usually present. Sellers who use the obfuscated reply form are skipped.

**Q: How do you handle GDPR/CCPA?**
All scraped fields are publicly published by the source sites. Use the data only for purposes permitted under applicable law. The actor is a tool — compliance is your responsibility.

**Q: Is the data deduped across sources?**
Yes. The same agent appearing on Compass listings and Realtor.com gets merged into one record (keyed on license #, NRDS ID, or email). The merge keeps the strongest field from each source.

**Q: How do I add a new site?**
Drop a new adapter under `src/adapters/`, add it to the registry and the input enum. The base `Adapter` interface defines `search()` (URL discovery) and `fetchLead()` (per-record extraction). Crawlee-based sources also expose a `runAll()` shortcut for sites where the search and detail steps share a session.

### Keywords

real estate scraper, realtor scraper, real estate lead generation, real estate API, MLS scraper, agent contact scraper, realtor.com scraper, redfin scraper, compass scraper, sotheby's scraper, apartments.com scraper, craigslist real estate scraper, realtor.ca scraper, rightmove scraper, real estate CRM enrichment, broker email scraper, FSBO lead scraper, property manager contact scraper, landlord lead scraper, agent license lookup, NRDS scraper

# Actor input Schema

## `sites` (type: `array`):

Pick which sources to run. Sources behind aggressive WAFs (Realtor.com, Redfin, Apartments.com) need the residential proxy below.

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

Cities to pull leads from. Provide an array of objects, e.g. \[{"city":"Austin","state":"TX"}, {"city":"Toronto","state":"ON"}]. For UK use {"city":"London","state":"GB"}.

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

Sale-side adapters resolve to listing-agent leads; rent-side adapters resolve to property-manager / landlord leads.

## `freshnessDays` (type: `integer`):

Listing-side adapters filter to listings posted in the last N days. Higher = more leads, lower = hotter (recent activity = more responsive agent).

## `maxLeadsPerLocation` (type: `integer`):

Caps each adapter's output for a given location. Total run size = sites × locations × this number, less dedupe.

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

Apify residential proxy is strongly recommended — Realtor.com, Redfin, Zillow and Apartments.com WAF non-proxied requests aggressively.

## Actor input object example

```json
{
  "sites": [
    "compass",
    "compassagents",
    "realtor",
    "realtoragents",
    "apartments"
  ],
  "locations": [
    {
      "city": "Austin",
      "state": "TX"
    }
  ],
  "listingType": "sale",
  "freshnessDays": 7,
  "maxLeadsPerLocation": 200,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `leads` (type: `string`):

All deduped lead records produced by the run. One JSON object per lead, schema defined in dataset\_schema.json.

## `leadsCsv` (type: `string`):

Same data as `leads` but flattened to CSV — convenient for spreadsheet/CRM import.

## `datasetOverview` (type: `string`):

Apify console view of the dataset with the configured table layout.

# 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 = {
    "sites": [
        "compass",
        "compassagents",
        "realtor",
        "realtoragents",
        "apartments"
    ],
    "locations": [
        {
            "city": "Austin",
            "state": "TX"
        }
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("logical_vivacity/realtor-lead-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 = {
    "sites": [
        "compass",
        "compassagents",
        "realtor",
        "realtoragents",
        "apartments",
    ],
    "locations": [{
            "city": "Austin",
            "state": "TX",
        }],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("logical_vivacity/realtor-lead-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 '{
  "sites": [
    "compass",
    "compassagents",
    "realtor",
    "realtoragents",
    "apartments"
  ],
  "locations": [
    {
      "city": "Austin",
      "state": "TX"
    }
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call logical_vivacity/realtor-lead-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,logical_vivacity/realtor-lead-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/kdIeYv9ZS9AE70Ofg/builds/bPGsD2gQbvh84Ph21/openapi.json
