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

Craigslist listings from more than 700 local sites with price, posting time, neighborhood and photos, plus the full text and attributes such as odometer on request. Paste a search URL from your browser, or pick sites, a category and a search term.

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

## Pricing

from $0.50 / 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

## Craigslist Scraper

Craigslist Scraper returns one row per listing from any Craigslist site: title, price, posting time, neighborhood with approximate map coordinates, category and photo links. Turn on **Include description and attributes** to add details: the full text and the listing's attribute box, such as odometer and title status for cars. Paste a search URL from your browser and click **Start**. A single Craigslist search shows only its newest 360 listings, so older listings need narrower searches. It costs $1.00 per 1,000 listings on the Free plan ($0.50 on Business), and the $5 of monthly credit in Apify's Free plan covers about 5,000 listings.

### What data does it return?

| Field | Description |
|---|---|
| `title` | Listing title as posted, e.g. `2011 Toyota Highlander Limited`. Phone numbers and emails in it are masked. |
| `price`, `priceText` | Asking price as a number in the site's currency (`12500`) and as Craigslist prints it (`$12,500`; UK sites show pounds). `price` is `null` when there is no price, as in jobs and free stuff. |
| `postedAt`, `updatedAt` | When the listing was posted and last updated, ISO 8601 in UTC. `updatedAt` needs details on. |
| `area`, `areaName` | The Craigslist site and its name, e.g. `sfbay` and `SF bay area`. |
| `subarea`, `neighborhood` | Subarea code on sites that have subareas (`nby` is the north bay) and the place the poster typed, e.g. `novato`. |
| `latitude`, `longitude` | Approximate position of the listing on Craigslist's map. |
| `category`, `categoryCode` | Category name and code, e.g. `cars & trucks - by owner` and `cto`. |
| `images`, `imageCount` | Links to the photos at 600x450 pixels, and the number of photos. |
| `description` | Full listing text, with details on. Where the poster hid a number behind Craigslist's contact button, the text reads `show contact info`. |
| `attributes` | The attribute box as keys and values, with details on; for cars that means `odometer`, `fuel`, `title status`, `transmission`, `type` and more. `summary` holds the headline, e.g. `2011 toyota highlander limited`. |
| `url`, `postingId` | Link to the listing on craigslist.org and Craigslist's posting number. |
| `search` | The search URL or area search that found the listing. |

### How to scrape Craigslist

1. Run the search on Craigslist in your browser, with the category, keywords and filters you want, and paste the address into **Search URLs**. Every parameter in the address is passed on to Craigslist, so filters the form lacks, such as model year, work too. The form starts with a bicycle search in the SF bay area.
2. Or fill **Areas** with site names as they appear in the address (`sfbay` for sfbay.craigslist.org), pick a **Category** and type a **Search query**. **Minimum price**, **Maximum price**, **Only listings with photos**, **Posted today only** and **Search titles only** apply to these area searches.
3. Turn on **Include description and attributes** if you need the full text. The actor then opens every listing page, six at a time, and the run takes longer; the price per listing stays the same.
4. Set **Maximum rows**. The form starts at 50, and API runs without the field stop at 1,000.
5. Click **Start**, watch the rows arrive in the **Output** tab and export them as CSV, Excel or JSON, or read them through the API.

An area search as API input:

```json
{
  "areas": ["sfbay", "losangeles"],
  "category": "cta",
  "query": "toyota tacoma",
  "minPrice": 8000,
  "maxPrice": 30000,
  "hasPic": true,
  "includeDetails": true,
  "maxItems": 500
}
```

### Example output

A car listing from a run on 30 September 2026 with details on. The `images` list is cut to 3 of the listing's 18 photos.

```json
{
  "key": "craigslist:7975151073",
  "postingId": "7975151073",
  "title": "2011 Toyota Highlander Limited",
  "price": 12500,
  "priceText": "$12,500",
  "url": "https://www.craigslist.org/view/d/novato-2011-toyota-highlander-limited/ewR6mfrGJbios4TBUEcgTt",
  "postedAt": "2026-09-29T22:04:38.000Z",
  "updatedAt": "2026-09-29T22:04:39.000Z",
  "area": "sfbay",
  "areaName": "SF bay area",
  "subarea": "nby",
  "neighborhood": "novato",
  "latitude": 38.1163,
  "longitude": -122.5714,
  "category": "cars & trucks - by owner",
  "categoryCode": "cto",
  "images": [
    "https://images.craigslist.org/00303_aBRTjqazcfu_0CI0t2_600x450.jpg",
    "https://images.craigslist.org/00g0g_iS5c6HSIupp_0CI0t2_600x450.jpg",
    "https://images.craigslist.org/00F0F_gyz8ws0XA16_0CI0t2_600x450.jpg"
  ],
  "imageCount": 18,
  "description": "96K Miles \nOne owner \n4 Wheel Drive\nFor more information contact show contact info",
  "attributes": {
    "summary": "2011 toyota highlander limited",
    "fuel": "gas",
    "odometer": "96,000",
    "title status": "clean",
    "transmission": "automatic",
    "type": "SUV"
  },
  "search": "https://sfbay.craigslist.org/search/cta?query=toyota&min_price=5000"
}
```

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

| | Free plan | Starter | Scale | Business |
|---|---|---|---|---|
| 1,000 listings | $1.00 | $0.80 | $0.65 | $0.50 |

You pay only for the events in the table. There is no start fee, and compute time and proxies are included.

Exporting 10,000 listings costs $10.00 on the Free plan and $5.00 on Business. A listing found by two searches is charged once, and listings skipped by the new-only mode are not charged.

### Limits

- The 360-listing cap applies to each search: in September 2026, `toyota` from $5,000 in the SF bay area car category matched 3,374 listings, and a single search read the newest 360 of them.
- On the 20 sites that Craigslist divides into subareas, among them sfbay, newyork, losangeles, chicago and seattle, a search with more matches is repeated in every subarea, 360 listings each: up to 2,160 in sfbay with its 6 subareas. **Split large searches by subarea** turns this off. On other sites, split a large search by price range or category yourself; the log shows how many listings each search matched and how many it read.
- Search URLs are used as they are. The form's price, photo, posted-today and title-only fields apply to **Areas** only.
- A search term also matches descriptions: the `toyota` search above returned a Honda Odyssey whose text mentions a Toyota. **Search titles only** limits the match to titles; in a search URL, use Craigslist's own title-only option.
- Email addresses and phone numbers in the title, description and attributes are replaced with `[email removed]` and `[phone removed]`, including numbers split into odd groups, written with the letter O for zero or spelled out in words. Names and street addresses that sellers put in the text stay in it.
- The **Areas** field takes Craigslist's site names, such as `sfbay`, or the place names Craigslist uses, such as `SF bay area`, `New York` or `London`. A city inside a larger site, such as San Francisco, searches that whole site (`sfbay`). A name that matches no site is skipped with a note in the log.
- If fewer than 60% of the requests to Craigslist succeed, the run is marked as failed. Rows saved until then stay in the dataset.

### Getting only new listings

Turn on **Return only listings new since the last run**, give the run a **Watch name** such as `sf-road-bikes` (or save the input as a task) and schedule it hourly or daily. The first run returns everything and saves a snapshot; later runs return only listings that are not in it. A listing stays in the snapshot for 60 days after it was last seen, so one that drops out of the results and comes back is not sent twice. The `CHANGES` record in the run's key-value store lists listings whose price or title changed since the previous run. Without a watch name or a task, the mode has nothing to compare with and every listing counts as new.

### FAQ

#### Is it legal to scrape Craigslist?

Craigslist listings are public ads that anyone can read without an account, and the actor reads only those pages. It does not use the reply button, so the contact details Craigslist keeps behind it are never collected. The ads are written by private people, so a description can still contain a seller's name or an address. You are responsible for handling that data lawfully and for following Craigslist's terms of use if you republish listings.

#### Which Craigslist sites are covered?

Every site in Craigslist's own list, more than 700 in September 2026: 413 in the US, 55 in Canada, 27 in the UK and the rest in 75 other countries. Use the name from the site's address, for example `sfbay`, `newyork` or `london`.

#### Which categories can I search?

The **Category** list includes for sale, cars and trucks, motorcycles, bicycles, electronics, furniture, free stuff, housing, apartments, rooms, sublets, real estate, jobs, gigs, services, community and events. A search URL can use any other category from Craigslist's own menu. The attribute box differs by category: cars have odometer and title status, apartments rent period and laundry, bikes frame size and wheel size.

### Related scrapers

- [Eventbrite Events Scraper](https://apify.com/deriverge/eventbrite-scraper)
- [Meetup Events Scraper](https://apify.com/deriverge/meetup-scraper)

### Support

This actor is built and maintained by deriverge s.r.o., a software company based in the Czech Republic. If a run fails or a field you need is missing, please open an issue in the **Issues** tab or write to us at info@deriverge.com. We respond in English and Czech. Runs can be scheduled in Apify Console or started from the **API** tab, which has examples for Python, JavaScript and cURL and works with Make, Zapier, n8n and the Apify MCP server. If the actor saves you time, a short review helps other people find it.

# Changelog

This Actor's version history is a separate document: https://apify.com/deriverge/craigslist-scraper/changelog.md

# Actor input Schema

## `searchUrls` (type: `array`):

Craigslist search pages as you see them in the browser, with any filters, for example https://sfbay.craigslist.org/search/cta?query=toyota\&min\_price=5000. Use this or the fields below.

## `areas` (type: `array`):

Craigslist sites to search: the site name (sfbay, newyork, losangeles, chicago, london) or a city name Craigslist uses (New York, Los Angeles, London). A city inside a larger site, such as San Francisco, searches that whole site (sfbay). Combined with Category, Search query and the filters below.

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

Category for the areas above.

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

Words to search for, for example "toyota tacoma" or "studio".

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

Lowest price in the local currency.

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

Highest price in the local currency.

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

Skip listings without photos.

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

Only listings posted today.

## `titleOnly` (type: `boolean`):

Match the query in listing titles only, not in descriptions.

## `splitBySubarea` (type: `boolean`):

Craigslist returns the newest ~360 listings per search. When a search has more, it is repeated for each subarea (in sfbay: San Francisco, South Bay, East Bay...), which reaches many more listings.

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

Opens each listing for the full description, the attributes (make, odometer, bedrooms, pets, laundry...) and the update time. Slower; the price is the same.

## `newOnly` (type: `boolean`):

Keeps a snapshot per watch name (or per saved task) and returns only listings that were not there before. Schedule it for a listing alert.

## `watchName` (type: `string`):

Name of the snapshot used by the new-only mode, for example "sf-road-bikes". Runs from a saved task get one automatically.

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

Hard cap on returned listings in the run.

## Actor input object example

```json
{
  "searchUrls": [
    "https://sfbay.craigslist.org/search/bia?query=bike"
  ],
  "category": "sss",
  "hasPic": false,
  "postedToday": false,
  "titleOnly": false,
  "splitBySubarea": true,
  "includeDetails": false,
  "newOnly": false,
  "maxItems": 50
}
```

# Actor output Schema

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

One row per listing with price, location, photos and, on request, description and attributes.

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

New listings and listings with a changed price or title since the previous run of the same task or watch name.

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

Searches run, listings found and returned, warnings.

# 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 = {
    "searchUrls": [
        "https://sfbay.craigslist.org/search/bia?query=bike"
    ],
    "maxItems": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("deriverge/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 = {
    "searchUrls": ["https://sfbay.craigslist.org/search/bia?query=bike"],
    "maxItems": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("deriverge/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 '{
  "searchUrls": [
    "https://sfbay.craigslist.org/search/bia?query=bike"
  ],
  "maxItems": 50
}' |
apify call deriverge/craigslist-scraper --silent --output-dataset

```

## MCP server setup

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