---
title: "How to Scrape Craigslist Listings (2026) | Scrape.ly"
description: "Scrape Craigslist by search URL or city and category: price, location, dates and full ad text, with a real run, its cost and code for curl and Python."
url: https://scrape.ly/blog/scrape-craigslist
markdown: https://scrape.ly/blog/scrape-craigslist.md
---

[Tutorials](https://scrape.ly/blog/category/tutorials.md)

# How to Scrape Craigslist Listings: Prices, Locations and Full Ads

Scrape Craigslist by search URL or by city and category and get every ad as a row: title, price, neighborhood, category, posting date, attributes and the full description. A real run on New York bike ads, its cost, code for curl, Python and Node.js, and how to use the data responsibly.

[Shelfbright Actor publisher on the Scrape.ly Store](https://scrape.ly/blog/author/shelfbright.md)

- Published

  Oct 23, 2026

- Reading time

  9 min read

![Pixel-art robot with an orange >\_ on its terminal head takes a classified ad slip with a purple title off a cork board topped with the purple Craigslist peace-sign logo and drops it into a crate](https://scrape.ly/media/scrape-craigslist.png?w=1080)

To scrape Craigslist, give a scraper a Craigslist search URL, or a list of cities and categories, and let it save every matching ad as a row: title, price, neighborhood, category, when it was posted and refreshed, attributes such as condition and make, and the full ad text. The fastest way is the Craigslist Scraper on Scrape.ly. It reads search results in bulk, opens each ad for the details, and costs $4 per 1,000 ads, with no login, API key or proxy of your own.

This guide covers the no-code steps, the API (curl, Python, Node.js and AI agents over MCP), the cost, the pitfalls and how to use the data responsibly. Everything comes from a real run on 23 October 2026: bike ads in New York.

## What data you can get from Craigslist

The [Craigslist Scraper](https://scrape.ly/store/shelfbright/craigslist-scraper.md) writes one row per ad, in the same shape for every section (for sale, housing, jobs, gigs, services). These are the fields you'll use most:

| Field                                                           | What it holds                                                              |
| --------------------------------------------------------------- | -------------------------------------------------------------------------- |
| `title`, `url`, `id`                                            | Ad title, link and Craigslist post ID                                      |
| `price`, `priceValue`, `currency`                               | Price as shown ("$500"), as a number, and the currency                     |
| `location`, `area`, `subarea`                                   | Neighborhood text, Craigslist site (`newyork`) and sub-area (`mnh`, `brk`) |
| `category`, `categoryCode`                                      | Category name ("bicycles - by owner") and code                             |
| `postedAt`, `datetime`                                          | When the ad was first published, and when it was last updated or reposted  |
| `post`                                                          | The full ad text                                                           |
| `attributes`, `properties`                                      | Attributes as listed ("wheel size: 29 in") and by name                     |
| `condition`, `manufacturer`, `model`                            | For-sale details when the seller fills them in                             |
| `bedrooms`, `bathrooms`, `space`, `availableFrom`, `rentPeriod` | Housing details                                                            |
| `compensation`, `employmentType`, `companyName`                 | Jobs and gigs details                                                      |
| `pics`, `latitude`, `longitude`, `address`                      | Photos, map position and address parts when the poster shows them          |
| `phoneNumbers`                                                  | Phone numbers written in the ad text                                       |

Craigslist ads are free text, so a field appears only when the ad has it: bedrooms on housing, pay on jobs, condition on items for sale.

## How to scrape Craigslist without code

1. Open the [Actor's page](https://scrape.ly/store/shelfbright/craigslist-scraper.md) in the Scrape.ly Store.
2. Pick a ready-made input. We used [Bikes for sale in New York, 10 ads](https://scrape.ly/store/shelfbright/craigslist-scraper/presets/url-search.md). Two more presets show the other shapes: [road bikes in the SF Bay Area from $100 to $2,000](https://scrape.ly/store/shelfbright/craigslist-scraper/presets/city-category-price.md) and [apartments for rent in Chicago](https://scrape.ly/store/shelfbright/craigslist-scraper/presets/url-housing-light.md).
3. Paste your own Craigslist search URL, or switch to cities and categories. This is the exact input of our run:

```json
{
  "urls": [{ "url": "https://newyork.craigslist.org/search/sss?query=bike" }],
  "maxItems": 10,
  "scrapeDetails": true
}
```

4. Click **Start**. Our 10 ads took 10 seconds, most of it container start-up.
5. Export the ads as JSON, CSV, Excel or HTML.

The fields that matter most:

- `urls`: any Craigslist search page; filters already in the URL (price, query, distance) are kept. Single ads work too, as `https://www.craigslist.org/view/...` links.
- `cities` and `categories`: site names such as `newyork`, `sfbay` or `chicago`, combined with category codes such as `bia` (bicycles), `apa` (apartments) or `jjj` (jobs). Fifty cities and five categories make 250 searches in one run.
- `searchQuery`, `titleOnly`: keywords for every search, optionally matched against titles only.
- `minPrice`, `maxPrice`, `maxAge`, `sellerType`, `sortBy`: price range, maximum age in days, owner or dealer, and sort order.
- `scrapeDetails`: opens every ad for the full text, attributes and posting date. Turn it off for a fast list of titles, prices and images; the price per ad stays the same.
- `maxItems`: total ads for the run (default 20, `0` for no limit).

Scrape.ly Store Craigslist Scraper Craigslist ads by search URL or by city and category: price, neighborhood, dates, attributes, photos and full text, for sale, housing, jobs, gigs and services. $4 per 1,000 ads.

[Try it free](https://scrape.ly/store/shelfbright/craigslist-scraper.md) [Browse the Store](https://scrape.ly/store.md)

## How to scrape Craigslist with the API

Create an API token under **Settings → API & Integrations** and export it as `SCRAPELY_TOKEN`.

Our run took 10 seconds, so the synchronous endpoint returns the ads in one request:

```shell
curl -X POST "https://api.scrape.ly/v2/actors/shelfbright~craigslist-scraper/run-sync-get-dataset-items"
  -H "Authorization: Bearer $SCRAPELY_TOKEN"
  -H "Content-Type: application/json"
  -d '{"urls": [{"url": "https://newyork.craigslist.org/search/sss?query=bike"}], "maxItems": 10, "scrapeDetails": true}'
```

The synchronous call waits up to 45 seconds. For thousands of ads or many cities, start the run with `/runs` and read the dataset when it finishes, as the [Actors API docs](https://scrape.ly/docs/api-actors.md) show.

Python (`pip install scrapely-client-python`). `call()` waits however long the run takes. Sellers often post the same ad in several categories, so this example drops repeats with the same title and text, then sorts by price:

```python
import os
from scrapely_client import ScrapelyClient

client = ScrapelyClient(os.environ["SCRAPELY_TOKEN"], api_url="https://api.scrape.ly")

run = client.actor("shelfbright/craigslist-scraper").call(
    run_input={"urls": [{"url": "https://newyork.craigslist.org/search/sss?query=bike"}],
               "maxItems": 10, "scrapeDetails": True}
)
print(run.status)  # SUCCEEDED, FAILED, ABORTED or TIMED-OUT
seen, ads = set(), []
for ad in client.dataset(run.default_dataset_id).iterate_items():
    key = (ad["title"].lower(), (ad.get("post") or "")[:200])
    if key not in seen:
        seen.add(key)
        ads.append(ad)
for ad in sorted(ads, key=lambda a: a.get("priceValue") or 0):
    print(f'{ad.get("price") or "no price":>8}  {ad["category"][:26]:26}  {ad["location"][:16]:16}  {ad["title"][:50]}')
```

Node.js (`npm install scrapely-client`):

```javascript
import { ScrapelyClient } from 'scrapely-client';

const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN, baseUrl: 'https://api.scrape.ly' });

const run = await client.actor('shelfbright/craigslist-scraper').call({
  cities: ['newyork', 'chicago'],
  categories: ['bia'],
  searchQuery: 'road bike',
  maxItems: 20,
  maxAge: 7,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((a) => [a.area, a.priceValue, a.condition, a.title]));
```

For AI agents, add the Scrape.ly MCP server. In Cursor, put this in `~/.cursor/mcp.json`:

```json
{
  "mcpServers": {
    "scrapely": {
      "url": "https://api.scrape.ly/mcp",
      "headers": { "Authorization": "Bearer YOUR_TOKEN" }
    }
  }
}
```

In Claude Code, run `claude mcp add --transport http scrapely https://api.scrape.ly/mcp` and sign in with `/mcp`. Then ask: "Use scrapely to run shelfbright/craigslist-scraper on bicycles in sfbay from $100 to $2,000, 20 ads, and give me a table of price, condition and neighborhood." Runs this size finish inside the 45 seconds `call-actor` waits; for big runs the agent polls `get-actor-run`. The [Craigslist API](https://scrape.ly/api/craigslist-api.md) page shows the same Actor as an API product.

## A real run: bike ads in New York

We ran the "Bikes for sale in New York, 10 ads" preset on 23 October 2026. It returned 10 ads in 10 seconds and was charged $0.0405. The first five rows:

| Title                                                              | Price    | Neighborhood    | Sub-area | Category            | Condition  | Make       |
| ------------------------------------------------------------------ | -------- | --------------- | -------- | ------------------- | ---------- | ---------- |
| 2018 Cannondale fsi Carbon 5                                       | $500     | Upper West Side | mnh      | bicycles - by owner | good       | Cannondale |
| Monza bicycle 80's style bmx 24" bike skyways tange new!           | $2,000   | New York        | mnh      | bicycles - by owner | new        | Monza      |
| Men's mountain bike                                                | no price | Flushing        | que      | wanted - by owner   | not stated | not stated |
| Woom 5 Red - Lightly Used, Excellent Condition! - Brooklyn Pick up | $550     | Midwood         | brk      | bicycles - by owner | not stated | Woom       |
| LIKE NEW Lizard Lime Woom 2 Kids Bike – (Brooklyn)                 | $350     | brooklyn        | brk      | bicycles - by owner | not stated | Woom       |

These sellers are private people. Craigslist doesn't show their names and the Actor doesn't collect them; we also left out post links, map coordinates and ad text so no ad can be traced back to its owner. What the full ten show:

- **A keyword search is broad.** "bike" matched five bicycle ads, but also an exercise bike, a helmet, a vintage bike in sporting goods and a "wanted" ad. Pick the bicycles category (`bia`) or turn on `titleOnly` when you want bikes only.
- **Cross-posts are common.** The same exercise bike appeared three times, in bicycles, garage sales and general for sale, with three different post IDs. Deduplicating on title and text left 8 unique ads, as in the Python example.
- **Refreshed is not new.** All ten were updated between 10:16 and 10:45 pm on 22 October, but nine had first been published earlier, as far back as 2 August. `datetime` tells you when an ad was refreshed; `postedAt` tells you when it first went up.
- **Prices are optional.** Six of ten had a price, from $25 to $2,000. Wanted ads and some for-sale ads have none.
- **Structured details come along.** Eight of ten carried attributes such as wheel size, frame material, brake type and condition, the fields you need to compare like with like.

The log, without the platform's start-up lines:

```plaintext
20261023T03:01:25.477Z [Scrapely] Container started (setup 4.0 s)
20261023T03:01:26.784Z [scrapely.proxy_configuration] INFO  Platform proxy access check succeeded.
20261023T03:01:31.010Z [scrapely.actor] INFO  [Status message]: 10 ads saved. Stopped at the limit of 10
20261023T03:01:31.492Z [Scrapely] Container state: status=exited exitCode=0 oomKilled=false
```

Reading the search and opening ten ads took about four seconds on the default datacenter proxy. The publisher's own tests put 1,000 ads with full descriptions at about 30 seconds.

## What it costs

The Actor charges one event: $0.004 per ad saved, which is $4 per 1,000 ads. Platform usage is billed on top and is tiny here, because searches are read from the JSON feed the Craigslist site itself uses, not through a browser.

For our run: 10 ads × $0.004 = $0.04 in ad fees. The run was charged $0.0405 in total: $0.0003 of compute, $0.0002 of datacenter proxy traffic and a fraction of a cent of storage. Ads removed before their page loads are not saved and not charged. A 1,000-ad pull costs about $4, so the Free plan's $5 of monthly credit covers it, and a maximum charge per run stops a big job before it goes over.

## What to watch out for when scraping Craigslist

- **10,000 ads per search.** Craigslist caps every search there. Split big jobs by city, category, price range or keyword; the run's status says when a search hit the cap.
- **Old post links are dead.** Links ending in `.html` no longer open on Craigslist. Use `https://www.craigslist.org/view/...` links or a search URL.
- **Contact details stay hidden.** Craigslist puts contact details behind its reply button, and the Actor doesn't press it. `phoneNumbers` only holds numbers a seller typed into the ad; our ten ads had none.
- **Duplicates and reposts.** Deduplicate cross-posts by title and text, and use `postedAt` to tell new ads from refreshed ones.
- **Use the site name, not the city.** `cities` takes Craigslist's own site names on craigslist.org, such as `newyork`, `sfbay` or `london`; copy them from the subdomain of the search page.
- **Blocks.** The built-in datacenter proxy worked in our run. If Craigslist starts refusing requests, switch `proxyConfiguration` to residential.
- **Personal data.** Sellers, landlords and gig posters are mostly private people. Addresses, map positions and phone numbers in ads are personal data, so collect them only if you truly need them.

## Is it legal to scrape Craigslist?

The Actor reads publicly visible ads without logging in, and it never posts, replies or uses the reply button.

Craigslist's [Terms of Use](https://www.craigslist.org/about/terms.of.use) cover automated collection, high-volume access and contacting users, so read them and check how they apply to your project before you start.

Responsible practice keeps the footprint small: set `maxItems` and a maximum charge per run so each job stays at a low volume, analyze prices and supply rather than republishing ads, never contact posters with scraped details, and store personal data only with a lawful basis under privacy laws such as the GDPR and the CCPA. Our guide on [whether web scraping is legal](https://scrape.ly/blog/is-web-scraping-legal.md) covers the general rules. This is not legal advice; if Craigslist data feeds a commercial product, get legal advice for your use case.

## Why Scrape.ly for Craigslist

- **There is no read API.** Craigslist's only developer interface is its [bulk posting interface](https://www.craigslist.org/about/bulk_posting_interface), which submits new ads and is "granted to high volume posters (hundreds of postings per month or more) on a case-by-case basis", limited to paid US categories. It doesn't return search results. The Actor does.
- **Tutorials go stale; fields don't.** The top-ranking ScrapingBee tutorial (January 2026) parses `.result-info` and `.result-title`. When we loaded a New York search page on 23 October 2026, it had zero `.result-info` elements; listings now sit in `li.cl-static-search-result`. The Actor reads the JSON feed the Craigslist site itself uses and hands you `price`, `postedAt` and `attributes` as named fields.
- **Full ads, every section, one shape.** Search snippets give you a title and a price. The Actor opens each ad for the full text, attributes, posting date and map position, and housing, jobs and for-sale ads come back in the same format.
- **Cities times categories.** One run can cover 50 cities and 5 categories, with duplicates removed. Schedule it and compare runs to spot new ads.
- **Part of a resale toolkit.** The same publisher maintains the [eBay Scraper](https://scrape.ly/store/shelfbright/ebay-scraper.md) and scrapers for Amazon, Walmart and Google Shopping. See [how to scrape eBay](https://scrape.ly/blog/how-to-scrape-ebay.md) and our [price scraping](https://scrape.ly/blog/price-scraping.md) guide to compare used and new prices.

## FAQ

### Does Craigslist have an API?

Not for reading ads. Craigslist offers a bulk posting interface for high-volume paid posters, and nothing for searching or downloading listings. To collect ads, use a scraper that reads public search pages.

### Can I scrape Craigslist with Python?

Yes. Install `scrapely-client-python`, call `shelfbright/craigslist-scraper` with a search URL or cities and categories, and iterate over the dataset, as in the example above. You don't need BeautifulSoup selectors or your own proxies.

### How do I scrape Craigslist across several cities?

Put the site names in `cities` (for example `newyork`, `sfbay`, `chicago`) and the category codes in `categories`. The Actor runs every city and category pair in one go and removes duplicates.

### Can I scrape Craigslist housing or job ads?

Yes. Use `apa` for apartments, `hhh` for all housing, `jjj` for jobs or `ggg` for gigs. Housing rows add bedrooms, bathrooms, space and move-in date; jobs add compensation and employment type.

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

$0.004 per ad, so $4 per 1,000, plus a little compute and proxy usage. Our 10-ad run was charged $0.0405 in total.

Scrape.ly Store Scrape Craigslist ads Run the New York bikes preset as-is, paste your own search URL, or list cities and categories. $4 per 1,000 ads with full details.

[Try it free](https://scrape.ly/store/shelfbright/craigslist-scraper.md) [Browse the Store](https://scrape.ly/store.md)

About the author

[Shelfbright](https://scrape.ly/blog/author/shelfbright.md) Actor publisher on the Scrape.ly Store

Prices, stock and seller data from shops and marketplaces, from Amazon and AliExpress to Vinted and Leboncoin. For price trackers, catalogue teams and resellers. A Scrapely studio.

- [Website](https://scrape.ly/users/shelfbright.md)

Keep reading

## More in Tutorials

- [![Pixel-art robot with an orange >\_ on its terminal head pulls an ad card with an image and a blue button out of a monitor showing the blue Facebook logo above two more ad cards, and drops it into a crate](https://scrape.ly/media/scrape-facebook-ads-library.png?w=750)](https://scrape.ly/blog/scrape-facebook-ads-library.md)
  ### [How to Scrape the Facebook Ads Library (Meta Ad Library)](https://scrape.ly/blog/scrape-facebook-ads-library.md)
  [Scrape the Facebook Ads Library for any brand, page or keyword: ad copy, creatives, call to action, landing page, start date, platforms and the Ad Library link. A real run on Nike's active US ads, its exact cost, and code for curl, Python, Node.js and AI agents.](https://scrape.ly/blog/scrape-facebook-ads-library.md)
- [![Pixel-art robot with a terminal for a head pulling a place card out of a Google Maps pin standing on a folded map, with a crate of collected place cards beside it](https://scrape.ly/media/how-to-scrape-google-maps.png?w=750)](https://scrape.ly/blog/how-to-scrape-google-maps.md)
  ### [How to Scrape Google Maps: Places, Ratings, Phones and Websites](https://scrape.ly/blog/how-to-scrape-google-maps.md)
  [Scrape Google Maps places for any search term and city, with no code or with one API call. A real run, its output, its log and its exact cost, plus the limits and the legal side.](https://scrape.ly/blog/how-to-scrape-google-maps.md)
- [![Pixel-art robot with an orange >\_ on its terminal head pulls a parcel from a stack of cardboard boxes marked with the Amazon smile logo and loads it into a crate](https://scrape.ly/media/how-to-scrape-amazon.png?w=750)](https://scrape.ly/blog/how-to-scrape-amazon.md)
  ### [How to Scrape Amazon: Prices, ASINs and Ratings From Search or Product URLs](https://scrape.ly/blog/how-to-scrape-amazon.md)
  [Paste an Amazon search or product URL into a ready-made Actor and get one row per product with price, ASIN, rating and review count. This guide covers the no-code steps, the API, ZIP code pricing, a real run and its cost.](https://scrape.ly/blog/how-to-scrape-amazon.md)

## The internet is full of data. Start owning yours.

Scrape.ly gives you the infrastructure, the tooling, and the team to extract, process, and operationalize web data at any scale. Setup takes minutes. The advantage lasts forever.

[Get Started Free](https://my.scrape.ly/register) [Chat with Support](mailto:support@scrape.ly?subject=Question%20about%20Scrape.ly\&body=Hi%2C%20I%20have%20a%20question%20about%20Scrape.ly.)

No credit card. No setup calls.
