# Craigslist For Sale Scraper | Classifieds, Autos, Free Stuff (`longanimous_bracken/craigslist-for-sale-scraper`) Actor

Scrape Craigslist For Sale (non-housing) listings by city - autos, bikes, boats, furniture, electronics, tools, pets, free stuff. Subcategory filter, free-only, price filters, new-listings monitoring. Plain HTTP, no browser. Works via Apify MCP.

- **URL**: https://apify.com/longanimous\_bracken/craigslist-for-sale-scraper.md
- **Developed by:** [petteri mähönen](https://apify.com/longanimous_bracken) (community)
- **Categories:** E-commerce, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

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?

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 For Sale Scraper

Scrape **Craigslist** For Sale (non-housing classifieds) listings across US cities — autos, bikes, boats, furniture, electronics, tools, pets, free stuff & more. **Plain HTTP, no browser, no proxy needed** (Craigslist's 2026 search and detail pages are fully server-rendered).

> **2026 reality:** Craigslist's 2026 UI collapsed the old categories. The only non-housing feed is `cat=sss` — one "For Sale" mega feed containing *all* subcategories (autos, motorcycles, bicycles, boats, furniture, appliances, electronics, tools, sports, music, toys, antiques, pets, farm, free). Jobs, services and events no longer exist as separate feeds. Because the 2026 UI has no per-listing category tags, this actor assigns a `subcategory` by keyword classification on the title (first-match wins, best-effort — a few listings may be mis-tagged).

### Features

- **Subcategory filter** — 16 keyword categories (`auto`, `motorcycle`, `bikes`, `boats`, `furniture`, `appliances`, `electronics`, `tools`, `sports`, `music`, `toys`, `antiques`, `pets`, `farm`, `free`, `other`), matched client-side and filtered *before* detail fetches so targeted runs use less compute
- **Free items only** — `freeOnly` returns just the "free" listings (keyword-first detection; the `$0` price box alone is unreliable, so a $0 price is only a fallback signal)
- **Price filters** — `minPrice` / `maxPrice` applied server-side (Craigslist filters before you pay for results)
- **Keyword filter** — `titleKeyword` matches listing titles client-side (Craigslist's search page ignores keyword params)
- **New-listings monitoring** — `dedupeAgainstDatasetId` skips listings already in a previous run's dataset and tags everything `is_new=true`. Combine with an Apify Schedule for a daily "new listings only" or "free stuff in my city" feed
- **Multi-city search** — scrape several areas in one run
- **Detail page extraction** — per listing: neighborhood, full description, all photos, reply URL, post ID, posted date, lat/lng
- **Fast & cheap** — CheerioCrawler, 256MB, no browser; one search page per area contains **all** results (no pagination/scroll)

### Input

| Field | Type | Default | Description |
|---|---|---|---|
| `locations` | string\[] | `["San Francisco, CA"]` | Cities/areas to scrape |
| `subcategory` | string | `all` | `all` | `auto` | `motorcycle` | `bikes` | `boats` | `furniture` | `appliances` | `electronics` | `tools` | `sports` | `music` | `toys` | `antiques` | `pets` | `farm` | `free` | `other` |
| `freeOnly` | boolean | `false` | Only `free` items only (title says free, or $0) |
| `minPrice` | number | `0` | Minimum price, server-side (0 = no minimum) |
| `maxPrice` | number | `0` | Maximum price, server-side (0 = no maximum) |
| `maxResults` | number | `100` | Stop after this many listings (0 = no limit) |
| `titleKeyword` | string | — | Only listings whose title contains this keyword (client-side; filters before detail fetches) |
| `fetchDetails` | boolean | `true` | Visit detail pages for enriched data |
| `dedupeAgainstDatasetId` | string | — | Dataset ID(s) of previous runs (comma-separated or array); matched `post_id`s are skipped |
| `apiToken` | string | — | Optional Apify API token for reading cross-actor datasets (needed when deduping against a dataset created by a different actor/task) |

#### Example: filtered search

```json
{
  "locations": ["San Francisco, CA"],
  "subcategory": "auto",
  "minPrice": 5000,
  "maxPrice": 25000,
  "maxResults": 50
}
```

#### Example: daily new-listings monitor (set as an Apify Schedule)

```json
{
  "locations": ["New York, NY", "Los Angeles, CA"],
  "freeOnly": true,
  "dedupeAgainstDatasetId": "<yesterday-run-dataset-id>",
  "apiToken": "apif...k"
}
```

Each day you get only listings that weren't in the previous run's dataset, all tagged `is_new: true`. (Cloud-verified: a baseline run followed by a deduped run returned 7 new listings with **zero overlap**.)

### Output

Each listing includes:

| Field | Source | Example |
|---|---|---|
| `title` | Search / Detail | "1987 VW Westfalia (4-spd, rotating seats)" |
| `price` | Search / Detail | "$19,500" |
| `price_num` | Derived | `19500` |
| `subcategory` | Derived (keyword classifier) | "auto" |
| `neighborhood` | Search / Detail | "potrero hill" |
| `link` | Search | "https://www.craigslist.org/view/d/..." |
| `thumbnail` | Detail | image URL |
| `latitude` / `longitude` | Detail | `37.71` / `-122.41` |
| `post_id` | Detail | "7965488586" |
| `posted` | Detail | "2026-09-12T23:02:18Z" (ISO) |
| `photos` | Detail | \["url1", "url2", ...] |
| `description` | Detail | "Full description text..." |
| `reply_url` | Detail | "https://.../reply/..." |
| `contact_info` / `contact_websites` | Detail | phone/email/URL mentions from description |
| `has_contact` | Detail | true |
| `h1_text` | Detail | raw detail-page title line |
| `is_new` | Dedupe | true (only set when `dedupeAgainstDatasetId` produced matches) |
| `location` / `area` | Input | "San Francisco, CA" / "sfbay" |
| `platform` | System | "craigslist" |
| `scraped_at` | System | ISO timestamp |

### Use Cases

- **Free stuff in your city** — daily schedule + `freeOnly` = "free near me" feed
- **New-listing alerts** — daily schedule + `dedupeAgainstDatasetId` = "new listings only"
- **Car shopping / market tracking** — `subcategory: auto` + `minPrice`/`maxPrice` for a specific make-of-market segment
- **Deal monitoring** — `titleKeyword: "peloton"`, re-run daily, track prices over time
- **Classifieds data pipeline** — feed structured marketplace data into analytics, price tracking, or ML models

### Performance & Limitations

- No browser (CheerioCrawler, 256MB) — Craigslist's 2026 pages are fully server-rendered
- One search page per area contains **all** results (no pagination/scroll needed) — e.g. 344 for-sale listings in the SF Bay area on a single page
- Subcategory is **keyword classification on the title** — best-effort, first-match wins; a few listings will be `other` or slightly mis-tagged. For precise matches, combine `subcategory` with `titleKeyword`
- The `$0` price field is unreliable (sellers often leave the price box blank) — free-item detection is keyword-first with `$0` as fallback
- Actual phone/email is behind Craigslist's JS-gated "show contact" — we extract the reply URL plus any phone/email/URL mentions from the description text
- For-sale detail pages have **no address or spec fields** (those are housing-only in the 2026 UI); some listings also lack a map pin, in which case `latitude`/`longitude` are `null`

### 💬 Quick Start for AI Assistants

Copy and paste this into ChatGPT, Claude, or another AI assistant:

***

You are helping me use the "Craigslist For Sale Scraper" on Apify (actor ID: ACqoWMdMJhw6sHAkO). It extracts Craigslist For Sale (non-housing) listings — autos, bikes, boats, furniture, electronics, tools, pets, free stuff — from craigslist.org across US cities.

Input fields:

- locations: string array, e.g. \["San Francisco, CA", "New York, NY"]
- subcategory: "all" (default) | "auto" | "motorcycle" | "bikes" | "boats" | "furniture" | "appliances" | "electronics" | "tools" | "sports" | "music" | "toys" | "antiques" | "pets" | "farm" | "free" | "other"
- freeOnly: boolean, only free items (default false)
- minPrice / maxPrice: numbers, server-side price filter (0 = no filter)
- titleKeyword: string, only listings whose title contains it (client-side)
- maxResults: number, max listings to return (default 100, 0 = no limit)
- fetchDetails: boolean, visit detail pages for photos, descriptions, reply URL (default true)
- dedupeAgainstDatasetId: string dataset ID(s), skip already-seen listings, tag is\_new
- apiToken: optional Apify API token to read cross-actor datasets

Output fields per listing: title, price, price\_num, subcategory, neighborhood, link, thumbnail, latitude, longitude, post\_id, posted, photos\[], description, reply\_url, has\_contact, contact\_info\[], contact\_websites\[], h1\_text, is\_new, location, area, platform, scraped\_at.

## Help me with the right input, output processing, or troubleshooting.

### 📋 Changelog

| Version | Date | Changes |
|---------|------|---------|
| 0.2 | 2026-09-13 | Rebuilt with output schema (publish-gate fix), Dockerfile cleanup, README pricing/actor-ID corrections |
| 0.1 | 2026-09-12 | Initial release — 2026 `sss` feed, 16-category keyword classifier, `freeOnly` (keyword-first free detection), `minPrice`/`maxPrice` server-side, `titleKeyword`, `dedupeAgainstDatasetId` + `apiToken` new-listings monitoring (cloud-verified: 0 overlap, all `is_new`) |

### Pricing

**Pay per event** — $1.00 per 1,000 results ($0.001 per listing in the dataset), plus $0.05 per run.

### Support & Feedback

**Enjoying this Actor?** [Leave a review on Apify Store](https://apify.com/longanimous_bracken/craigslist-for-sale-scraper/reviews) — it helps others discover the tool.

Found a bug or have a feature request? [Open an issue](https://console.apify.com/actors/ACqoWMdMJhw6sHAkO/issues) on the Actor page.

# Actor input Schema

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

US cities to search. Examples: San Francisco CA, Seattle WA, New York NY.

## `subcategory` (type: `string`):

Craigslist's 2026 UI has no subcategory tags, so this is matched by keywords in the listing title (client-side, first-match wins). 'free' matches $0-priced items. 'all' = no filtering. Note: keyword classification is best-effort - a few listings may be mis-tagged.

## `freeOnly` (type: `boolean`):

Only items priced exactly $0. Combines well with a schedule for a daily 'free stuff in my city' monitor.

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

Only listings at or above this price (server-side filter). 0 = no minimum.

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

Only listings at or below this price (server-side filter). 0 = no maximum.

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

Stop after this many listings. 0 = no limit. (Default 100 keeps runs fast; the 2026 search page returns ALL area results on one page.)

## `titleKeyword` (type: `string`):

Only listings whose title contains this keyword (case-insensitive). Filtered client-side before detail fetches, so targeted runs also use less compute. Example: 'peloton'.

## `fetchDetails` (type: `boolean`):

Fetch each listing's detail page (description, photos, reply URL, post ID, lat/lng). Disable for a fast overview-only run.

## `dedupeAgainstDatasetId` (type: `string`):

Dataset ID(s) of a previous run (comma-separated or array). Listings already in those datasets (matched by post\_id) are skipped and everything emitted is tagged is\_new=true. Combine with a schedule for a daily 'new listings only' monitor.

## `apiToken` (type: `string`):

Optional. Your Apify API token, used to read the dataset(s) named in dedupeAgainstDatasetId (the actor's token can only read its own datasets). Leave empty when deduping against a dataset created by this same actor.

## Actor input object example

```json
{
  "locations": [
    "San Francisco, CA"
  ],
  "subcategory": "all",
  "freeOnly": false,
  "minPrice": 0,
  "maxPrice": 0,
  "maxResults": 100,
  "fetchDetails": true
}
```

# Actor output Schema

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

No description

# 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("longanimous_bracken/craigslist-for-sale-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("longanimous_bracken/craigslist-for-sale-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 longanimous_bracken/craigslist-for-sale-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,longanimous_bracken/craigslist-for-sale-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/ACqoWMdMJhw6sHAkO/builds/ALY5uLkrnYc4z1vxN/openapi.json
