# Craigslist Scraper: Listings, Prices, Housing, Jobs, For Sale (`fernandosord/craigslist-scraper`) Actor

Scrape Craigslist in any city: paste search URLs or pick a city, category and search words. Get title, price, location, date, coordinates and images per posting. Optional full text, attributes (bedrooms, sqft, condition) and large images. Price filters. No login.

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

## Pricing

from $1.40 / 1,000 postings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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

This Craigslist scraper collects postings from any Craigslist city: for sale, housing, jobs, services, gigs and community. Paste search URLs copied from Craigslist, or pick a city, a category and some search words. Each posting comes with its price and currency, place, category, date, map position and image links. Switch on full details to also get the whole text, every attribute (bedrooms, square feet, condition, make, model), large images and the original posted and last updated dates. No login, no API key.

- **Search URLs or city mode.** Paste any search address, with its filters and sort order, or give city names like `toronto` and `sfbay` plus a category and search words. Both can be used in one run.
- **Up to 10,000 postings per search.** Craigslist's own limit. The Actor reads the same data the Craigslist website loads, so titles, prices and images arrive in bulk, not one page at a time.
- **Full details when you want them.** One extra page read per posting adds the description, attributes and large images.
- **No duplicates.** A posting that shows up in two searches is saved once.
- **Searches with no results do not fail.** The run finishes with an empty dataset and a clear status message.

### What data you get

| Field | What it holds |
|---|---|
| `postingId`, `postingUuid`, `url` | The posting's number, its short code and the link to its page |
| `title` | Posting title |
| `price`, `priceText`, `currency` | Price as a number, as Craigslist shows it ("$1,250"), and the currency code (USD, CAD and so on) |
| `site`, `subarea`, `location`, `neighborhood` | Craigslist city, sub-area code, the place name the poster gave and the neighbourhood when there is one |
| `category`, `categoryName`, `section` | Category code (`apa`, `cta`, `jjj`), its name, and the section (housing, for sale, jobs) |
| `listedAt` | Date the posting was last listed or renewed, as search results show it |
| `latitude`, `longitude` | Map position of the posting (Craigslist blurs it a little) |
| `bedrooms`, `sqft` | For housing postings |
| `imageCount`, `images`, `thumbnail` | Image links |
| `company`, `jobTitle`, `salary` | For job postings |
| `mileage`, `monthlyPayment` | For vehicle postings that show them |

With **Include full posting details** you also get:

| Field | What it holds |
|---|---|
| `description` | The full posting text |
| `attributes` | Labelled attributes from the page, for example `condition`, `make / manufacturer`, `model name / number`, `rent period`. The labels differ per category. |
| `features` | Tags without a label, for example `1BR / 1Ba`, `600ft2`, `laundry in bldg` |
| `bedrooms`, `bathrooms`, `sqft` | Read from those tags |
| `postedAt`, `updatedAt` | When the posting was first posted and when it was last edited |
| `address`, `postalCode`, `region`, `country` | The location text under the map, when the poster gave it |
| `images` | All images in the large 1200x900 size |

### How to use it

1. Paste one or more **Search URLs**. Open a search on Craigslist, set your filters and sort order, and copy the address from the browser. Or fill **Cities** and pick a **Category**, then add **Search words**.
2. Optional: set a price range, sort order, postal code with distance, or turn on **Include full posting details**.
3. Set **Maximum postings**. Start small, then raise it.
4. Run it and export to JSON, CSV or Excel, or call it from the API, Make, Zapier, n8n or an AI agent through the Apify MCP server.

If you start the Actor with no search URL and no city, it runs a small example (Toronto, "bike", 20 postings) instead of failing, and says so in the run's status message.

#### Example input

```json
{
  "searchUrls": [{ "url": "https://toronto.craigslist.org/search/apa?min_price=1500" }],
  "includeDetails": true,
  "maxItems": 10
}
```

City mode:

```json
{
  "cities": ["vancouver", "seattle"],
  "category": "cta",
  "query": "honda civic",
  "minPrice": 2000,
  "maxPrice": 15000,
  "maxItems": 100
}
```

#### Example output (one posting with full details, images shortened)

```json
{
  "postingId": 7993738983,
  "postingUuid": "ozzQabZB2hdDG9Ly5JmJSv",
  "title": "Raleigh 2+2 Bike Hitch Rack",
  "url": "https://www.craigslist.org/view/d/mississauga-raleigh-22-bike-hitch-rack/ozzQabZB2hdDG9Ly5JmJSv",
  "price": 180,
  "priceText": "$180",
  "currency": "CAD",
  "site": "toronto",
  "subarea": "mss",
  "location": "Mississauga",
  "neighborhood": null,
  "category": "bop",
  "categoryName": "bicycle parts - by owner",
  "section": "for sale",
  "postedAt": "2026-11-02T00:24:29.000Z",
  "listedAt": "2026-11-02T00:28:29.000Z",
  "updatedAt": null,
  "latitude": 43.5924,
  "longitude": -79.7611,
  "bedrooms": null,
  "bathrooms": null,
  "sqft": null,
  "imageCount": 4,
  "images": [
    "https://images.craigslist.org/00v0v_2Hz5AR7VcxC_0hq0dX_1200x900.jpg",
    "https://images.craigslist.org/00s0s_7CDMw8lLM5t_0g80aL_1200x900.jpg"
  ],
  "thumbnail": "https://images.craigslist.org/00v0v_2Hz5AR7VcxC_0hq0dX_300x300.jpg",
  "description": "This hitch-mounted carrier holds 2 or 4 bicycles securely. It features a durable black metal construction and folds up when not in use. Approximately 100 cm wide by 80 cm deep. Only used a few times, in great condition.\n\nRetail for $460 plus tax.\n\nPickup only. Cash or e-transfer.",
  "attributes": {
    "part type": "racks, fenders, bags",
    "condition": "like new",
    "make / manufacturer": "Raleigh",
    "model name / number": "2+2 Hitch Rack",
    "size / dimensions": "100 cm x 80 cm"
  },
  "features": [],
  "postalCode": "L5N",
  "region": "ON",
  "country": "CA",
  "detailsFetched": true,
  "searchUrl": "https://www.craigslist.org/search/area/toronto?cat=sss&query=bike",
  "scrapedAt": "2026-11-02T02:20:41.771Z"
}
```

#### Example output (housing posting, description and images shortened)

```json
{
  "postingId": 7982011173,
  "title": "1 bedroom apartment downtown Toronto",
  "price": 1600,
  "currency": "CAD",
  "site": "toronto",
  "subarea": "tor",
  "location": "city of toronto",
  "category": "apa",
  "categoryName": "apartments / housing for rent",
  "postedAt": "2026-10-12T02:25:24.000Z",
  "updatedAt": "2026-11-02T01:40:16.000Z",
  "latitude": 43.6606,
  "longitude": -79.372,
  "bedrooms": 1,
  "bathrooms": 1,
  "sqft": 600,
  "description": "Bright one bedroom, one bathroom apartment for rent available now in a Victorian house in the heart of downtown Toronto. ...",
  "attributes": { "rent period": "monthly" },
  "features": ["1BR / 1Ba", "600ft2", "apartment", "laundry in bldg", "off-street parking"],
  "address": "299 Sherbourne street near Gerrard",
  "postalCode": "M5A3Y1",
  "region": "ON",
  "country": "CA"
}
```

### How much does it cost?

You pay per posting saved: $0.0014 per posting, plus $0.0005 once per run. 1,000 postings cost about $1.40 and 10,000 cost about $14.00. Apify's free plan credit of $5 a month covers about 3,500 postings. The price is the same with or without full details.

Searches with no results, and inputs that fail (an unknown city, a URL that is not a Craigslist search), save no postings, so you pay only the start fee. They are listed with the reason in the `SUMMARY` record of the run's key-value store.

### Use cases

- **Price research:** compare what bikes, cars, furniture or electronics sell for across cities, with `price`, `location` and `listedAt`.
- **Rental market tracking:** pull apartments by city with bedrooms, square feet, rent and map position, and watch how rents move week to week.
- **Reselling and sourcing:** find new postings under a price you set, sorted by newest, and schedule the run every hour.
- **Job postings:** collect local jobs with employer, title and pay for a region.
- **Datasets and maps:** plot postings from `latitude` and `longitude`, or build a dataset of images and descriptions for analysis.

### FAQ

**Which Craigslist address do I paste?**
Any search address. Open a search on Craigslist, copy the address from the browser bar. Addresses in the old style (`https://sfbay.craigslist.org/search/apa`), the new style (`https://www.craigslist.org/search/area/sfbay?cat=apa`) and sub-area searches (`https://sfbay.craigslist.org/search/sfc/apa`) all work. A link to one posting also works: it returns that posting with full details.

**What are the limits?**
Craigslist serves at most 10,000 results for one search. To get more, split the search into several cities, price ranges or categories. Sort by newest and schedule the Actor to catch new postings.

**Why are there two dates?**
`listedAt` is the date Craigslist shows in search results, which moves forward when a poster renews a posting. `postedAt` is the date the posting was first posted, and `updatedAt` the last edit. Both are only filled with **Include full posting details**, because they come from the posting page.

**Do I get phone numbers or email addresses?**
No. Craigslist hides contact details behind its reply button, and this Actor does not try to get past that. If the poster wrote a number or address in the text, it is part of `description`.

**How exact are the coordinates?**
Craigslist blurs them on purpose. Expect a position within a few hundred metres of the real place, and not every posting has one.

**Why did a posting have `detailsError`?**
Full details read each posting's page. If the poster deleted the posting between the search and the page read, you still get the search data and `detailsError` says the page was no longer available.

**Why are "nearby" postings missing?**
When a search has few local results Craigslist adds postings from other areas below them. The Actor leaves those out unless you switch on **Include nearby areas**.

**How fast is it?**
Search results arrive in bulk: 3,000 postings without details took about 20 seconds in our test on Apify. With full details the Actor reads one page per posting, a few at a time and at a polite pace, so 100 postings take about 90 seconds.

**Do I need a proxy?**
Not in our tests. The Actor ran from Apify's standard servers without a proxy on every search we tried (San Francisco, New York, Toronto, Vancouver). If Craigslist blocks your runs, turn on Apify Proxy in the input. We have not tested the proxy option.

### Other Actors by this developer

- [Shopify Products Scraper](https://apify.com/fernandosord/shopify-products-scraper): prices, variants and stock for any Shopify store.
- [Open Places Leads](https://apify.com/fernandosord/open-places-leads): businesses and places by area from open map data.
- [Website Change Monitor](https://apify.com/fernandosord/website-change-monitor): get told when a page changes.
- [Dataset Merge and Dedupe](https://apify.com/fernandosord/dataset-merge-dedupe): combine runs and remove repeats.
- [Google Sheets Export](https://apify.com/fernandosord/google-sheets-export): send a dataset to a spreadsheet.

# Actor input Schema

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

Open a search on Craigslist (any city, category, filters, sort order), copy the address from the browser and paste it here. Old and new style addresses both work, sub-areas too. A link to a single posting also works and returns that posting with full details. Leave empty if you use cities below.

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

Craigslist city names as they appear in the web address, for example toronto, vancouver, newyork, sfbay, london. A full address such as https://toronto.craigslist.org also works. One search runs per city, using the category, search word and filters below.

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

Where to search in each city. Leave empty to search all of for sale. Pick a whole section (housing, jobs, for sale, services, gigs, community) or a single category such as apartments, cars+trucks or bikes. Any other Craigslist category code can be given through the API.

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

Words to look for in the posting title and text, for example "road bike". Also applied on top of a pasted search URL if you fill it in.

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

Only postings priced at or above this amount, in the local currency.

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

Only postings priced at or below this amount, in the local currency.

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

How Craigslist orders the results. Leave empty for its default: best match when there are search words, newest otherwise. With a limit, the first results in this order are the ones you get.

## `hasPictures` (type: `boolean`):

Skip postings that have no image.

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

Only postings from the last day.

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

Match the search words in the title only, not in the posting text.

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

Centre of a radius search, for example M5V2T6 or 94103. Use together with Search distance.

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

Radius around the postal or ZIP code, in miles for US searches and kilometres elsewhere (the unit Craigslist uses for that country).

## `includeNearby` (type: `boolean`):

When a search has few local results Craigslist adds postings from nearby areas to the end. They are left out unless you switch this on.

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

Open every posting page to add the full description, all attributes (bedrooms, square feet, condition, make, model and more), all images in large size, original posted date, last updated date and map position. Slower: about one page per posting.

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

Stop after this many postings across all searches. Craigslist returns at most 10,000 results per search.

## `maxItemsPerSearch` (type: `integer`):

Optional cap for each search URL or city, so one big city does not use up the whole total. Leave empty for no per-search cap.

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

Optional. The Actor works without a proxy. Switch on Apify Proxy only if Craigslist starts blocking you.

## Actor input object example

```json
{
  "searchUrls": [
    {
      "url": "https://toronto.craigslist.org/search/sss?query=bike"
    }
  ],
  "maxItems": 20
}
```

# Actor output Schema

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

One item per posting.

# 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": [
        {
            "url": "https://toronto.craigslist.org/search/sss?query=bike"
        }
    ],
    "maxItems": 20
};

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

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

```

## MCP server setup

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