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

Scrapes Craigslist postings — title, price, location and link — from any city and any category.

- **URL**: https://apify.com/mina_safwat/craigslist-scraper.md
- **Developed by:** [Mina](https://apify.com/mina_safwat) (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.50 / 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?

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 does Craigslist Scraper do?

**Craigslist Scraper** collects postings from any [Craigslist](https://www.craigslist.org) search: cars, apartments, furniture, jobs, gigs, or anything else, in any city worldwide. For each posting you get the **title, price, ISO currency code, location, city and a direct link**. Jobs, gigs, services, community, events and resumes have no price on Craigslist, so for them the price is left empty. You paste the search links you already use on Craigslist, and every filter in them is kept.

It runs on the Apify platform, so you also get API access, scheduled runs, integrations (Google Sheets, Zapier, Make, webhooks), rotating residential proxies and run monitoring without extra setup.

### Why use Craigslist Scraper?

- **Market research:** see what the same kind of item sells for across cities and categories.
- **Rental tracking:** run the same apartment search every morning and watch rents in a neighbourhood move.
- **Deal alerts:** schedule a narrow search, such as one car model under a price, and get new postings into a sheet or a webhook.
- **Inventory snapshots:** capture what is on offer in a local market today, for a report or a dataset.

### How to scrape Craigslist

1. Go to Craigslist, pick a city and search for what you want.
2. Narrow the search with the filters on the page: price range, neighbourhood, category, keywords.
3. Copy the address from your browser's address bar.
4. Paste it into **Craigslist search links** and click **Start**.
5. Download the results, or connect them to your tools, when the run finishes.

You can paste several links, one per line. Different cities and categories can go in the same run, and their results land in one table. Both link styles work: `https://www.craigslist.org/search/area/newyork?cat=cta` and the older `https://newyork.craigslist.org/search/cta`.

### Input

The **Input** tab has three fields:

- **Craigslist search links:** one or more search pages copied from Craigslist.
- **Max results per search:** stops after this many postings per link. The default is 400.
- **Proxy country:** the 2-letter code of the country the requests come from, such as `US` or `GB`. The default, US, works for every Craigslist city.

```json
{
    "search_urls": [
        "https://newyork.craigslist.org/search/cta",
        "https://losangeles.craigslist.org/search/apa"
    ],
    "max_results_per_search": 400,
    "proxy_country": "US"
}
```

### Output

Each posting becomes one row:

```json
{
    "id": "vqWL5SYy8CNy1cbcwNjFVp",
    "title": "Yonge/Steeles 2 bedroom + den, heat and parking included",
    "price": 2250,
    "currency": "CAD",
    "location": "Yonge and Steeles",
    "url": "https://www.craigslist.org/view/d/thornhill-yonge-steeles-bedroomdenfree/vqWL5SYy8CNy1cbcwNjFVp",
    "city": "toronto",
    "position": 1,
    "search_url": "https://www.craigslist.org/search/area/toronto?cat=apa"
}
```

You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

### Data fields

| Field | Description |
| --- | --- |
| `id` | Craigslist's posting ID, taken from the posting link |
| `title` | Posting title |
| `price` | Asking price as a whole number. Empty for jobs, gigs, services, community, events and resumes, which have no price, and for the odd posting listed without one |
| `currency` | ISO currency code of the city's site, such as `USD`, `CAD`, `GBP` or `EUR`. Empty whenever `price` is empty |
| `location` | The neighbourhood, town or address the poster gave. Empty if they left it blank, which is more common outside the US |
| `url` | Direct link to the posting |
| `city` | The Craigslist site the posting was found on, such as `newyork` or `london` |
| `position` | Position of the posting within its search, starting at 1 |
| `search_url` | The search link the posting came from |

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

The Actor uses pay-per-event pricing:

- **$0.0015 per posting** saved to the dataset
- **$0.00005 per run** for the Actor start

That comes to **about $1.50 per 1,000 results**. A full search of about 350 postings costs roughly $0.53. Links that return nothing are not charged per row. The monthly credit on Apify's free plan is enough to try the Actor on several searches.

### Tips for complete coverage

- **This Actor reads at most about 360 postings per search link**, however many match. That is the first batch Craigslist sends with the search page; the Actor does not page further. If a link returns around 350 postings, it has most likely hit that cap.
- **Split big searches** to reach the rest: by price band (`min_price`/`max_price`), by neighbourhood, or by a more specific category. Put each slice in as its own link.
- **Lower "Max results per search"** when you only need the first few postings of each search. A run then saves fewer rows and costs less.
- **Schedule the run** (daily or hourly) to track new postings and price changes over time.

### FAQ, disclaimers, and support

**Is it legal to scrape Craigslist?**
Craigslist's Terms of Use forbid scraping and other automated access to the site. Craigslist has sued companies that scraped it, including 3Taps and RadPad. This Actor reads only publicly visible search pages. You are responsible for how you use it and the data it collects, including following Craigslist's terms and the laws that apply to you, such as data-protection rules for any personal information in postings. If you are unsure, ask a lawyer. This Actor is not affiliated with or endorsed by Craigslist.

**Does it get descriptions, photos or posting dates?**
No. It reads Craigslist's search results, which carry the title, price, location and link but not the full posting. Open the `url` to see the posting.

**Why do some prices read 0 or 1?**
In for-sale and housing searches, that is what the poster entered. Some dealers use it for "call for price" or to advertise a down payment, and everything under "free stuff" reads 0. Jobs, gigs, services, community, events and resumes have no price, so their `price` and `currency` are empty instead.

**What happens to links that return nothing?**
They are listed with the reason in the `FAILED_INPUTS` record of the run's key-value store, and the run's status message says how many there were. Examples are a link that is not a Craigslist search, a search with no matches, or a page Craigslist would not serve. The run fails only when no postings came back and every search it tried was blocked or could not be loaded. A mistyped link is listed too, but does not change that.

**Found a problem or need a custom solution?**
Open an issue on the **Issues** tab and include the search link you used. Custom Craigslist extractions, such as other fields or other sites, are available on request.

# Actor input Schema

## `search_urls` (type: `array`):

Search links, one per line. Search on Craigslist with whatever filters you want — price range, category, neighbourhood, keywords — then copy the address bar. Every filter in the link is honoured, and the city comes from the link too, so you can cover several cities in one run. Both www.craigslist.org/search/area/newyork?cat=cta and newyork.craigslist.org/search/cta links work.

## `max_results_per_search` (type: `integer`):

Stops after this many postings for each link. This Actor reads up to about 360 postings per search link (the first batch Craigslist sends with the page), so raising this beyond that has no effect — use more, narrower searches instead.

## `proxy_country` (type: `string`):

A 2-letter country code to browse from, such as US or GB (not UK). Craigslist serves every city to every country, so the default, US, works everywhere.

## Actor input object example

```json
{
  "search_urls": [
    "https://newyork.craigslist.org/search/cta",
    "https://losangeles.craigslist.org/search/apa"
  ],
  "max_results_per_search": 400,
  "proxy_country": "US"
}
```

# Actor output Schema

## `dataset` (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 = {
    "search_urls": [
        "https://newyork.craigslist.org/search/cta",
        "https://losangeles.craigslist.org/search/apa"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("mina_safwat/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 = { "search_urls": [
        "https://newyork.craigslist.org/search/cta",
        "https://losangeles.craigslist.org/search/apa",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("mina_safwat/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 '{
  "search_urls": [
    "https://newyork.craigslist.org/search/cta",
    "https://losangeles.craigslist.org/search/apa"
  ]
}' |
apify call mina_safwat/craigslist-scraper --silent --output-dataset

```

## MCP server setup

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