# Craigslist Classifieds Scraper — No Login Required (`crowdpull/craigslist-scraper`) Actor

Extract Craigslist listings across real estate, cars, jobs, gigs, services, for-sale, free stuff, community, and events. No login or cookies needed. Supports API-first search, postal-radius scoping, detail/contact enrichment, Smart Scrape, garage-sale dates, and real estate presets.

- **URL**: https://apify.com/crowdpull/craigslist-scraper.md
- **Developed by:** [Crowd Pull](https://apify.com/crowdpull) (community)
- **Categories:** E-commerce, Real estate, Jobs
- **Stats:** 11 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 search-card listing extracteds

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/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

## Craigslist Classifieds Scraper

Extract Craigslist listings across real estate, cars, jobs, gigs, services, for-sale, free stuff, community, events, resumes, and direct post URLs. No login or cookies needed.

This actor is API-first. It calls Craigslist's public JSON search endpoint, decodes listing rows, and optionally hydrates post pages for full descriptions and attributes. Real estate is the highlighted workflow, with presets and output fields for apartments, rooms, sublets, FSBO, office/commercial, parking, beds, baths, square feet, pets, and furnished searches.

### Features

- All major Craigslist categories in one actor
- Real estate presets and dedicated dataset view
- Postal-radius scoping for accurate geography
- Multi-city and multi-category fanout
- Search-card mode for fast, low-cost runs
- Optional detail enrichment for full descriptions and attributes
- Optional public contact extraction from posting pages, including visible phone/email text, mailto/tel links, and Craigslist reply URL metadata
- Owner/dealer/all `listingType`, native duplicate hiding, nearby search, delivery-available, and condition filters
- Garage and moving sale date filters with `startDate` / `endDate`
- Deleted, expired, and unavailable detail-page status fields for direct URLs and detail-enriched searches
- Smart Scrape mode to emit only new or changed listings on scheduled runs
- Canonical listing URLs, posting IDs, timestamps, images, location, price, and category-specific fields

### Example Input

```json
{
  "searches": [
    {
      "city": "newyork",
      "postalCode": "10001",
      "searchDistance": 5,
      "category": "apa",
      "query": "studio",
      "listingType": "owner",
      "minBedrooms": 0,
      "maxPrice": 3500,
      "includeDetails": true,
      "includeContactInfo": true,
      "maxResultsPerSearch": 50
    },
    {
      "city": "sfbay",
      "postalCode": "94103",
      "searchDistance": 25,
      "category": "cta",
      "query": "honda civic",
      "condition": ["good", "excellent"],
      "deliveryAvailable": true,
      "maxResultsPerSearch": 100
    },
    {
      "city": "sfbay",
      "postalCode": "94103",
      "searchDistance": 25,
      "category": "gms",
      "startDate": "2026-06-06",
      "endDate": "2026-06-07",
      "maxResultsPerSearch": 50
    }
  ],
  "onlyNew": false
}
```

### Smart Scrape

Set `onlyNew` to `true` and keep the same `cacheName` for scheduled runs. The actor stores a material hash for each posting ID and only emits rows that are new or meaningfully changed.

```json
{
  "city": "detroit",
  "postalCode": "48201",
  "searchDistance": 20,
  "categories": ["apa", "roo", "sub", "rea"],
  "onlyNew": true,
  "cacheName": "detroit-housing-monitor",
  "maxResultsPerSearch": 200
}
```

### Output

Each dataset item is a normalized Craigslist listing:

```json
{
  "type": "listing",
  "source": "craigslist",
  "status": "ok",
  "postingId": "7938170495",
  "url": "https://newyork.craigslist.org/brk/apa/d/brooklyn-no-fee-lrg-studio-loft-home/7938170495.html",
  "title": "No Fee, Lrg Studio Loft + Home Office/1 Bed",
  "category": "apa",
  "categoryLabel": "apartments",
  "listingType": "owner",
  "city": "newyork",
  "price": 3450,
  "priceText": "$3,450",
  "postedAt": "2026-06-01T23:32:13.000Z",
  "updatedAt": "2026-06-02T12:14:00.000Z",
  "neighborhood": "Bed-Stuy",
  "bedrooms": 1,
  "squareFeet": 855,
  "imageUrls": ["https://images.craigslist.org/example_600x450.jpg"],
  "listingStatus": "active",
  "isDeleted": false,
  "isExpired": false,
  "contactInfoAvailable": true,
  "contactPhones": ["212-555-0100"],
  "replyUrlTemplate": "https://newyork.craigslist.org/reply/...",
  "searchPostalCode": "10001",
  "searchDistance": 5,
  "scrapedAt": "2026-06-02T00:00:00.000Z"
}
```

### Pricing

Recommended pay-per-event pricing:

- Actor start: low fixed start fee
- `listing-extracted`: about $0.00275 to $0.0035 per search-card listing
- `detail-enriched`: about $0.00625 to $0.0075 per detail/contact-enriched listing

Detail/contact enrichment is optional so broad classifieds users can run cheaply while higher-value real estate monitoring pays for richer rows.

### Limitations

- Craigslist's JSON endpoint scopes reliably by postal code and search radius. The actor includes default postal codes for common city subdomains, but exact workflows should pass `postalCode`.
- The actor does not log in, bypass reply flows, or extract private contact details. `includeContactInfo` only parses public posting-page text, public mailto/tel links, and Craigslist reply metadata when exposed.
- Detail enrichment fetches public posting pages and may miss fields that Craigslist does not expose in public HTML.
- Craigslist can remove or expire postings at any time; direct post URLs and detail-enriched rows surface `listingStatus`, `isDeleted`, `isExpired`, and `detailFailureReason` when this is detectable.

# Actor input Schema

## `searches` (type: `array`):

Run one or more Craigslist searches. Each search can override city, postal code, category, query, filters, and max results. Leave empty to use the top-level fields below.

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

Optional Craigslist search/category/post URLs. Search URL filters are preserved when possible. Direct post URLs are hydrated as detail records.

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

Craigslist city subdomain such as newyork, sfbay, detroit, seattle, chicago, losangeles, or miami. A default postal code is used for popular cities; add postalCode for exact scoping.

## `cities` (type: `array`):

Optional list of Craigslist city subdomains. Each city runs the same top-level filters. Add postalCode inside searches\[] for exact per-city scoping.

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

ZIP/postal code for accurate Craigslist API scoping. Recommended whenever geography matters.

## `searchDistance` (type: `integer`):

Radius around the postal code in miles.

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

Craigslist category code. Real estate examples: apa apartments, hhh all housing, rea real estate for sale, roo rooms, sub sublets, vac vacation rentals, off office, prk parking. Broad examples: sss for sale, cta cars, gms garage sales, jjj jobs, ggg gigs, srv services, ccc community, eee events, zip free stuff.

## `categories` (type: `array`):

Optional list of category codes to run with the same filters. Use this for all-housing or all-classifieds fanout.

## `query` (type: `string`):

Free-text Craigslist search query. Leave empty to browse the latest listings in the category.

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

Minimum price in the local Craigslist currency.

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

Maximum price in the local Craigslist currency.

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

Only return listings Craigslist marks as posted in the last 24 hours.

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

Only return listings with at least one image.

## `ownerOnly` (type: `boolean`):

Compatibility toggle for owner/private posts. Prefer listingType for owner/dealer/all workflows.

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

Craigslist owner/dealer filter. Use owner for private-owner real-estate or vehicle searches, dealer for dealer listings, or all for no seller filter.

## `hideDuplicates` (type: `boolean`):

Ask Craigslist to bundle/hide duplicate postings when supported by the category.

## `searchNearby` (type: `boolean`):

Ask Craigslist to include nearby areas when supported by the search endpoint.

## `deliveryAvailable` (type: `boolean`):

Only return listings marked with delivery available when Craigslist supports the filter.

## `condition` (type: `array`):

Optional Craigslist condition filters. Use values like new, like-new, excellent, good, fair, salvage, or numeric Craigslist codes 10/20/30/40/50/60.

## `sort` (type: `string`):

Craigslist sort order.

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

Minimum number of bedrooms for housing categories.

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

Maximum number of bedrooms for housing categories.

## `minBathrooms` (type: `number`):

Minimum number of bathrooms for housing categories.

## `maxBathrooms` (type: `number`):

Maximum number of bathrooms for housing categories.

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

Minimum square footage for housing categories.

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

Maximum square footage for housing categories.

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

Only include housing listings that allow cats when Craigslist supports the filter.

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

Only include housing listings that allow dogs when Craigslist supports the filter.

## `furnished` (type: `boolean`):

Only include furnished housing listings when Craigslist supports the filter.

## `startDate` (type: `string`):

Garage-sale date filter start, formatted as YYYY-MM-DD.

## `endDate` (type: `string`):

Garage-sale date filter end, formatted as YYYY-MM-DD. Date ranges are capped at 31 days.

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

Fetch each posting page for full description, attribute text, and richer images. Search-card mode is faster and cheaper.

## `includeContactInfo` (type: `boolean`):

Fetch each public posting page and extract visible phone/email text, mailto/tel links, and Craigslist reply URL metadata when exposed.

## `onlyNew` (type: `boolean`):

Use a named key-value store cache to emit only listings that are new or materially changed since a previous run.

## `cacheName` (type: `string`):

Named key-value store used by onlyNew. Keep the same value for scheduled monitor runs.

## `maxResultsPerSearch` (type: `integer`):

Maximum listings to save per normalized search. Craigslist API batches are fetched in 360-item pages.

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

Maximum concurrent detail-page fetches when includeDetails or includeContactInfo is enabled.

## `requestDelayMs` (type: `integer`):

Delay between Craigslist search API batch requests.

## `maxRequestRetries` (type: `integer`):

Retry attempts for transient Craigslist API/detail failures.

## `saveDebugHtml` (type: `boolean`):

Save failed detail-page HTML/error snippets to the default key-value store.

## Actor input object example

```json
{
  "searches": [
    {
      "city": "newyork",
      "postalCode": "10001",
      "searchDistance": 5,
      "category": "apa",
      "query": "studio",
      "listingType": "owner",
      "maxResultsPerSearch": 50,
      "includeDetails": true,
      "includeContactInfo": true
    },
    {
      "city": "detroit",
      "postalCode": "48201",
      "searchDistance": 20,
      "category": "zip",
      "maxResultsPerSearch": 50
    }
  ],
  "startUrls": [
    {
      "url": "https://sfbay.craigslist.org/search/cta?query=honda%20civic&postal=94103&search_distance=25"
    }
  ],
  "city": "newyork",
  "postalCode": "10001",
  "searchDistance": 25,
  "category": "apa",
  "query": "studio",
  "postedToday": false,
  "hasPic": false,
  "ownerOnly": false,
  "listingType": "all",
  "hideDuplicates": false,
  "searchNearby": false,
  "deliveryAvailable": false,
  "sort": "date",
  "catsOk": false,
  "dogsOk": false,
  "furnished": false,
  "includeDetails": false,
  "includeContactInfo": false,
  "onlyNew": false,
  "cacheName": "craigslist-scraper-cache",
  "maxResultsPerSearch": 100,
  "maxConcurrency": 4,
  "requestDelayMs": 250,
  "maxRequestRetries": 3,
  "saveDebugHtml": false
}
```

# Actor output Schema

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

No description

## `summary` (type: `string`):

No description

## `searchSpecs` (type: `string`):

No description

## `failedTargets` (type: `string`):

No description

# 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 = {
    "searches": [
        {
            "city": "newyork",
            "postalCode": "10001",
            "searchDistance": 5,
            "category": "apa",
            "query": "studio",
            "listingType": "owner",
            "maxResultsPerSearch": 50,
            "includeDetails": true,
            "includeContactInfo": true
        },
        {
            "city": "detroit",
            "postalCode": "48201",
            "searchDistance": 20,
            "category": "zip",
            "maxResultsPerSearch": 50
        }
    ],
    "startUrls": [
        {
            "url": "https://sfbay.craigslist.org/search/cta?query=honda%20civic&postal=94103&search_distance=25"
        }
    ],
    "city": "newyork",
    "postalCode": "10001",
    "category": "apa",
    "query": "studio"
};

// Run the Actor and wait for it to finish
const run = await client.actor("crowdpull/craigslist-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 = {
    "searches": [
        {
            "city": "newyork",
            "postalCode": "10001",
            "searchDistance": 5,
            "category": "apa",
            "query": "studio",
            "listingType": "owner",
            "maxResultsPerSearch": 50,
            "includeDetails": True,
            "includeContactInfo": True,
        },
        {
            "city": "detroit",
            "postalCode": "48201",
            "searchDistance": 20,
            "category": "zip",
            "maxResultsPerSearch": 50,
        },
    ],
    "startUrls": [{ "url": "https://sfbay.craigslist.org/search/cta?query=honda%20civic&postal=94103&search_distance=25" }],
    "city": "newyork",
    "postalCode": "10001",
    "category": "apa",
    "query": "studio",
}

# Run the Actor and wait for it to finish
run = client.actor("crowdpull/craigslist-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 '{
  "searches": [
    {
      "city": "newyork",
      "postalCode": "10001",
      "searchDistance": 5,
      "category": "apa",
      "query": "studio",
      "listingType": "owner",
      "maxResultsPerSearch": 50,
      "includeDetails": true,
      "includeContactInfo": true
    },
    {
      "city": "detroit",
      "postalCode": "48201",
      "searchDistance": 20,
      "category": "zip",
      "maxResultsPerSearch": 50
    }
  ],
  "startUrls": [
    {
      "url": "https://sfbay.craigslist.org/search/cta?query=honda%20civic&postal=94103&search_distance=25"
    }
  ],
  "city": "newyork",
  "postalCode": "10001",
  "category": "apa",
  "query": "studio"
}' |
apify call crowdpull/craigslist-scraper --silent --output-dataset

```

## MCP server setup

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