# Craigslist Real Estate & Housing Scraper (`khadinakbar/craigslist-real-estate-scraper`) Actor

Scrape Craigslist housing — apartments, rooms, vacation rentals, real estate for sale. Beds/baths/sqft, price, address, geo. MCP-ready. Cheerio + Residential.

- **URL**: https://apify.com/khadinakbar/craigslist-real-estate-scraper.md
- **Developed by:** [Khadin Akbar](https://apify.com/khadinakbar) (community)
- **Categories:** Real estate, Lead generation, MCP servers
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 property card scrapeds

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?

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

### What is Craigslist Real Estate Scraper?

Extract **public Craigslist housing listings** into structured JSON for rental shortlists, FSBO research, market scans, and MCP/API agents. Search by metro site code and housing category, filter by price or bedrooms, or paste a Craigslist housing search / listing URL. Each row includes title, price, beds/baths/sqft when published, neighborhood, address/geo when public, and optional full description — HTTP-only with Apify Residential, no login.

Run it on Apify for scheduling, API access, residential proxy, and Pay per event billing with a clear `maxResults` cost cap.

### Best fit

Choose this Actor when you need **public Craigslist housing listings** with price, beds, and location fields when the board publishes them. It works well for SF Bay, New York, and Austin rental lead lists, roommate searches, vacation-rental scans, and off-MLS FSBO research where Craigslist is the source board.

For all Craigslist categories (jobs, for-sale, services, gigs), continue with [Craigslist All-in-One Scraper](https://apify.com/khadinakbar/craigslist-all-in-one-scraper) when the next step is multi-category classifieds rather than housing-only.
For US for-sale / rental listing search on Zillow, then use [Zillow Search Scraper](https://apify.com/khadinakbar/zillow-search-scraper) when the source board is Zillow.
For UK property BUY / RENT / SOLD, continue with [Rightmove All-in-One Scraper](https://apify.com/khadinakbar/rightmove-all-in-one-scraper) when the market is the UK.

### Workflow story

A rental-ops analyst sets `site` to `sfbay`, `category` to `apa`, `minBedrooms` to `2`, `minPrice`/`maxPrice` to `2000`/`4000`, and `maxResults` to `5`. The Actor fetches the public Craigslist housing search over Residential, optionally opens each listing for description and attributes, writes one validated row per listing, then the analyst exports CSV into a lead sheet and keeps only rows under `$3500` with `bedrooms >= 2`.

### How it works

1. Builds a Craigslist housing search URL from site/category/filters, or uses caller-supplied housing start URLs
2. Fetches listing pages over HTTPS with Apify Residential (Craigslist works best on residential exits)
3. Optionally enriches each listing from the detail page (description, attributes, images, reply URL)
4. Charges `property-scraped` or `property-detailed`, then `pushData`, and writes `OUTPUT` / `RUN_SUMMARY` with an honest outcome

### Input example

```json
{
  "site": "sfbay",
  "category": "apa",
  "minPrice": 2000,
  "maxPrice": 4000,
  "minBedrooms": 2,
  "maxResults": 5,
  "includeDetails": false
}
```

URL mode:

```json
{
  "startUrls": [
    { "url": "https://www.craigslist.org/search/area/newyork?cat=roo&max_price=1500" }
  ],
  "maxResults": 5,
  "includeDetails": true
}
```

| Field | What it controls |
|---|---|
| `site` / `sites` | Craigslist metro code(s) such as `sfbay`, `newyork`, `austin` |
| `category` | Housing class: `apa`, `hhh`, `roo`, `sub`, `vac`, `rea`, `off`, `prk`, `swp`, `hsw` |
| `startUrls` | Housing search or listing URLs (overrides site/category builders) |
| `maxResults` | Hard property cap (default 25; quality prefill 5) |
| `includeDetails` | Fetch full description + attributes from the listing page |
| `extractContacts` | Also pull public body email/phone + reply URL (turns details on) |
| `minPrice` / `maxPrice` / bedrooms / bathrooms / sqft | Common housing filters |
| `proxyConfiguration` | Defaults to Apify Residential — leave as-is |

### Output fields

| Field | Description |
|---|---|
| `listingId` + `title` + `url` | Stable listing token, title, and canonical page |
| `site` / `category` / `neighborhood` | Metro, housing class, and area label |
| `priceText` / `priceNumeric` / `currency` | Rent or sale price when shown |
| `bedrooms` / `bathrooms` / `sqft` / `housingType` | Size and type when Craigslist publishes them |
| `address` / `geo` / `postedAt` | Location and freshness when public |
| `description` / `images` / `contact` | Detail-mode body, gallery, and reply link |
| `detailEnriched` / `source` / `scrapedAt` | Enrich flag, `craigslist.org`, scrape time |

### Example output

You can download the dataset in JSON, HTML, CSV, or Excel.

```json
{
  "listingId": "r69N4UvYf6GCWN9BwkVJSB",
  "title": "Where style meets substance: 2 BR homes up for grabs!",
  "url": "https://www.craigslist.org/view/d/fremont-where-style-meets-substance-br/r69N4UvYf6GCWN9BwkVJSB",
  "site": "sfbay",
  "category": "apa",
  "neighborhood": "Fremont",
  "priceText": "$2,924",
  "priceNumeric": 2924,
  "currency": "USD",
  "bedrooms": 2,
  "bathrooms": 2.5,
  "sqft": 1004,
  "housingType": "townhouse",
  "address": "3939 Monroe Ave, Fremont, CA 94536",
  "geo": { "lat": 37.551, "lng": -121.991 },
  "detailEnriched": true,
  "source": "craigslist.org",
  "scrapedAt": "2026-09-30T00:00:00.000Z"
}
```

### Pricing

This Actor uses **Pay per event**. The live [Pricing tab](https://apify.com/khadinakbar/craigslist-real-estate-scraper/pricing) is the source of truth for effective event fees, platform usage payer, and any scheduled pricing changes. When **Pay per event plus usage** applies, callers pay platform compute, proxy traffic, and storage usage separately from the event fees.

- `apify-actor-start`: the run-start event, scaled by allocated memory (minimum one event)
- `property-scraped`: one saved search-card row (primary)
- `property-detailed`: one saved listing enriched from its detail page

For five cards, event fees are five times the effective card price plus the Actor start event. Platform usage is separate when the Pricing tab enables Pay per event plus usage. Invalid input and empty valid searches leave property events unbilled. Enabling `includeDetails` switches the row event to `property-detailed`.

### API example

```bash
curl "https://api.apify.com/v2/acts/khadinakbar~craigslist-real-estate-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"site":"sfbay","category":"apa","minBedrooms":2,"maxResults":5,"includeDetails":false}'
```

After completion, read dataset items and the `OUTPUT` / `RUN_SUMMARY` key-value records.

### Best results

- Keep `maxResults` ≤ 5 while testing filters so you can validate bed/bath fill rates before a larger harvest.
- Leave Residential proxy as the default — Craigslist works best on residential exits.
- Prefer `includeDetails: true` when you need the full description, attributes, or reply URL from the listing page.
- Beds, baths, and sqft stay sparse on some cards: empty numeric fields mean Craigslist omitted them, and the Actor still returns title, price, neighborhood, and URL.
- Empty but valid searches finish successfully with `VALID_EMPTY` and zero property charges.
- Hitting `maxResults` finishes as `PARTIAL` by design — raise the cap when you need a larger sample.
- Non-Craigslist or non-housing start URLs finish as `INVALID_INPUT` with zero property charges.
- Tighten price and bedroom filters when you want a focused shortlist from the first public search page.

### Use with AI agents (Apify MCP)

> Scrape Craigslist SF Bay apartments with at least 2 bedrooms between $2000 and $4000. Return title, price, bedrooms, bathrooms, neighborhood, and url. Cap at 5 listings.

Connect via <https://mcp.apify.com>. Tool name shape: `apify--craigslist-real-estate-scraper`. Read `OUTPUT.outcome` and `itemsPushed` before treating an empty dataset as an outage. Cost signal: one card event or one detail event per saved row, plus the start event and platform usage when applicable. Provenance fields include `source`, `url`, and `scrapedAt`. Pagination stays on the first public search page per site/category query.

### Builder's note

I built this around Craigslist's public static search list and `ld_searchpage_results` JSON-LD because beds, baths, and geo already arrive without a login when Residential clears the path. I learned that the classic subdomain search URLs redirect to `www.craigslist.org/search/area/{site}`, and that deep `?s=` offsets bounce back to page one, so the honest contract is one public HTML page plus optional detail enrich. My goal was one validated public housing row per listing with truthful PPE billing.

### Legal disclaimer

Craigslist® and related marks are trademarks of their respective owners. This independent Actor is not affiliated with, associated with, or endorsed by Craigslist.

You remain responsible for complying with applicable laws, Craigslist terms of use, and your own data-use policies. Use results for lawful housing research and market analysis only. Prefer lawful research over spam or unlawful processing of personal data.

For feedback or custom workflows, use the Actor **Issues** tab on Apify.

### Event allowance and housing controls

The Actor checks the run-effective event allowance before starting requests, bounds detail-page work by funded rows, and returns `PARTIAL` if the allowance cannot fund a property. `maxResults` bounds row count; it is not a total platform-cost ceiling. Keep run memory, timeout and concurrency bounded when platform usage is charged separately.

Housing controls include multiple metro sites, ten housing categories, minimum and maximum bedrooms and bathrooms, square-footage bounds, housing types, pets, furnishing, photos, posting age and ZIP radius. These provide a broader housing search input than the common city/price/minimum-bedroom workflow. Listing details remain source-dependent; the Actor does not produce an AI lead score or deeper public-HTML pagination.

# Actor input Schema

## `site` (type: `string`):

Scrape housing from this Craigslist metro site code (e.g. sfbay, newyork, austin, london). Must match craigslist.org/about/sites. Ignored when startUrls are provided.

## `category` (type: `string`):

Choose the Craigslist housing category to search. apa=apartments for rent, rea=real estate for sale, roo=rooms & shares, vac=vacation rentals, hhh=all housing.

## `searchQuery` (type: `string`):

Optional free-text keywords Craigslist applies to titles and post bodies (e.g. studio, backyard, downtown).

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

Stop after this many billable housing rows. Public Craigslist HTML returns about 360 cards per search page; this Actor caps at one HTML page.

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

Open each listing page for its full description, attributes, images and public reply URL. Detailed rows use the property-detailed event; the live Pricing tab shows its effective price.

## `extractContacts` (type: `boolean`):

When true, auto-enable detail mode and pull emails/phones that appear in the public listing body plus the Craigslist reply URL. Does not bypass Craigslist reply forms or require login.

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

Keep listings at or above this price (rent or sale). Use 0 to disable.

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

Keep listings at or below this price. Use 0 to disable.

## `minBedrooms` (type: `integer`):

Filter search results to at least this many bedrooms. Use 0 to disable.

## `maxBedrooms` (type: `integer`):

Filter search results to at most this many bedrooms. Use 0 to disable.

## `minBathrooms` (type: `integer`):

Filter search results to at least this many bathrooms. Use 0 to disable.

## `maxBathrooms` (type: `integer`):

Filter search results to at most this many bathrooms. Use 0 to disable.

## `minSqft` (type: `integer`):

Filter by minimum living area when Craigslist exposes sqft. Use 0 to disable.

## `maxSqft` (type: `integer`):

Filter by maximum living area when Craigslist exposes sqft. Use 0 to disable.

## `housingTypes` (type: `array`):

Optional Craigslist housing_type filters (apartment, condo, house, townhouse, etc.). Leave empty for all types.

## `catsOk` (type: `boolean`):

Only return listings marked cats-ok on Craigslist.

## `dogsOk` (type: `boolean`):

Only return listings marked dogs-ok on Craigslist.

## `furnishedOnly` (type: `boolean`):

Only return furnished listings when Craigslist supports the filter.

## `hasPic` (type: `boolean`):

Only return listings that include photos.

## `postedToday` (type: `boolean`):

Only return listings Craigslist marks as posted today.

## `forSaleByOwnerOnly` (type: `boolean`):

When category is real estate for sale (rea), keep owner-listed properties only. Craigslist may ignore this filter on rent categories.

## `postalCode` (type: `string`):

Optional ZIP/postal that redirects Craigslist to a city search scoped around that code.

## `searchRadiusMiles` (type: `integer`):

Radius in miles around postalCode. Only applied when postalCode is set.

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

Optional extra Craigslist site codes to fan out the same housing search across multiple metros.

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

Paste Craigslist housing search or listing URLs (new www.craigslist.org/search/... or /view/d/... forms, or legacy \*.craigslist.org/search/apa links). Non-housing categories are rejected.

## `maxAgeDays` (type: `integer`):

Skip listings older than this many days when a posted date is available. Use 0 to disable.

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

Parallel HTTP requests (1-20). Keep low on Residential to reduce blocks.

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

Apify Proxy settings. Residential is strongly recommended — datacenter IPs trigger Craigslist CAPTCHAs quickly.

## Actor input object example

```json
{
  "site": "sfbay",
  "category": "apa",
  "searchQuery": "studio",
  "maxResults": 5,
  "includeDetails": false,
  "extractContacts": false,
  "minPrice": 2000,
  "maxPrice": 4000,
  "minBedrooms": 2,
  "maxBedrooms": 0,
  "minBathrooms": 0,
  "maxBathrooms": 0,
  "minSqft": 0,
  "maxSqft": 0,
  "housingTypes": [],
  "catsOk": false,
  "dogsOk": false,
  "furnishedOnly": false,
  "hasPic": false,
  "postedToday": false,
  "forSaleByOwnerOnly": false,
  "postalCode": "94110",
  "searchRadiusMiles": 0,
  "sites": [],
  "startUrls": [],
  "maxAgeDays": 0,
  "maxConcurrency": 5,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

All scraped housing listings as structured JSON records.

## `OUTPUT` (type: `string`):

Terminal outcome, itemsPushed, and chargedEventCounts.

## `RUN_SUMMARY` (type: `string`):

Detailed run diagnostics and outcome.

# 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 = {
    "site": "sfbay",
    "category": "apa",
    "searchQuery": "",
    "maxResults": 5,
    "includeDetails": false,
    "minPrice": 2000,
    "maxPrice": 4000,
    "minBedrooms": 2,
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("khadinakbar/craigslist-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 = {
    "site": "sfbay",
    "category": "apa",
    "searchQuery": "",
    "maxResults": 5,
    "includeDetails": False,
    "minPrice": 2000,
    "maxPrice": 4000,
    "minBedrooms": 2,
    "startUrls": [],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("khadinakbar/craigslist-real-estate-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 '{
  "site": "sfbay",
  "category": "apa",
  "searchQuery": "",
  "maxResults": 5,
  "includeDetails": false,
  "minPrice": 2000,
  "maxPrice": 4000,
  "minBedrooms": 2,
  "startUrls": [],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call khadinakbar/craigslist-real-estate-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,khadinakbar/craigslist-real-estate-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/bxT9u0d8Dturh4I8F/builds/9Adh49IGMj1eXGaZ2/openapi.json
