# Craigslist Scraper + Listing Change Monitor (`luminar/craigslist-scraper-listing-monitor`) Actor

Collect rich source-published Craigslist listing data across locations, categories, queries, and direct URLs, or track verified NEW, UPDATED, and ENDED changes.

- **URL**: https://apify.com/luminar/craigslist-scraper-listing-monitor.md
- **Developed by:** [Luka](https://apify.com/luminar) (community)
- **Categories:** Automation, 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.80 / 1,000 craigslist 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/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

Collect current Craigslist listings across multiple locations, categories, search terms, and direct URLs—or run the same scope repeatedly to receive only verified changes.

The Actor returns source-published fields and mechanical normalization. It does not score listings, recommend purchases, infer quality, estimate value, or reinterpret the seller’s text.

![Actual Craigslist listing rows from a verified Actor run](https://api.apify.com/v2/key-value-stores/DJgPR6wwS2tIaLDQW/records/craigslist_listing_monitor--c451a6d6a2180349-craigslist-listings-dataset.png)

### Two clear workflows

#### Get current listings

Use `current` for a fresh export. Search cards include stable listing ID, URL, title, published price, location text, category provenance, and matching target IDs. Enable **Open each listing for full details** to add the source description, posting/update timestamps, published attributes, map coordinates, and image URLs to the same result row.

#### Track new/changed listings

The first run of `changes` establishes a verified baseline and emits `NEW` rows for listings in that complete scope. Use the same scope and `stateNamespace` on repeat runs:

- `NEW` — first verified appearance in this scope, including the baseline run.
- `UPDATED` — one or more normalized source fields changed.
- `ENDED` — the listing was absent from two sequential, comparable, complete scans.

Unchanged listings produce no Dataset row. A capped, blocked, partial, or failed scan cannot emit `ENDED` and cannot commit monitoring state.

### Quick start

```json
{
  "workflow": "current",
  "locations": ["newyork"],
  "categories": ["sss"],
  "searchQueries": ["bicycle"],
  "maxItems": 25
}
```

You may also provide `startUrls` for existing Craigslist search pages and `listingUrls` for direct listings. Generated searches combine every location, category, and search term, then deduplicate identical targets. The run fails before source traffic if the combination exceeds 50 targets.

### Input guide and search controls

Available source filters include price range, owner/dealer, free listings, photos, posted today, Craigslist duplicate bundling, delivery, postal radius, nearby areas, condition codes, bedroom/bathroom ranges, cats/dogs, and sort order. These values are sent as Craigslist search parameters and included in the monitoring scope fingerprint.

### Output contract

Every Dataset row declares `recordType` (`listing` or `change`). Change rows also declare `changeType`, `changedFields`, `before`, and `after`. `stableId` is based on Craigslist’s opaque current identity or accepted legacy numeric posting ID—not the search position or URL slug.

The `OUTPUT` Key-Value Store record is authoritative for coverage, target receipts, delivery count, state commit, resource guards, route, billing mode, and limitations. Empty searches are reported as `EMPTY_CONFIRMED`; they are never represented by fake Dataset rows.

### Coverage and reliability

Every run reports one explicit coverage state. `COMPLETE` means the bounded request finished. `CAPPED` means a declared row, request, byte, runtime, or spending guard stopped additional work after preserving any trustworthy prefix allowed by the selected workflow. `BLOCKED` and `FAILED` never advance monitoring state. `EMPTY_CONFIRMED` is a positive source-backed empty result, not a placeholder row. A changes run commits its new snapshot only after its delivered events are confirmed.

### API and automation

Use the same JSON input with the Apify API, client libraries, webhooks, or your own scheduled workflow. For monitoring, keep the same `stateNamespace` and search scope on later runs. The Dataset contains delivered rows; the `OUTPUT` Key-Value Store record contains authoritative coverage, target receipts, billing status, resource guards, and state status. This Actor does not create Tasks or schedules for you.

### Safety and boundaries

The Actor uses public listing/search pages only. It does not visit reply, email, CAPTCHA, account, login, or contact-deanonymization routes. It does not create an email field. It returns source fields and mechanical normalization without adding an opinion about the listing.

### Pricing status

Pricing is not active in this private build. Any future event pricing requires a separate owner decision and an exact read-back before it can be presented as active.

### FAQ and support

**Why can a current run be CAPPED and still return rows?** Current export can safely return the trustworthy prefix up to `maxItems`. Changes mode is stricter and will not commit state or emit `ENDED` from an incomplete scan.

**Are descriptions and images always present?** No. Enable **Open each listing for full details** to request fields available on the listing page. A field remains null or empty when Craigslist does not publish it or the bounded detail request is unavailable.

**Does this Actor evaluate a deal or seller?** No. It does not score, rank, recommend, infer seller quality, or estimate market value. Review the source listing yourself.

# Actor input Schema

## `workflow` (type: `string`):

Current delivers source-published listings. Changes keeps a scope-specific snapshot and delivers only NEW, UPDATED, or safely confirmed ENDED events.

## `searchQueries` (type: `array`):

Each term is combined with every location and category below. Leave empty to browse the category without a keyword.

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

Craigslist subdomain names such as newyork, sfbay, chicago, or losangeles.

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

Craigslist category codes such as sss (for sale), apa (apartments), or jjj (jobs).

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

Optional existing Craigslist search or listing pages. These are added to generated targets and deduplicated.

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

Optional direct listing pages. No reply, email, account, or CAPTCHA route is visited.

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

Hard delivery ceiling. Current can report CAPPED with a useful prefix. Changes never commits state or emits ENDED from a capped scan.

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

Adds description, published attributes, map coordinates, timestamps, and image URLs to the same listing result. It is not a separate paid result.

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

Minimum source search price.

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

Maximum source search price.

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

Keep all sellers or request Craigslist owner/dealer results.

## `onlyFreeListings` (type: `boolean`):

Request only listings published as free.

## `onlyWithPhotos` (type: `boolean`):

Request only listings that publish at least one photo.

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

Request listings posted today.

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

Ask Craigslist to bundle its duplicate listings.

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

Request listings marked with delivery availability.

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

Postal code used by the source radius search.

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

Maximum source search radius from the postal code.

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

Ask Craigslist to include nearby areas.

## `conditions` (type: `array`):

Optional Craigslist condition values. Values are passed through as source filter codes, not interpreted.

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

Minimum bedroom count sent to applicable housing searches.

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

Maximum bedroom count sent to applicable housing searches.

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

Minimum bathroom count sent to applicable housing searches.

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

Maximum bathroom count sent to applicable housing searches.

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

Request applicable housing listings marked as allowing cats.

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

Request applicable housing listings marked as allowing dogs.

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

Craigslist source sort order.

## `stateNamespace` (type: `string`):

Stable buyer-supplied name that separates monitoring states.

## `maxBuyerChargeUsd` (type: `number`):

Stops before source work when the maximum event vector could exceed this ceiling. Pricing remains inactive until owner approval.

## `maxRequests` (type: `integer`):

Internal run-wide Craigslist request ceiling.

## `maxSourceBytes` (type: `integer`):

Internal run-wide source transfer ceiling.

## `maxRuntimeSecs` (type: `integer`):

Internal source-work runtime ceiling.

## `detailConcurrency` (type: `integer`):

Internal maximum concurrent listing-detail requests.

## `_luminarQaFaultStage` (type: `string`):

Factory QA only; rejected outside the exact registered private QA Actor and immutable build.

## Actor input object example

```json
{
  "workflow": "current",
  "searchQueries": [
    "bicycle"
  ],
  "locations": [
    "newyork"
  ],
  "categories": [
    "sss"
  ],
  "maxItems": 25,
  "includeDetails": false,
  "sellerType": "all",
  "onlyFreeListings": false,
  "onlyWithPhotos": false,
  "postedToday": false,
  "hideDuplicates": true,
  "deliveryAvailable": false,
  "searchNearby": false,
  "catsOk": false,
  "dogsOk": false,
  "sort": "date",
  "stateNamespace": "default",
  "maxBuyerChargeUsd": 5,
  "maxRequests": 2200,
  "maxSourceBytes": 500000000,
  "maxRuntimeSecs": 3600,
  "detailConcurrency": 4
}
```

# Actor output Schema

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

Open every current-listing or verified-change row delivered by this run.

## `listings` (type: `string`):

Open the Dataset with the most useful listing columns selected.

## `changes` (type: `string`):

Open the Dataset with change type, changed fields, and before/after columns selected.

## `runSummary` (type: `string`):

Open the authoritative completion, cap, billing, and monitoring-state receipt for this run.

# 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 = {
    "workflow": "current",
    "searchQueries": [
        "bicycle"
    ],
    "locations": [
        "newyork"
    ],
    "categories": [
        "sss"
    ],
    "maxItems": 25,
    "includeDetails": false,
    "sellerType": "all",
    "hideDuplicates": true,
    "sort": "date",
    "stateNamespace": "default",
    "maxBuyerChargeUsd": 5,
    "maxRequests": 2200,
    "maxSourceBytes": 500000000,
    "maxRuntimeSecs": 3600,
    "detailConcurrency": 4
};

// Run the Actor and wait for it to finish
const run = await client.actor("luminar/craigslist-scraper-listing-monitor").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 = {
    "workflow": "current",
    "searchQueries": ["bicycle"],
    "locations": ["newyork"],
    "categories": ["sss"],
    "maxItems": 25,
    "includeDetails": False,
    "sellerType": "all",
    "hideDuplicates": True,
    "sort": "date",
    "stateNamespace": "default",
    "maxBuyerChargeUsd": 5,
    "maxRequests": 2200,
    "maxSourceBytes": 500000000,
    "maxRuntimeSecs": 3600,
    "detailConcurrency": 4,
}

# Run the Actor and wait for it to finish
run = client.actor("luminar/craigslist-scraper-listing-monitor").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 '{
  "workflow": "current",
  "searchQueries": [
    "bicycle"
  ],
  "locations": [
    "newyork"
  ],
  "categories": [
    "sss"
  ],
  "maxItems": 25,
  "includeDetails": false,
  "sellerType": "all",
  "hideDuplicates": true,
  "sort": "date",
  "stateNamespace": "default",
  "maxBuyerChargeUsd": 5,
  "maxRequests": 2200,
  "maxSourceBytes": 500000000,
  "maxRuntimeSecs": 3600,
  "detailConcurrency": 4
}' |
apify call luminar/craigslist-scraper-listing-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,luminar/craigslist-scraper-listing-monitor"
        }
    }
}

```

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/vYC8F9mxylXneskVM/builds/DkSQcKXUgaCThNUTE/openapi.json
