Craigslist Scraper - Listings by City and Category
Pricing
from $0.85 / 1,000 listing returneds
Craigslist Scraper - Listings by City and Category
Scrape Craigslist listings by city, category and keyword. Every Craigslist city is its own site. One run covers one city and one category. Rows have the listing id, title, price, neighborhood, posted date, images and URL. No account, no API key. A flat $0.85 per 1,000 listings.
Pricing
from $0.85 / 1,000 listing returneds
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
5
Total users
2
Monthly active users
2 days ago
Last modified
Categories
Share
Craigslist Scraper: listings by city, category and keyword, no API key
Give it a city, a category and something to search for. You get rows with the listing id, title, price, posted time, neighbourhood, coordinates, image links and the listing URL. Switch on full posting text and each row also carries the seller's body text and the attribute table.
Craigslist has no nationwide index. Every city is its own site, so one search covers one city. You can list several cities in one run, and each one is searched separately.
| Input | A city, a category and a search term, or Craigslist search URLs |
| Output | One row per listing |
| Ceiling | 50,000 listings per run |
| Account needed | None, and no API key |
| Price | $0.85 per 1,000 listings, flat on every plan |
🔍 What Craigslist Scraper does
It runs the search Craigslist's own filter bar would run, and hands you the results as structured rows instead of a page you have to read. Price bounds, owner or dealer, photos only, titles only, posted today, and a postal code with a radius are all there.
City names are forgiving. newyork, new york city, sfbay and london all resolve, and 707
Craigslist sites across 79 countries are recognised. If you would rather not think about
abbreviations at all, paste a Craigslist search URL into searchUrls and whatever filters are
already in it are kept.
Rows are written at the end of the run rather than as they are found, so keep maxItems at a size
the run can finish.
📥 What you give it
{"city": ["sfbay"],"query": "toyota tacoma","category": "cta","maxItems": 500,"maxPrice": 25000}
| Field | Default | What it is |
|---|---|---|
city | none | The Craigslist site, as a subdomain like newyork or a plain name like new york city. Add several to cover several cities. The box starts with newyork in it, which is a suggestion and not a default. |
query | none | What to search for. Leave it empty to take the whole category. The box starts with bike in it. |
category | sss | The category abbreviation. Groups: sss all for sale, hhh housing, jjj jobs, ggg gigs, bbb services, ccc community, cta cars and trucks, eee events. Leaf codes work too: bia bicycles, apa apartments, fuo furniture, zip free stuff, ela electronics. |
searchUrls | none | Paste Craigslist search URLs instead of filling in the fields above. |
maxItems | 100 | Total listings across every search in the run, up to 50,000. |
fetchDetails | false | Open each posting for the body text, the attribute table, the street address where one is shown and the last-updated time. Slower, roughly one extra request per listing. |
sort | newest | newest or relevant. Relevance stops at 360 results, which is Craigslist's cap. |
minPrice, maxPrice | none | Price bounds. |
postalCode, radiusMiles | none | Search around a postal code rather than the whole city. Set both. |
sellerType | any | owner or dealer, in the categories that have both. |
hasImage | false | Skip postings with no photos. |
titleOnly | false | Match your terms against titles only. |
postedToday | false | Only today's postings. |
proxyConfiguration | none | Optional. Leave it alone unless you need the run to go out through a particular network. |
📤 What you get back
A real row, with the image list cut short:
{"listingId": "7959183765","title": "Dutch Gazelle Tour Populair C8, 61CM, In storage, like NEW IMPORT","price": 850,"priceText": "$850","currency": "USD","url": "https://www.craigslist.org/view/d/long-island-city-dutch-gazelle-tour/fRrdPyQukG7jW8afcTduEd","postedAt": "2026-09-14T05:37:44.000Z","categoryId": 68,"categoryAbbr": "bik","categoryName": "bicycles - by owner","location": "LIC","neighborhood": null,"subarea": "que","city": "newyork","cityName": "new york city","region": "NY","country": "US","latitude": 40.7446,"longitude": -73.9345,"images": ["https://images.craigslist.org/00L0L_2mdiEek2CdR_0dI07I_600x450.jpg", "..."],"imageCount": 9,"searchUrl": "https://newyork.craigslist.org/search/sss?query=bike","scrapedAt": "2026-09-14T05:42:36.888Z"}
| Field | What it is |
|---|---|
listingId | Stable. Use it as your dedupe key across runs. |
price | A number, and null when the posting has no price. Jobs, gigs and most community posts have none. priceText keeps Craigslist's own formatting. |
postedAt | A real timestamp, not a relative phrase. |
location | Craigslist's free-text place label, filled in on effectively every row. neighborhood is a separate assigned field and is usually null. |
latitude, longitude | Coordinates for the posting, which is what makes a map or a distance filter possible. |
images | Image URLs at 600x450. imageCount is how many of those were built for the row. |
searchUrl | Which of your searches produced this row, so a multi-city run is easy to split. |
With Fetch full posting text on, five more fields land on the same row: description (the
seller's body text), attributes (the labelled table, so condition and odometer on a car,
rent period on a rental, frame size on a bike), attributeTags (the unlabelled chips like
1BR / 1Ba), updatedAt and address. A posting that disappeared between the search and the
detail fetch keeps its search fields and gains a detailError.
🧾 Reading the output
| Row | How to spot it | Charged |
|---|---|---|
| A listing | It has a listingId and no charged field | yes |
| The sample row | _sample: true and charged: false | no |
| A diagnostic | _diagnostic: true and an errorCode | no |
charged: false is the marker on the rows that are not listings. A real listing row does not carry
the field at all, so filter on _sample and _diagnostic being absent.
errorCode | What it means |
|---|---|
BAD_INPUT | That city could not be resolved to a Craigslist site. Check the spelling, or use the subdomain. |
BAD_SEARCH | Craigslist turned the search down, nearly always a category abbreviation that does not exist for that site. |
NO_RESULTS | The search ran and matched nothing. Try a broader term, another category, or a bigger radius. |
SEARCH_REJECTED | Craigslist answered with something that could not be read. Re-run it. |
BLOCKED | The request did not get through. Try again in a few minutes. |
Every diagnostic carries a hint in plain words, and one failed search never stops the others.
▶️ How to run it
- Open Craigslist Scraper and click Try for free.
- Put your city into City and what you want into Search terms.
- Set Category.
ssscovers everything for sale and is a fine starting point. - Set Maximum listings, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it from the Apify API.
💰 How much does it cost?
$0.85 per 1,000 listings. Flat on every Apify plan, no volume tiers.
You pay per listing row. Turning on full posting text does not add a second charge, it just adds fields to the same row. The sample row is not charged, diagnostic rows are not charged, and a listing id seen twice in one run only becomes one row.
💡 What people use it for
- Watching a city and category on a schedule and diffing on
listingId, so you see what went up since yesterday without reloading a page. - Pulling every car under a price in one metro, with
attributeson, so odometer and title status arrive as columns rather than as paragraphs. - Rental research:
hhhorapawith a postal code and a radius, then readingattributeTagsfor bedroom counts and square footage. - Finding dealer postings hiding in an owner category, or the reverse, using
sellerType. - Mapping what is for sale where, because every row carries coordinates.
🚧 What it does not do
- One city per search. There is no nationwide Craigslist index. List several cities and each is searched on its own.
- Relevance sorting stops at 360 results. Craigslist's cap, not a setting here.
newesthas no such limit, which is why it is the default. - No sorting by price. Craigslist no longer offers it. Sort the dataset yourself.
- No seller contact details. No phone number, no email, no reply-to address. Craigslist keeps those behind its own relay.
neighborhoodis usuallynull. Craigslist only assigns neighbourhoods in a few dense metros.locationis the field to rely on.- Cross-posts are separate rows. The same couch posted to three subareas is three postings with three ids, and Craigslist reports them separately.
- Rows land at the end of the run, so a run that hits its time limit writes nothing. Full posting
text roughly doubles the work, so pick
maxItemswith that in mind. - Postings expire and get deleted.
scrapedAtrecords when the row was read.
🧭 Which listings scraper do you need?
| If you want | Use |
|---|---|
| Craigslist listings by city and category | This one |
| Classified listings across Russia and the CIS | Avito Listings Scraper |
| AliExpress search results with prices and order counts | AliExpress Products Scraper |
| Wholesale prices, minimum order quantities and suppliers | 1688 Wholesale Scraper |
| Buyer reviews with photos for a shop | Shopee Shop Reviews Scraper |
❓ Questions people ask
Do I need a Craigslist account? No. Nothing to log into and no key to apply for.
Can I search the whole country at once? No, and neither can Craigslist. Pass a list of cities instead.
Why did I only get 360 results? You used relevance sorting. Switch Sort to newest first.
Can I get the seller's phone or email? No. Craigslist hides them behind its own relay, so they are not on the page to read.
Is price missing a lot? In job, gig and community categories, yes, because those postings have
no price. For-sale postings where the seller left it blank also come back null.
Can I schedule it? Yes. Keep listingId as your key and each run tells you what is new.
Is scraping Craigslist legal? These are public postings, and they can contain personal data, which GDPR and similar laws cover, so have a reason for collecting it. Check Craigslist's terms too. Apify's write-up on scraping and the law is a good starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the city, the category and the run ID. If you got a
diagnostic row, its errorCode and hint usually name the problem on their own.