# Craigslist Scraper (`lergassy/craigslist-scraper`) Actor

Scrape Craigslist listings from many cities in one run: title, numeric price, place, coordinates, posted date, photos, attributes and full description. Housing, for sale, cars, jobs, gigs, services. Export JSON/CSV/Excel, use the API, schedule it or plug it into Make, n8n or Zapier.

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

## Pricing

from $0.91 / 1,000 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?

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 Scraper?

**Craigslist Scraper** pulls listings from [craigslist.org](https://www.craigslist.org) — apartments, rooms, cars, furniture, electronics, jobs, gigs, services, events — from **as many cities as you want in one run**. Give it a list of cities (or a whole state, a country, or "all"), pick a category, add keywords and a price range, and you get a clean table: title, **numeric price**, city and neighborhood, map coordinates, posted date, photos, attributes (bedrooms, bathrooms, square feet, odometer, condition, pay…) and the full description.

No login, no browser, no proxy to set up. Results go to a dataset you can download as JSON, CSV or Excel, read through the Apify API, schedule, or send to Google Sheets, Make, n8n or Zapier.

- 📍 **Many cities in one run** — `sfbay`, `new york`, `California`, `state:TX`, `United Kingdom`, `all`
- 🗂️ **Any category** — housing, for sale, cars & trucks, jobs, gigs, services, community, events, plus any other Craigslist code
- 🔍 **Craigslist's own filters** — keywords, min / max price, posted today, with photos, titles only, sort
- 📝 **Full details included in the price** — description, every photo, attributes, street address
- ♻️ **Duplicates removed** — reposts and the same ad cross-posted to nearby cities are charged once
- 🔁 **"Only new" mode** — schedule it and get (and pay for) only listings you have not seen

### What data can it extract?

| Field | Example | Notes |
|---|---|---|
| `title` | Terramina Square – Waiting List Open | as posted |
| `price` | 2232 | number, no `$` or commas |
| `priceText`, `currency` | "$2,232", "USD" | currency of the city |
| `city`, `cityName`, `subarea` | sfbay, SF bay area, sby | Craigslist area and sub-area |
| `region`, `country` | California, United States | |
| `neighborhood`, `location`, `address` | san jose east, …, 410 N. White Road, San Jose | address when the poster gave one |
| `latitude`, `longitude` | 37.376745, -121.837012 | map pin |
| `category`, `categoryName`, `section` | apa, apartments / housing for rent, housing | |
| `postedAt`, `updatedAt` | 2026-10-22T15:05:57Z | ISO dates; updated only when edited |
| `bedrooms`, `bathrooms`, `sqft` | 2, 2, 1011 | housing |
| `odometer`, `year`, `makeModel` | 98564, 2013, toyota avalon | cars & motorcycles |
| `salary`, `company`, `jobTitle` | "$45 - $60 per hour", … | jobs & gigs |
| `eventDates`, `openHouses` | \["2026-10-25"] | events, housing |
| `description` | full text | with details on |
| `attributes` | `{"housing_type":"apartment","laundry":"laundry on site","parking":"attached garage"}` | everything Craigslist lists for the ad |
| `images`, `imageCount` | photo URLs | |
| `url`, `id`, `searchUrl`, `scrapedAt` | | link to the ad and to the search it came from |

Fields that a listing does not have are left out of its row (a job has no `bedrooms`, a free couch has no `price`).

### How much does it cost to scrape Craigslist?

You pay per listing delivered (pay-per-event), nothing for starting the Actor and nothing extra for details:

| Apify plan | Price per listing | Listings per $1 |
|---|---|---|
| Free | $0.00126 | ~790 |
| Starter (Bronze) | $0.00105 | ~950 |
| Scale (Silver) | $0.00098 | ~1,020 |
| Business (Gold) and up | $0.00091 | ~1,100 |

Duplicates, problem rows ("this city was not found") and the summary row are **free**. The Apify free plan gives you $5 of credit every month — roughly **4,000 Craigslist listings with full details** for free. Set **Max cost per run** in the run options and the Actor stops cleanly at that amount, with everything written paid for.

### How to scrape Craigslist

1. Open the Actor and click **Try for free**.
2. In **📍 Cities** type one or more cities — the subdomain from the address bar (`sfbay` for sfbay.craigslist.org) or a name (`los angeles`). For a whole region write `California`, `state:TX`, `country:GB` or `all`.
3. Choose a **Category** and, if you want, keywords and a price range.
4. Set **💯 Max listings in total** and click **Start**.
5. Download the results as JSON, CSV or Excel, or connect them to your tools.

Already filtered a search on craigslist.org (bedrooms, make and model, distance from a ZIP)? Paste that address into **🔗 Craigslist URLs** instead — every filter in the URL is kept.

### ⬇️ Input

```json
{
    "cities": ["sfbay", "los angeles", "state:TX"],
    "category": "apa",
    "searchQuery": "parking",
    "minPrice": 1500,
    "maxPrice": 3500,
    "includeDetails": true,
    "maxItems": 500
}
```

Other options: `postedToday`, `hasImages`, `searchTitlesOnly`, `sort` (`newest`, `oldest`, `priceasc`, `pricedsc`, `relevance`), `startUrls`, `maxItemsPerCity`, `categoryCode` (any Craigslist code like `sof`, `cto`, `tia`), `dedupeCrossPosts`, `includeNearbyAreas`, `onlyNewRowsStore`. With several cities, **Max listings in total** is shared fairly: each city gets an equal part, and what a small town cannot fill goes to the bigger ones.

### ⬆️ Output

A real row (description and photos shortened):

```json
{
    "type": "listing",
    "id": "7987893666",
    "url": "https://www.craigslist.org/view/d/san-jose-terramina-square-waiting-list/ogNUeJQkakeZJiB4vvoFSZ",
    "title": "Terramina Square – Waiting List Open",
    "price": 2232,
    "priceText": "$2,232",
    "currency": "USD",
    "city": "sfbay",
    "cityName": "SF bay area",
    "subarea": "sby",
    "region": "California",
    "country": "United States",
    "neighborhood": "san jose east",
    "location": "san jose east",
    "address": "410 N. White Road, San Jose, CA 95127",
    "latitude": 37.376745,
    "longitude": -121.837012,
    "category": "apa",
    "categoryName": "apartments / housing for rent",
    "section": "housing",
    "postedAt": "2026-10-22T15:05:57.000Z",
    "bedrooms": 2,
    "bathrooms": 2,
    "sqft": 1011,
    "description": "2-Bedroom Waiting List Open!\n\nMinimum and Maximum Income Restrictions\n\n2-Bedroom/ 2 -Bath Units…",
    "attributes": {
        "bedrooms": "2",
        "bathrooms": "2",
        "area": "1011 ft²",
        "application_fee_explained": "$50.00 per adult",
        "rent_period": "monthly",
        "housing_type": "apartment",
        "laundry": "laundry on site",
        "parking": "attached garage",
        "airconditioning": true
    },
    "images": [
        "https://images.craigslist.org/00X0X_8RMWJ93OwFI_0CI0pO_600x450.jpg",
        "https://images.craigslist.org/00v0v_7yN60Z6sMvQ_0gw0co_600x450.jpg"
    ],
    "imageCount": 2,
    "searchUrl": "https://sfbay.craigslist.org/search/apa?sort=date",
    "scrapedAt": "2026-10-22T15:15:18.467Z"
}
```

Besides listings the dataset can hold free rows with `type: "error"` (a city that does not exist, a deleted posting, `kind: "no-results"` for a search with no matches) and one free `type: "notice"` summary row at the end. Filter on `type = "listing"` to keep only data.

### Use cases

#### Real estate investors and property managers

Track rents across a whole metro or state: `bedrooms`, `bathrooms`, `sqft`, `price` and coordinates for every rental, ready for price-per-square-foot maps and comps.

#### Car dealers and flippers

Pull every Toyota under $15,000 across ten cities at once, with odometer, year, make and model, title status and photos — then schedule it hourly with "only new" to be first to call.

#### Resellers and e-commerce teams

Watch furniture, electronics or free-stuff listings for arbitrage, price research and sourcing leads, in every city you buy in.

#### Recruiters and job-market researchers

Collect job and gig posts with pay, employer, job title and the full ad text by city and category.

#### Market researchers and data teams

Build datasets of local supply and pricing over time; the clean numeric `price`, ISO dates and stable `id` make joins and time series easy.

#### AI agents and LLM workflows

One call returns structured, deduplicated listings for any number of cities — ideal as a tool for an agent answering "what's for rent under $2,500 near Oakland right now?". Use it through the Apify MCP server or the API.

### Integrations

- **Apify API** — start runs and read results over HTTP; every option above is a JSON field.
- **Python and JavaScript** — `apify-client` for Python or Node.js: `client.actor("lergassy/craigslist-scraper").call(run_input={...})`.
- **No-code** — Make, n8n, Zapier and Google Sheets integrations, webhooks when a run finishes.
- **Schedules** — run hourly or daily; with **Only new listings** each run delivers only fresh posts.
- **MCP** — available to Claude, Cursor and other agents through the Apify MCP server (`mcp.apify.com`).

### Migrating from another Craigslist scraper?

| Their field | Here |
|---|---|
| `region`, `subdomain`, `city` | `cities` (a list — many at once) |
| `searchTerm`, `searchQueries` | `searchQuery` |
| `priceMin` / `priceMax` | `minPrice` / `maxPrice` |
| `hasImage`, `onlyWithPhotos` | `hasImages` |
| `postedToday` | `postedToday` |
| `maxResults`, `maxItems` | `maxItems` (total) and `maxItemsPerCity` |
| `startUrls`, `urls`, `listingUrls` | `startUrls` (search pages and single postings) |
| `monitoringMode` | `onlyNewRowsStore` (give it a name) |
| `hideDuplicates` | `dedupeCrossPosts` (on by default) |
| `searchNearby` | `includeNearbyAreas` |

### Troubleshooting

- **"City … not found on Craigslist"** — use the subdomain from the address bar (`sfbay`, not `San Francisco Bay`). Two-letter codes are ambiguous: write `state:CA` or `country:CA`.
- **Fewer listings than Max listings** — the search really has fewer (check `searchUrl` in the browser), or duplicates and cross-posts were removed. Craigslist shows at most 10,000 results per search.
- **No price on some rows** — the poster gave none (common for jobs, services, free stuff). With a price limit set, such listings are left out.
- **Need a filter that is not in the form** (bedrooms, make & model, distance from a ZIP)? Set it on craigslist.org and paste the URL into **Craigslist URLs**.

### ❓ FAQ

#### Is it legal to scrape Craigslist?

The Actor reads only public listings that anyone can see without an account, and it does not collect hidden contact details. Using public data is generally lawful, but Craigslist's terms of use restrict automated access and commercial reuse, and listings can contain personal data protected by laws such as GDPR or CCPA. You are responsible for how you use the data; if in doubt, ask a lawyer.

#### Do I need a Craigslist account or a proxy?

No. The Actor reads Craigslist directly and switches to a residential proxy by itself only for a request that gets blocked.

#### Can I get the seller's phone number or e-mail?

No. Craigslist hides contact details behind its relay; the Actor returns what the listing shows publicly.

#### How fresh is the data?

Live — every run reads Craigslist at that moment. Use `sort: newest` and `postedToday` for the latest posts, or a schedule with **Only new listings**.

#### How fast is it?

Hundreds of listings with full details take a few seconds; a whole state with 3,000 listings took under a minute in our tests.

### Your feedback

Something missing or not working? Open an issue on the Actor's **Issues** tab — we read every one.

### You might also like

| Actor | What it does |
|---|---|
| [Zillow Scraper](https://apify.com/lergassy/zillow-scraper) | US homes for sale and rent from Zillow with prices, Zestimates and photos |
| [Airbnb Listings Scraper](https://apify.com/lergassy/airbnb-listings-scraper) | Airbnb stays with prices, ratings and hosts for any location |
| [Indeed Jobs Scraper](https://apify.com/lergassy/indeed-jobs-scraper) | Indeed job posts with salary, company and full description |

# Actor input Schema

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

Give this or <code>startUrls</code>. One Craigslist city per line — the subdomain from the address bar (<code>sfbay</code>, <code>newyork</code>, <code>london</code>) or its name (<code>los angeles</code>, <code>San Francisco</code>). Whole regions too: a US state or Canadian province (<code>California</code>, <code>state:TX</code>), a country (<code>United Kingdom</code>, <code>country:DE</code>) or <code>all</code>. Every city is searched in one run.

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

Which Craigslist section to search in every city above (empty = all for sale). Housing, for sale, cars, jobs, gigs, services, community and events. For any other section type its code in <b>Other category code</b> below.

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

Optional. Words to look for, exactly as in Craigslist's search box (<code>toyota tacoma</code>, <code>"walk-in closet"</code>, <code>iphone -broken</code>). Leave empty to get everything in the category.

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

Optional. Only listings priced at least this much, in the city's own currency. Listings without a price are left out when a price limit is set.

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

Optional. Only listings priced at most this much, in the city's own currency. Listings without a price are left out when a price limit is set.

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

Stop after this many listings across all cities. With several cities the limit is shared fairly: each city gets an equal part, and what a small city cannot fill goes to the others.

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

Open every listing for its full description text, all photos, attributes (bedrooms, bathrooms, housing type, pets, parking, odometer, condition, pay…), street address and updated date. Included in the price. Switch off for the fastest list of titles, prices and places.

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

Only listings posted today (Craigslist's own "posted today" filter).

## `hasImages` (type: `boolean`):

Only listings that have at least one photo (Craigslist's "has image" filter).

## `searchTitlesOnly` (type: `boolean`):

Match the keywords in listing titles only, not in the description. Ignored when there are no keywords.

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

Order in which Craigslist returns listings — matters when you take fewer than all of them.

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

Give this or <code>cities</code>. Paste Craigslist search pages exactly as you filtered them in the browser — <code>https://sfbay.craigslist.org/search/apa?min_bedrooms=2\&max_price=4000</code> — all filters in the address are kept. Single listing pages work too. Keywords and price fields above do not change these URLs.

## `maxItemsPerCity` (type: `integer`):

Optional cap for each city / search. Leave empty to let every city use its fair share of the total. Craigslist shows at most 10,000 listings per search.

## `categoryCode` (type: `string`):

Any other Craigslist section by its code — the letters after /search/ in the address: <code>sof</code> software jobs, <code>cto</code> cars by owner, <code>tia</code> tickets, <code>hsh</code> household items. Overrides <b>Category</b>.

## `dedupeCrossPosts` (type: `boolean`):

Skip the same ad posted again, or posted in several nearby cities (same title, price and photo). You are charged once per unique listing.

## `includeNearbyAreas` (type: `boolean`):

When a city has few results, Craigslist adds listings from neighbouring areas. Off: you get only listings of the cities you asked for.

## `onlyNewRowsStore` (type: `string`):

Give this run a name — <code>my-craigslist-watch</code> — and the Actor remembers every listing it delivered under that name. Every later run with the same name writes and charges <b>only listings you have not received before</b>. Schedule the Actor hourly or daily to get a feed of new posts. Leave empty to get everything found, every time.

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

Not needed: the Actor reaches Craigslist directly and switches to a residential proxy by itself only for requests that get blocked. Set your own proxy only if you must, then it is used for every request.

## `includeRunSummary` (type: `boolean`):

One extra free row at the end with the run's totals: rows delivered, free rows, what was charged and how much in US dollars. It carries type "notice", so a filter on the data rows skips it. Switch off if your pipeline cannot tolerate an extra row.

## Actor input object example

```json
{
  "cities": [
    "sfbay"
  ],
  "category": "apa",
  "maxItems": 50,
  "includeDetails": true,
  "postedToday": false,
  "hasImages": false,
  "searchTitlesOnly": false,
  "sort": "newest",
  "dedupeCrossPosts": true,
  "includeNearbyAreas": false,
  "includeRunSummary": true
}
```

# Actor output Schema

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

One row per Craigslist listing (type "listing"), plus free rows for problems (type "error") and the run summary (type "notice").

## `allFields` (type: `string`):

Every field of every row, including description, attributes and photo links.

# 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 = {
    "cities": [
        "sfbay"
    ],
    "category": "apa",
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("lergassy/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 = {
    "cities": ["sfbay"],
    "category": "apa",
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("lergassy/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 '{
  "cities": [
    "sfbay"
  ],
  "category": "apa",
  "maxItems": 50
}' |
apify call lergassy/craigslist-scraper --silent --output-dataset

```

## MCP server setup

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