# Craigslist Scraper — Price, Location & Geo-Coordinates (`axery/craigslist-search-scraper`) Actor

Scrape Craigslist listings by city, category and keyword: title, price, location, images and geo-coordinates. No login, no API key.

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

## Pricing

from $1.01 / 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.
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

## Craigslist Search Scraper

Scrapes Craigslist listings by city, category and keyword — title, price, location, images and geo-coordinates. No login, no API key.

Useful for local market research, price monitoring on specific item categories, and building a search alert across one or many cities.

### What makes this different

**Images and precise geo-coordinates, which the listing cards alone don't carry.** Craigslist's search page splits its data across two places: the visible listing cards (title, price, neighborhood, URL) and a separate structured `ItemList` block (images, exact latitude/longitude) with no shared ID linking the two. This Actor merges them by title match into one row, so you get both the clickable listing and its images/coordinates together — something neither source alone provides.

**The real depth limit is stated honestly, not hidden.** This search page has a fixed ceiling around 350–400 results with no working pagination — the `s=` offset parameter Craigslist's full site uses for "next page" is silently ignored here, and the RSS export that used to be a workaround is blocked outright. Rather than pretending to page past that (and quietly returning the same listings over and over), this Actor reports what it actually found and documents the limit so you can narrow with `query`, `category`, or price filters when a search is broader than that.

**Price filters that actually filter**, verified against live results rather than assumed from the URL parameter names.

### Input

| Field | Type | Notes |
|---|---|---|
| `city` | string | Craigslist city subdomain, e.g. `sfbay`, `newyork`. |
| `category` | string | Category code, e.g. `sss` (for sale - all), `bik` (bicycles), `zip` (free). Defaults to `sss`. |
| `query` | string | Optional keyword, same as the site's own search box. |
| `minPrice` / `maxPrice` | integer | Optional price range. |
| `maxItems` | integer | `0` = everything this search returns (up to the endpoint's own ~350-400 ceiling). |
| `incremental` | boolean | Only listings not seen in previous runs. |
| `proxyConfiguration` | object | Not normally needed. |

#### Finding city and category codes

City: the subdomain from that city's Craigslist URL (`sfbay.craigslist.org` → `sfbay`). The full list is at craigslist.org/about/sites. Category: the short code visible in the search URL when browsing the category on the site itself.

### Output

```json
{
  "listing_id": "craigslist.org:jNAsa3GTtJA3uJWjxeh7fs",
  "title": "Purple lowrider bicycle 20\"",
  "price": 50,
  "currency": "USD",
  "location": "sunnyvale",
  "neighborhood": "Sunnyvale",
  "latitude": 37.3764004252778,
  "longitude": -122.023795650699,
  "images": ["https://images.craigslist.org/..."],
  "url": "https://www.craigslist.org/view/d/sunnyvale-purple-lowrider-bicycle-20/jNAsa3GTtJA3uJWjxeh7fs"
}
```

`neighborhood`, coordinates and `images` are only present when the structured data block matched that listing by title — most listings match, but not all. Each run also writes a `RUN_COVERAGE` record to the key-value store with what was requested, what came back, and any failure.

### Local development

```bash
pip install -r requirements.txt
python test_local.py sfbay --query bike --max 30 --out sample_output.json
python test_local.py sfbay --category bik --min-price 50 --max-price 300
```

`sample_output.json` is real output from a live search.

# Actor input Schema

## `city` (type: `string`):

The Craigslist city subdomain, e.g. `sfbay`, `newyork`, `losangeles`, `chicago` - the part before `.craigslist.org` in that city's URL. See craigslist.org/about/sites for the full list.

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

The Craigslist category code from the search URL, e.g. `sss` (for sale - all), `bik` (bicycles), `zip` (free stuff), `act` (activities). Defaults to for-sale-all.

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

Optional search term, the same as typing into Craigslist's own search box. Leave blank to browse the whole category.

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

Optional minimum price filter.

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

Optional maximum price filter.

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

Cap on listings returned. `0` returns everything this search page shows - note this page has a fixed ceiling around 350-400 results with no way to page deeper; narrow with `query`, `category` or price filters to stay under it for a broad search.

## `incremental` (type: `boolean`):

Remember listing IDs between runs and return only listings not seen before - useful for a scheduled watch on a search.

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

Not normally needed.

## Actor input object example

```json
{
  "city": "sfbay",
  "category": "sss",
  "query": "bike",
  "maxItems": 0,
  "incremental": false,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

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

One row per listing: title, price, location, images, and geo-coordinates where available.

# 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 = {
    "city": "sfbay",
    "category": "sss",
    "maxItems": 0
};

// Run the Actor and wait for it to finish
const run = await client.actor("axery/craigslist-search-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 = {
    "city": "sfbay",
    "category": "sss",
    "maxItems": 0,
}

# Run the Actor and wait for it to finish
run = client.actor("axery/craigslist-search-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 '{
  "city": "sfbay",
  "category": "sss",
  "maxItems": 0
}' |
apify call axery/craigslist-search-scraper --silent --output-dataset

```

## MCP server setup

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