# Craigslist Scraper: Contacts & Change Monitoring (`scrapingmonkey/craigslist-scraper`) Actor

Search Craigslist across cities and categories, extract full listing details and public contacts, monitor new or changed posts, and generate price and inventory analytics.

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

## Pricing

from $0.90 / 1,000 search listings

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

## Craigslist Scraper - Listings, Full Details, Monitoring and Market Analytics

Search public Craigslist listings across regions and categories, extract complete posting details and visible contacts, monitor changes, and turn the results into structured market data.

- Search with keywords, Craigslist URLs, regions, categories, price ranges, seller type, location radius, and native category-specific filters
- Decode exact posting IDs, timestamps, prices, locations, coordinates, images, and deep paginated results
- Enrich listings with the full description, category attributes, public phones and emails, vehicle, housing, job, and event fields
- Monitor new listings and meaningful changes through scheduled runs with persistent state
- Produce price, inventory, region, category, contact, and status analytics
- Process multiple searches and detail pages concurrently with retries and proxy rotation
- No Craigslist account, cookie, API key, or user-supplied proxy is required; production traffic always uses the built-in Apify Residential Proxy
- Export to JSON, CSV, Excel, XML, or consume results through the Apify API

### What can you do with this Actor?

| Mode / action | Input | Output | Best for |
| --- | --- | --- | --- |
| `search` | Friendly search fields or Craigslist search URLs | Fast normalized listing summaries | Discovery, lead lists, inventory collection, price tracking |
| `searchAndDetails` | The same search inputs | Search records enriched from every public posting page | Complete descriptions, visible contacts, specifications, amenities |
| `details` | Direct Craigslist posting URLs | Full normalized posting records | Enriching a known URL list or checking listing availability |
| `monitor` | Search inputs plus a stable monitor key | Only new listings or new and changed listings | Scheduled alerts, price drops, inventory and status monitoring |
| `analytics` | Search inputs and filters | Listing rows plus one aggregate analytics row | Market research and regional/category comparisons |

Search URLs and posting URLs may be mixed in one run outside `details` mode. Search enrichment replaces each summary with one complete detail record; it does not create duplicate summary and detail rows.

### Quick start

1. Open the Actor and click **Try for free**.
2. Keep **Search summaries** selected.
3. Use the default `mountain bike`, `sfbay`, and `sss` values or enter your own search.
4. Set **Results per search** and click **Start**.
5. Open the single **Results** table or download the dataset.

The default input is deliberately small and returns useful public listings without requiring any account or proxy configuration.

### Input examples

#### Search listing summaries

```json
{
  "mode": "search",
  "searchTerms": ["mountain bike", "road bike"],
  "regions": ["sfbay"],
  "categories": ["bia"],
  "maxResults": 25,
  "sort": "date",
  "hasImage": true
}
```

`maxResults` applies to every independent term × region × category combination or supplied search URL. `maxItems` can add one global cap after merging and deduplication.

#### Search and extract full details

```json
{
  "mode": "searchAndDetails",
  "searchTerms": ["toyota rav4"],
  "regions": ["sfbay", "sacramento"],
  "categories": ["cta"],
  "maxResults": 20,
  "minPrice": 5000,
  "maxPrice": 30000,
  "condition": ["20", "30", "40"],
  "sellerType": "owner",
  "includePublicContacts": true
}
```

#### Extract direct posting details

```json
{
  "mode": "details",
  "listingUrls": [
    "https://www.craigslist.org/view/d/example-listing/AbCdEf123456",
    "https://sfbay.craigslist.org/sfc/apa/d/example-apartment/7952817881.html"
  ],
  "includeImages": true,
  "includePublicContacts": true
}
```

#### Monitor new listings and changes

```json
{
  "mode": "monitor",
  "searchTerms": ["macbook pro"],
  "regions": ["sfbay"],
  "categories": ["ela"],
  "maxResults": 250,
  "monitorMode": "changes",
  "monitorKey": "bay-area-macbooks",
  "monitorIncludeDetails": true
}
```

Use the same `monitorKey` on every scheduled run. The first run treats discovered listings as new; later runs emit only newly discovered or meaningfully changed records.

#### Build market analytics

```json
{
  "mode": "analytics",
  "searchTerms": ["apartment"],
  "regions": ["sfbay"],
  "categories": ["apa"],
  "maxResults": 1000,
  "minPrice": 1000,
  "maxPrice": 5000,
  "onlyWithPrice": true,
  "analyticsOnly": true
}
```

#### Use a Craigslist search URL and advanced native filters

```json
{
  "mode": "searchAndDetails",
  "startUrls": [
    "https://www.craigslist.org/search/area/sfbay?cat=cta&query=toyota&sort=date"
  ],
  "maxResults": 100,
  "filters": {
    "min_auto_year": 2018,
    "auto_transmission": [1, 2],
    "auto_fuel_type": 1
  }
}
```

### Complete output examples

The Actor emits three stable top-level row shapes. A summary, full detail, removed listing, and monitored change all use the same 113-field listing shape; unavailable values remain explicit as `null`, `false`, `{}`, or `[]`.

#### Complete listing output - 113 top-level fields

```json
{
  "recordType": "listing",
  "resultType": "detail",
  "id": "7952817881",
  "serviceId": "mGsExampleService",
  "url": "https://www.craigslist.org/view/d/macbook-pro-14-inch/mGsExampleService",
  "canonicalUrl": "https://www.craigslist.org/view/d/macbook-pro-14-inch/mGsExampleService",
  "sourceSearchUrl": "https://sfbay.craigslist.org/search/ela?query=macbook&sort=date",
  "sourceType": "search",
  "sourceRank": 1,
  "searchTerm": "macbook",
  "requestedRegion": "sfbay",
  "requestedCategory": "ela",
  "region": "sfbay",
  "regionName": "SF bay area",
  "regionCountry": "US",
  "regionState": "CA",
  "subarea": "sby",
  "category": "ela",
  "categoryId": 96,
  "categoryGroup": "for sale",
  "categoryName": "electronics",
  "subcategory": "electronics",
  "title": "MacBook Pro 14-inch",
  "description": "Well-maintained laptop. Public contact: +1 415 555 2671.",
  "descriptionHtml": "Well-maintained laptop.<br>Public contact: +1 415 555 2671.",
  "price": 750.0,
  "currency": "USD",
  "priceText": "$750",
  "priceDetailText": "cash only",
  "locationText": "Cupertino",
  "neighborhood": "Apple Park",
  "address": "1 Infinite Loop",
  "city": "Cupertino",
  "state": "CA",
  "postalCode": "95014",
  "country": "US",
  "latitude": 37.3318,
  "longitude": -122.0312,
  "postedAt": "2026-08-10T19:00:00Z",
  "updatedAt": "2026-08-11T01:00:00Z",
  "availableFrom": null,
  "validThrough": null,
  "eventDates": [],
  "images": [
    "https://images.craigslist.org/example_600x450.jpg"
  ],
  "imageCount": 1,
  "primaryImage": "https://images.craigslist.org/example_600x450.jpg",
  "hasImages": true,
  "imageDimensionCode": "0t20CI",
  "condition": "excellent",
  "sellerType": "owner",
  "year": null,
  "make": null,
  "model": null,
  "makeModel": null,
  "vin": null,
  "odometer": null,
  "cylinders": null,
  "drivetrain": null,
  "fuel": null,
  "transmission": null,
  "titleStatus": null,
  "bodyType": null,
  "bedrooms": null,
  "bathrooms": null,
  "squareFeet": null,
  "housingType": null,
  "rentPeriod": null,
  "availability": null,
  "laundry": null,
  "parking": null,
  "petsAllowed": [],
  "furnished": null,
  "smokingAllowed": null,
  "wheelchairAccessible": null,
  "airConditioning": null,
  "evCharging": null,
  "compensation": null,
  "employmentType": null,
  "employer": null,
  "telecommuting": null,
  "internship": null,
  "nonprofit": null,
  "education": null,
  "attributes": {
    "condition": "excellent",
    "delivery_available": "delivery available"
  },
  "attributeList": [
    {
      "key": "condition",
      "label": "condition",
      "value": "excellent"
    },
    {
      "key": "delivery_available",
      "label": "delivery available",
      "value": "delivery available"
    }
  ],
  "searchMetadataCodes": {
    "4": ["3:exampleImageId"],
    "6": ["macbook-pro-14-inch"],
    "10": ["$750"],
    "13": ["mGsExampleService"]
  },
  "phones": [
    "+14155552671"
  ],
  "phoneDetails": [
    {
      "e164": "+14155552671",
      "display": "+1 415 555 2671",
      "countryCode": 1,
      "nationalNumber": "4155552671"
    }
  ],
  "emails": [
    "seller@example.com"
  ],
  "externalLinks": [
    "https://example.com/specifications"
  ],
  "hasPublicPhone": true,
  "hasPublicEmail": true,
  "hasReplyControl": true,
  "replyUrl": "/reply/sfo/ela/7952817881/mGsExampleService",
  "listingStatus": "active",
  "isActive": true,
  "isDeleted": false,
  "isExpired": false,
  "isUnavailable": false,
  "statusReason": null,
  "monitorStatus": "changed",
  "monitorKey": "bay-area-laptops",
  "previousPrice": 800.0,
  "previousScrapedAt": "2026-08-10T01:00:00Z",
  "changedFields": [
    "price",
    "description"
  ],
  "previousSnapshot": {
    "title": "MacBook Pro 14-inch",
    "description": "Earlier description",
    "price": 800.0,
    "currency": "USD",
    "locationText": "Cupertino",
    "postedAt": "2026-08-10T19:00:00Z",
    "updatedAt": null,
    "images": ["https://images.craigslist.org/example_600x450.jpg"],
    "attributes": {"condition": "excellent"},
    "phones": ["+14155552671"],
    "emails": ["seller@example.com"],
    "listingStatus": "active",
    "isDeleted": false,
    "isExpired": false,
    "isUnavailable": false
  },
  "detailEnriched": true,
  "detailHttpStatus": 200,
  "detailError": null,
  "parseConfidence": 100,
  "warnings": [],
  "scrapedAt": "2026-08-11T02:00:00Z",
  "schemaVersion": 1
}
```

#### Complete analytics output - 27 top-level fields

```json
{
  "recordType": "analytics",
  "resultType": "analytics",
  "totalListings": 250,
  "newListings": 18,
  "changedListings": 7,
  "activeListings": 248,
  "deletedListings": 1,
  "expiredListings": 1,
  "unavailableListings": 2,
  "withPrice": 231,
  "withImages": 219,
  "withPhone": 36,
  "withEmail": 12,
  "minimumPrice": 10.0,
  "maximumPrice": 5500.0,
  "averagePrice": 742.68,
  "medianPrice": 425.0,
  "currencyCounts": {
    "USD": 250
  },
  "regionCounts": {
    "sfbay": 250
  },
  "categoryCounts": {
    "ela": 250
  },
  "statusCounts": {
    "active": 248,
    "removed": 2
  },
  "topAttributes": [
    {
      "name": "condition",
      "count": 214
    }
  ],
  "postedAtMinimum": "2026-08-01T10:00:00Z",
  "postedAtMaximum": "2026-08-11T01:55:00Z",
  "generatedAt": "2026-08-11T02:00:00Z",
  "scrapedAt": "2026-08-11T02:00:00Z",
  "schemaVersion": 1
}
```

#### Complete diagnostic output - 12 top-level fields

```json
{
  "recordType": "diagnostic",
  "resultType": "diagnostic",
  "severity": "info",
  "diagnosticType": "zeroResults",
  "message": "Craigslist returned no matching listings for this search.",
  "input": "rare vintage workstation",
  "sourceSearchUrl": "https://sfbay.craigslist.org/search/sss?query=rare+vintage+workstation",
  "url": null,
  "httpStatus": null,
  "retryable": false,
  "scrapedAt": "2026-08-11T02:00:00Z",
  "schemaVersion": 1
}
```

Diagnostics describe an empty or failed input clearly and are not billing events. They appear in the same neutral **Results** table so a successful run is not presented as a wall of errors.

### What data can you extract?

Every top-level output key is listed below. Category-specific values that Craigslist introduces are preserved in `attributes` and repeated in the readable `attributeList`.

| Category | Fields |
| --- | --- |
| Row identity | `recordType`, `resultType`, `id`, `serviceId`, `url`, `canonicalUrl` |
| Search context | `sourceSearchUrl`, `sourceType`, `sourceRank`, `searchTerm`, `requestedRegion`, `requestedCategory` |
| Region and category | `region`, `regionName`, `regionCountry`, `regionState`, `subarea`, `category`, `categoryId`, `categoryGroup`, `categoryName`, `subcategory` |
| Content and price | `title`, `description`, `descriptionHtml`, `price`, `currency`, `priceText`, `priceDetailText` |
| Location | `locationText`, `neighborhood`, `address`, `city`, `state`, `postalCode`, `country`, `latitude`, `longitude` |
| Dates and media | `postedAt`, `updatedAt`, `availableFrom`, `validThrough`, `eventDates`, `images`, `imageCount`, `primaryImage`, `hasImages`, `imageDimensionCode` |
| General listing data | `condition`, `sellerType` |
| Vehicle data | `year`, `make`, `model`, `makeModel`, `vin`, `odometer`, `cylinders`, `drivetrain`, `fuel`, `transmission`, `titleStatus`, `bodyType` |
| Housing data | `bedrooms`, `bathrooms`, `squareFeet`, `housingType`, `rentPeriod`, `availability`, `laundry`, `parking`, `petsAllowed`, `furnished`, `smokingAllowed`, `wheelchairAccessible`, `airConditioning`, `evCharging` |
| Job data | `compensation`, `employmentType`, `employer`, `telecommuting`, `internship`, `nonprofit`, `education` |
| Flexible attributes | `attributes`, `attributeList`, `searchMetadataCodes` |
| Public contact data | `phones`, `phoneDetails`, `emails`, `externalLinks`, `hasPublicPhone`, `hasPublicEmail`, `hasReplyControl`, `replyUrl` |
| Availability | `listingStatus`, `isActive`, `isDeleted`, `isExpired`, `isUnavailable`, `statusReason` |
| Monitoring | `monitorStatus`, `monitorKey`, `previousPrice`, `previousScrapedAt`, `changedFields`, `previousSnapshot` |
| Parsing and provenance | `detailEnriched`, `detailHttpStatus`, `detailError`, `parseConfidence`, `warnings`, `scrapedAt`, `schemaVersion` |
| Analytics counts | `totalListings`, `newListings`, `changedListings`, `activeListings`, `deletedListings`, `expiredListings`, `unavailableListings`, `withPrice`, `withImages`, `withPhone`, `withEmail` |
| Analytics prices and groups | `minimumPrice`, `maximumPrice`, `averagePrice`, `medianPrice`, `currencyCounts`, `regionCounts`, `categoryCounts`, `statusCounts`, `topAttributes` |
| Analytics dates | `postedAtMinimum`, `postedAtMaximum`, `generatedAt` |
| Diagnostics | `severity`, `diagnosticType`, `message`, `input`, `httpStatus`, `retryable` |

### Input parameters

| Parameter | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `mode` | string | Yes | `search` | `search`, `searchAndDetails`, `details`, `monitor`, or `analytics` |
| `searchTerms` | string\[] | Search workflows | `["mountain bike"]` | Keywords; combined with every friendly region and category |
| `regions` | string\[] | Search workflows | `["sfbay"]` | Craigslist host/region names such as `sfbay`, `newyork`, `london`, `tokyo` |
| `categories` | string\[] | Search workflows | `["sss"]` | Three-character category codes such as `sss`, `cta`, `apa`, `jjj`, `ggg`, `bbb` |
| `startUrls` | string\[] | No | - | Current or legacy Craigslist search URLs and/or posting URLs |
| `listingUrls` | string\[] | Details mode | - | Direct public Craigslist posting URLs |
| `maxResults` | integer | No | `50` | Results per independent friendly search or search URL; 1-5,000 |
| `maxItems` | integer | No | `0` | Global listing limit after merge and deduplication; 0 means unlimited, maximum 100,000 |
| `maxConcurrency` | integer | No | `5` | Parallel searches/detail requests; 1-20 |
| `maxRequestRetries` | integer | No | `4` | Retry attempts with backoff and proxy-session rotation; 1-10 |
| `country` | string | No | `US` | Two-letter request locale country; the Craigslist region controls listing currency |
| `language` | string | No | `en` | Interface language/locale such as `en`, `de`, `fr`, `ja`, or `en-GB` |
| `sort` | string | No | `date` | `date`, `rel`, `priceasc`, `pricedsc`, `dateoldest`, or `dist` |
| `minPrice` | number | No | - | Minimum non-negative listing price |
| `maxPrice` | number | No | - | Maximum non-negative listing price |
| `condition` | string\[] | No | - | Craigslist condition codes: `10`, `20`, `30`, `40`, `50`, `60` |
| `sellerType` | string | No | `all` | `all`, `owner`, or `dealer` |
| `hasImage` | boolean | No | `false` | Ask Craigslist for listings containing an image |
| `postedToday` | boolean | No | `false` | Ask Craigslist for listings posted today |
| `hideDuplicates` | boolean | No | `true` | Ask Craigslist to hide bundled duplicates |
| `deliveryAvailable` | boolean | No | `false` | Require delivery where supported by the category |
| `titlesOnly` | boolean | No | `false` | Match the search term against titles only |
| `postalCode` | string | With distance | - | Center of a radius search |
| `searchDistance` | number | With postal code | - | Non-negative radius in the region's native distance units |
| `filters` | object | No | `{}` | Native Craigslist parameters; scalar and array values are supported |
| `maxAgeDays` | number | No | - | Locally discard records older than this many days |
| `includeImages` | boolean | No | `true` | Include full image URLs and media counts |
| `includePublicContacts` | boolean | No | `true` | Extract only phones/emails written publicly in the posting body |
| `onlyWithPrice` | boolean | No | `false` | Discard records without a numeric price before storage and billing |
| `onlyWithImages` | boolean | No | `false` | Discard records without images before storage and billing |
| `deduplicate` | boolean | No | `true` | Keep one record per posting across overlapping inputs |
| `includeAnalytics` | boolean | No | `false` | Add one analytics row in a search, detail, or monitor run |
| `analyticsOnly` | boolean | No | `false` | Calculate and store analytics without individual listing rows |
| `monitorMode` | string | No | `changes` | `changes` emits new and changed records; `newListings` emits only new records |
| `monitorKey` | string | Monitor mode | `craigslist-monitor` | Stable 1-80 character identity for persistent monitor state |
| `monitorIncludeDetails` | boolean | No | `false` | Open details during monitoring to detect content/contact/attribute changes |

There is intentionally no proxy field. Apify Residential Proxy is created internally for every production run, and direct Craigslist traffic is rejected by the runtime.

### Use cases

#### Classified lead discovery

Collect fresh owner, dealer, service, gig, or job postings across multiple cities. Use full-detail mode when the workflow needs public contact details written in the listing body.

#### Price and inventory intelligence

Track vehicles, electronics, furniture, rentals, or other categories by region. Filter comparable listings and use the analytics row for median, average, minimum, and maximum pricing.

#### Housing and vehicle datasets

Extract promoted fields such as bedrooms, bathrooms, square feet, amenities, VIN, mileage, drivetrain, transmission, and title status while keeping every other Craigslist attribute in a flexible object.

#### Scheduled change alerts

Run `monitor` on an Apify schedule. Send a webhook to Slack, Make, Zapier, n8n, a CRM, or a database only when a listing appears or changes.

#### Regional market research

Combine terms, regions, and categories into one run, deduplicate overlaps, and compare availability, image coverage, visible-contact coverage, attributes, and price distributions.

### Performance and cost

This Actor is designed for pay-per-event pricing. Exact prices are displayed in the Actor's **Pricing** tab and depend on the published plan.

| Event | Emitted for | Relative request work |
| --- | --- | --- |
| `listing-summary` | One saved search-only listing | Lowest: search API requests are shared across many results |
| `listing-detail` | One successfully enriched detail record | Higher: opens one public detail page per listing |
| `listing-change` | One new or changed monitor result | Depends on `monitorIncludeDetails` |
| `analytics-summary` | One aggregate analytics row | One event after the source listings are processed |

Diagnostic rows and unavailable direct-detail rows that could not be enriched do not call a custom charge event. Filtering happens before storage and billing. `searchAndDetails`, `monitorIncludeDetails`, high `maxResults`, many search combinations, and high retry counts increase runtime and proxy usage.

Measured Apify timing and price examples should be added after repeatable runs on the published Actor; this README does not invent fixed throughput or cost claims.

### API usage

Replace `YOUR_USERNAME` with the published Actor owner name.

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/YOUR_USERNAME~craigslist-scraper/runs?token=APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "mode": "searchAndDetails",
    "searchTerms": ["mountain bike"],
    "regions": ["sfbay"],
    "categories": ["bia"],
    "maxResults": 10
  }'
```

Use the dataset API directly or connect Apify to Google Sheets, Make, Zapier, n8n, Airbyte, webhooks, Slack, a CRM, or a data warehouse.

### Best for / not for

**Best for:** public Craigslist search, category browsing, known posting enrichment, public contact extraction, multi-region datasets, market analytics, and scheduled listing/change monitoring.

**Not for:** account-only data, posting or messaging sellers, anonymized Craigslist relay-email extraction, captcha solving, private contact discovery, account automation, or real-time streaming.

### Limits and good to know

- One workflow mode is selected per run, but search and posting URLs can coexist outside `details` mode.
- `maxResults` is per independent search; `maxItems` is the optional global listing cap.
- The Actor reproduces Craigslist's cache-based batch pagination for results beyond the first response and stops at the requested/source limit.
- Craigslist category support is broad: umbrella codes and category-specific filters can be passed through `filters` without a code update.
- Search rows contain the fields exposed by search. Full descriptions, public contacts, JSON-LD data, and detailed attributes require `searchAndDetails`, `details`, or detail-enabled monitoring.
- Currency follows the selected Craigslist area. `country` and `language` influence request localization but do not convert prices.
- Missing source values remain explicit. Listing rows always keep the same 113 top-level fields.
- A removed or redirected posting is returned as an unavailable listing when it can be identified; failed/empty inputs produce clear diagnostic rows.
- Requests retry with exponential backoff, honor `Retry-After`, and rotate the proxy session on retryable failures. Other inputs continue after a partial failure.
- Public contact extraction never opens the reply challenge. `replyUrl` only records the public reply-control path already present in the HTML.
- Source websites and internal public-web endpoints can change. Pin production automations to tested Actor builds and report reproducible parser regressions.

### Frequently asked questions

#### What input should I provide?

For a normal search, provide a keyword, region, and three-character category code, for example `mountain bike`, `sfbay`, and `bia`. You may instead paste a current/legacy Craigslist search URL or a direct posting URL.

#### Which category codes are supported?

The Actor accepts Craigslist's three-character codes instead of a short hardcoded list. Common umbrella codes are `bbb` services, `ccc` community, `eee` events, `ggg` gigs, `hhh` housing, `jjj` jobs, `rrr` resumes, and `sss` for sale. Examples of high-value subcategories are `cta`, `ela`, `fua`, `bia`, `apa`, `roo`, and `sub`.

#### How many results can I extract?

Set 1-5,000 results per independent search and optionally 0-100,000 listings globally. The actual count still depends on Craigslist availability, filters, duplicates, removed postings, and the selected category/region.

#### Why is `description` empty in search mode?

Fast search summaries do not open every detail page. Select `searchAndDetails` to retrieve the complete body, HTML, public contacts, and detailed attributes.

#### Why are vehicle or housing fields `null`?

The 113-field listing shape is shared across categories. A laptop does not have bedrooms and an apartment does not have a VIN. Category-specific values also remain available in `attributes`.

#### Can I process multiple inputs?

Yes. Friendly values form a term × region × category matrix, and `startUrls` can add search or posting URLs. Actor-level deduplication keeps one listing per posting identity by default.

#### Can I schedule recurring runs?

Yes. Use `monitor` with a stable `monitorKey`, an Apify schedule, and optional webhooks. State is committed only after successful output so a billing limit does not silently advance the monitor.

#### Do I need an account, API key, cookies, or proxy?

No Craigslist account, cookie, or API key is needed. The Actor automatically uses Apify Residential Proxy for every production request; users do not configure or see a proxy input.

#### Does it extract Craigslist relay email addresses?

No. The anonymized reply flow may require a challenge. This Actor intentionally avoids captcha/reply-email automation and extracts only phones and email addresses visibly written in the public listing body.

### Responsible use

This Actor extracts publicly available information. Users are responsible for complying with applicable laws, privacy regulations, contractual obligations, and Craigslist's terms. Avoid unwanted contact, sensitive-data profiling, and excessive collection.

Craigslist is a trademark of craigslist, Inc. This Actor is an independent product and is not affiliated with, endorsed by, or sponsored by craigslist, Inc.

### Support

If a public listing or search stops parsing, create an issue in the Actor's **Issues** tab. Include the Apify run ID, mode, non-sensitive input, expected result, and one reproducible public URL. Never include proxy credentials, cookies, tokens, or private contact information.

### Local verification

Run the unit and fixture regression suite:

```bash
python -m unittest discover -s tests -v
```

The optional `scripts/live_smoke.py` accepts a private local proxy file for development verification. It is excluded from the production image. The release runtime has no path to that file and always creates Apify Residential Proxy internally.

# Actor input Schema

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

Search returns fast summaries. Search + details opens every listing. Details accepts posting URLs. Monitor returns new or changed listings. Analytics adds a market summary.

## `searchTerms` (type: `array`):

Keywords or phrases. Leave an empty string out and use a category URL when you want an unfiltered category browse.

## `regions` (type: `array`):

Region hostnames such as sfbay, newyork, london, tokyo, or manila. Multiple regions are combined with every term and category.

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

Three-character Craigslist category abbreviations such as sss, cta, apa, jjj, ggg, or bbb.

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

Optional current or legacy Craigslist search and posting URLs. Search URL parameters are preserved. Mixed lists are supported outside Details mode.

## `listingUrls` (type: `array`):

Direct Craigslist posting URLs for Details mode or additional detail records in another mode.

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

Maximum listings returned for every independent term × region × category or search URL.

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

Maximum deduplicated listing rows across the whole run. Use 0 for unlimited. Analytics and diagnostic rows are additional.

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

Independent searches and detail pages processed in parallel.

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

Retry attempts for rate limits, temporary server failures, proxy failures, and timeouts. The proxy session rotates after retryable failures.

## `country` (type: `string`):

Two-letter locale country sent to Craigslist, such as US, GB, CA, JP, or PH. Listing prices still follow the selected Craigslist region.

## `language` (type: `string`):

Craigslist interface language or locale such as en, de, fr, ja, or en-GB.

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

Sort every friendly search by newest, relevant, price, oldest, or distance.

## `minPrice` (type: `number`):

Minimum listing price. Applied to Craigslist and verified again before output.

## `maxPrice` (type: `number`):

Maximum listing price. Applied to Craigslist and verified again before output.

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

Craigslist condition values: 10 new, 20 like new, 30 excellent, 40 good, 50 fair, 60 salvage.

## `sellerType` (type: `string`):

All listings, owner listings, or dealer listings.

## `hasImage` (type: `boolean`):

Ask Craigslist to return listings that contain at least one image.

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

Keep Craigslist results posted today.

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

Ask Craigslist to hide bundled duplicate postings. Actor-level ID deduplication remains enabled separately.

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

Keep listings marked as offering delivery where the selected category supports it.

## `titlesOnly` (type: `boolean`):

Match the keyword against listing titles instead of the full Craigslist search index.

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

Center for a radius search. Provide Search distance too.

## `searchDistance` (type: `number`):

Radius around Postal code in the Craigslist region's native distance units.

## `filters` (type: `object`):

Native Craigslist query parameters as JSON. Values may be strings, numbers, booleans, or arrays for repeated parameters, for example {"min\_auto\_year": 2018, "auto\_transmission": \[1, 2]}.

## `maxAgeDays` (type: `number`):

Discard listings older than this many days after decoding the exact posting timestamp.

## `includeImages` (type: `boolean`):

Return full 600×450 Craigslist image URLs and image counts.

## `includePublicContacts` (type: `boolean`):

Extract only phone numbers and email addresses written publicly in the listing body. The anonymized reply-email challenge is never opened.

## `onlyWithPrice` (type: `boolean`):

Discard listings without a numeric price before storage and billing.

## `onlyWithImages` (type: `boolean`):

Discard listings without images before storage and billing.

## `deduplicate` (type: `boolean`):

Keep one record per Craigslist posting across overlapping terms, categories, regions, and input URLs.

## `includeAnalytics` (type: `boolean`):

Add one analytics row with listing, price, contact, region, category, status, and attribute statistics.

## `analyticsOnly` (type: `boolean`):

Use the scraped listings to calculate analytics but omit individual listing rows. Diagnostics remain visible and uncharged.

## `monitorMode` (type: `string`):

Return only never-seen listings or both new listings and changes to price, content, images, contacts, attributes, or availability.

## `monitorKey` (type: `string`):

Stable name that identifies this monitor's persistent state across scheduled runs.

## `monitorIncludeDetails` (type: `boolean`):

Open every discovered posting so changes to descriptions, contacts, attributes, and status can be detected. Leave off for cheaper price-only monitoring.

## Actor input object example

```json
{
  "mode": "search",
  "searchTerms": [
    "mountain bike"
  ],
  "regions": [
    "sfbay"
  ],
  "categories": [
    "sss"
  ],
  "maxResults": 50,
  "maxItems": 0,
  "maxConcurrency": 5,
  "maxRequestRetries": 4,
  "country": "US",
  "language": "en",
  "sort": "date",
  "sellerType": "all",
  "hasImage": false,
  "postedToday": false,
  "hideDuplicates": true,
  "deliveryAvailable": false,
  "titlesOnly": false,
  "filters": {},
  "includeImages": true,
  "includePublicContacts": true,
  "onlyWithPrice": false,
  "onlyWithImages": false,
  "deduplicate": true,
  "includeAnalytics": false,
  "analyticsOnly": false,
  "monitorMode": "changes",
  "monitorKey": "craigslist-monitor",
  "monitorIncludeDetails": false
}
```

# Actor output Schema

## `dataset` (type: `string`):

Complete Craigslist listing summaries, enriched details, monitored changes, analytics summaries, and clear uncharged diagnostics in one Results table.

# 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 = {};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapingmonkey/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 = {}

# Run the Actor and wait for it to finish
run = client.actor("scrapingmonkey/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 '{}' |
apify call scrapingmonkey/craigslist-scraper --silent --output-dataset

```

## MCP server setup

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