Facebook Marketplace Scraper
Scrape Facebook Marketplace listings by keyword and city. Rows carry title, price, currency, location, link, posted date, sold status.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
searchTerms,location,maxItems(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.0004 per listing = $0.4 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Listing | One Facebook Marketplace listing delivered to your dataset, with its title, price, currency, original price, location, listing link, primary photo, posting time, days listed, delivery options, category id and sold/pending status. Sample rows, diagnostics and listings already returned earlier in the same run are never charged. | $0.0004 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-08-16, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
searchTerms | What to look for on Marketplace. Up to 10 terms per run; the row budget below is shared evenly between them. | array |
location | Where to search. A plain city name works ("Austin, TX", "Manchester", "Toronto"), so does a Marketplace city slug ("nyc", "la", "sanfrancisco"), and so does a raw "latitude,longitude" pair. Marketplace search is local, so this is required unless you set the coordinates below or paste a URL that carries them. | string |
maxItems | Total listings to return across all search terms. The budget is shared evenly between the terms, so four terms and 40 rows gives you ten of each. Keep it low while you are testing - you pay per row. | integer |
minPrice | Only listings at or above this price, in the currency of the place you are searching. Leave empty for no lower bound. | integer |
maxPrice | Only listings at or below this price, in the currency of the place you are searching. Leave empty for no upper bound. | integer |
condition | Not applied at the moment. The search runs as if this were empty, so picking a condition does not narrow the listings that come back. It stays on the form so saved tasks that send it keep working. Facebook does not show an item's condition in search results, so there is no condition column in the output either. | array |
daysSinceListed | Only listings posted in the last N days, from 1 to 30. Facebook counts whole days, so a row's postedAt can be a little older than N days. Used together with a sort order, some searches come back empty. Leave empty for all listings. | integer |
sortBy | How Facebook should order the results. Defaults to its own relevance ranking. | string |
availability | Not applied at the moment. The search runs as if this were empty, so choosing Sold does not narrow the listings that come back: you get what is for sale now, and isSold is false on nearly every row. It stays on the form so saved tasks that send it keep working. | string |
exactMatch | Not applied at the moment. The search runs as if this box were unticked, so Facebook matches your term the loose way whatever you choose here. It stays on the form so saved tasks that send it keep working. | boolean |
category | Not applied at the moment. The search runs as if this were empty, so a category id does not narrow the listings that come back. To keep to one kind of item, say it in the search term. It stays on the form so saved tasks that send it keep working. | string |
startUrls | Marketplace search URLs copied straight from your browser, for example https://www.facebook.com/marketplace/nyc/search?query=road%20bike&minPrice=100. Up to 10 per run. The term, the place, the price range, the days-listed limit and the sort order are taken from the URL. A condition, category, radius, availability or exact-phrase setting in the URL is ignored, just as those fields are on this form, and so is a delivery method. Each URL is searched in the city it names, so URLs for different cities can share a run. A URL whose city the run can't place (a numeric Facebook location id, for example) falls back to the run's own location, and a free NO_LOCATION row says so. A filter you set in the fields above wins over the same filter in the URL. | array |
latitude | Centre the search on these exact coordinates instead of a place name, for example 30.2672. Set both latitude and longitude, or neither. | string |
longitude | Centre the search on these exact coordinates instead of a place name, for example -97.7431. Set both latitude and longitude, or neither. | string |
radiusKm | Not applied at the moment. The search runs as if this were empty, and Facebook decides how wide to look around the place you give: an Austin search can bring back towns more than 100 km away. It stays on the form so saved tasks that send it keep working. | integer |
proxyUrls | Leave this empty for a normal run. Fill it in only if you want the traffic to leave through proxy servers you already pay for, one URL per line, in the form http://user:pass@host:port. | array |
sessionCookies | Leave this empty unless you need it. Runs are logged out by default and that is enough for public Facebook content. Facebook shows some things only to a signed-in account, and it limits how fast any one account may read; supplying your own cookie uses your account and your own rate limit, shared with nobody. In Chrome: open facebook.com while signed in, press F12, then Application > Cookies > https://www.facebook.com, and paste the values as "c_user=…; xs=…". One line per account. Treat these like a password: anyone with them can act as that account, and Facebook may sign the session out or restrict the account for automated use. | array |
What you get
A structured dataset — each result includes fields like:
searchTermlistingIdlistingUrltitlepricepriceFormattedcurrencyoriginalPricepriceMinpriceMaxcitystatelocationNameimageUrlExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
Related tools in Real Estate & Classifieds
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
Zillow Scraper
Scrape Zillow search results and full listing details: price, beds, baths, sqft, photos, price history, schools. No login or API key. $0.0008 per property.
Realtor.com Scraper
Realtor.com listings as JSON, by city, ZIP or county. Fields: address, price, beds, baths, sqft, year built, days on market, agent, broker. $0.68/1k.
Craigslist Scraper
Scrape Craigslist listings by city, category and keyword: id, title, price, neighborhood, date, images and URL. No account or API key. $0.85 per 1,000.
Airbnb Listings Scraper
Scrape Airbnb listings by location, dates and guests. Get listing ID, name, room type, price, rating, reviews and host. No account, no API key.
Avito Listings Scraper
Scrape Avito.ru listings by keyword, category or city. Get id, title, price, seller name and type, publish date and photos. $0.30 per 1,000 listings.
Where this tool sits
- Categories
- Real Estate & Classifieds
Facebook Marketplace Scraper: listings and prices for a search, in the city you pick
Tell it what you're after and where, and it returns the Facebook Marketplace listings that search turns up, one row each. Every row has the title, the price and any crossed-out price, the seller's town, the listing link, the main photo and how many days the item has been up. The limit to know before you plan a big job: one search returns about 24 listings, Facebook's first page of results, however high you set maxItems.
Two more things. Five filters on the form (condition, category, sold only, exact phrase and radius) don't change the results at the moment, so don't count on them. And the form arrives filled in with a real search, road bikes in Austin, so pressing Start without editing it runs that search and bills what it finds.
| Input | Search terms and a place, or Marketplace search links from your browser |
| Output | One row per listing |
| Ceiling | About 24 listings per search, up to 10 searches per run |
| Account needed | None from you |
| Price | $0.40 per 1,000 listings, flat on every plan |
🔍 What Facebook Marketplace Scraper does
It runs the search you would run on Marketplace yourself, in the place you name, and writes down what Facebook shows. That is Facebook's idea of the area, not a fixed circle. A search for road bikes in Austin also brought back listings from Round Rock, Georgetown and San Antonio.
Up to ten search terms can share a run. The row budget is split evenly between them, and a listing that two of your terms both find comes back once and is charged once.
A place name Facebook doesn't recognise gets quietly answered with listings from some other city. When Facebook's answer says it searched somewhere other than the place you asked for, those listings are thrown away and you get a free WRONG_LOCATION row instead of a bill for the wrong town.
Already built the search in your browser? Paste the link into startUrls and the term, city, price range, day limit and sort order are read out of it. Each link is searched in its own city, so one run can cover several.
📥 What you give it
{
"searchTerms": ["road bike"],
"location": "Austin, TX",
"minPrice": 300,
"maxPrice": 600,
"daysSinceListed": 7,
"maxItems": 24
}
| Field | If you leave it empty | What it is |
|---|---|---|
searchTerms | your links only, or the free sample row | What to look for, up to 10 terms. The form arrives with road bike in it. |
location | the city in your first link, if any | Where your search terms are searched: a city name ("Austin, TX", "Manchester"), a Marketplace city slug ("nyc", "la") or a latitude,longitude pair. Marketplace search is local, so a run needs a place. Links keep the city they name. |
maxItems | 20 | Total listings across all terms, 1 to 1,000, shared evenly between them. Each search still stops at about 24. |
minPrice, maxPrice | no limit | Price range in the currency of the place you search. |
daysSinceListed | any age | Only listings posted in the last 1 to 30 days. Facebook counts whole days, so a row's postedAt can be a little older than that. |
sortBy | Facebook's own order | best_match, newest, price_low_to_high, price_high_to_low or distance. |
startUrls | none | Up to 10 Marketplace search links, such as https://www.facebook.com/marketplace/nyc/search?query=road%20bike&minPrice=100. Each link is searched in the city it names. One whose city the run can't place (a numeric Facebook location id, for example) falls back to location, with a free NO_LOCATION row. A filter you also set in the fields above wins over the one in the link. |
latitude, longitude | none | Exact coordinates instead of a place name. Set both or neither. |
condition, category, availability, exactMatch, radiusKm | no effect | On the form, but the search currently runs as if they were empty. |
proxyUrls | empty | Only if you want the requests to go out through servers of your own, as http://user:pass@host:port. |
sessionCookies | empty | Your own Facebook cookies, one account per line, as c_user=…; xs=…. Optional, see the questions below. |
📤 What you get back
A real row from a real run, with the photo link cut short:
{
"ok": true,
"charged": true,
"recordType": "listing",
"searchTerm": "road bike",
"listingId": "1807545393723285",
"listingUrl": "https://www.facebook.com/marketplace/item/1807545393723285/",
"title": "Giant TCR C3 Road Bike. 600$ OBO. Full Carbon Frame + Fork. 700x 23c tires.",
"price": 600,
"priceFormatted": "$600",
"currency": "USD",
"originalPrice": 850,
"priceMin": null,
"priceMax": null,
"city": "Austin",
"state": "TX",
"locationName": "Austin, Texas",
"imageUrl": "https://scontent.fpei1-1.fna.fbcdn.net/v/t39.84726-6/818962247_1436233761733825_8678125269974170042_n.jpg?stp=...",
"videoUrl": null,
"postedAt": "2026-09-20T15:32:49.000Z",
"postedAtTimestamp": 1789918369,
"daysListed": 9,
"isSold": false,
"isPending": false,
"isLive": true,
"categoryId": "1658310421102081",
"deliveryTypes": ["IN_PERSON"],
"subtitle": null,
"fromGroup": null,
"scrapedAt": "2026-09-30T02:26:04.593Z"
}
| Field | What it is |
|---|---|
listingId, listingUrl | The item's id and permanent link. Stable, so use either as your key across runs. |
price, priceFormatted, currency | The asking price as a number, the exact text Facebook shows, and the currency code worked out from that text's symbol. price is null when the listing has none. |
originalPrice | The crossed-out price when the seller has cut it, otherwise null. The row above dropped from 850 to 600. |
priceMin, priceMax | Filled in only for listings priced as a range. |
city, state, locationName | Where the seller says the item is. state is empty in countries without one. |
postedAt, postedAtTimestamp, daysListed | When it was listed, as an ISO date and as epoch seconds, and how many days ago that was. |
isSold, isPending, isLive | The listing's status when the run read it. A search shows what is for sale now, so isSold is false on nearly every row. |
deliveryTypes | How the seller will hand it over, such as IN_PERSON, PUBLIC_MEETUP or DOOR_PICKUP. |
categoryId | Facebook's internal department id. Fine for grouping, but Facebook publishes no name for it, so none is made up here. |
subtitle, fromGroup | The extra line on vehicle listings (mileage and so on), and the group name when the item was cross-posted from one. Null on most rows. |
searchTerm | Which of your terms found it. |
🧾 Reading the output
Three kinds of row can land in the dataset.
| Row | How to spot it | Charged |
|---|---|---|
| A listing | charged: true | yes |
| The sample row | _sample: true | no |
| A diagnostic | _diagnostic: true, with an errorCode and a details sentence | no |
The sample row only appears when the input has no search terms and no links. It shows the shape of a real row and also says recordType: "listing", so filter on charged rather than on recordType to keep just the listings.
errorCode | What it means |
|---|---|
NO_LOCATION | The run had no place it could search, so nothing was searched. On a link's row it means that link's city couldn't be placed, so the run's own location was searched instead. |
WRONG_LOCATION | Facebook didn't recognise the place and answered with somewhere else. Those listings were thrown away. |
NO_RESULTS | Nothing for that term in that place. A narrow term, a tight price range, or a sort order used together with daysSinceListed can do it. |
BLOCKED | Facebook wouldn't show that search this time. Running it again later usually works. |
BAD_INPUT | A link in startUrls isn't a Marketplace link. |
NETWORK, TIME_BUDGET, CHARGE_ERROR and the rest | Rare. The details sentence says what happened. |
▶️ How to run it
1. Open Facebook Marketplace Scraper and click Try for free. 2. Type what you're looking for into Search terms, one per line. 3. Put the city in Location. 4. Set Maximum rows. Under Filters, add a price range or Listed within the last N days if you want them. 5. Click Start, then download the dataset as JSON, CSV or Excel, or read it from the API.
💰 How much does it cost?
$0.40 per 1,000 listings, flat on every Apify plan.
You pay per listing row. The sample row and the diagnostic rows are never charged. A listing that two of your terms both found is charged once, and one thrown away because Facebook searched the wrong city isn't charged at all.
💡 What people use it for
- Resellers running the same few terms every morning with
daysSinceListedset to 1, so each run holds only what went up since yesterday. - Pricing something before buying or listing it: take the median of
priceacross two dozen local listings instead of guessing. - Finding sellers who have already come down. Every row with an
originalPriceis one of them. - Keeping a spreadsheet of what's for sale in a category you trade in, instead of scrolling the feed by hand.
🚧 What it does not do
- More than about 24 listings per search. That is Facebook's first page, and there is no paging past it. A bigger
maxItemsonly helps if you add more terms. - Condition, category, sold only, exact phrase or radius filtering. Those fields are on the form but change nothing right now.
- Seller names or item condition as columns. Facebook leaves both out of search results.
- Shipped items only. Asked for those, Facebook's search here returns nothing.
- Several cities for your typed search terms.
locationtakes one place. To cover more cities in one run, paste a Marketplace link for each city intostartUrls. - A radius you choose. Facebook decides how wide to look, and an Austin search can pull in towns more than 100 km away.
- Listings only group members can see. You get what Facebook shows anyone.
- Photo links that last.
imageUrlpoints at Facebook's image server and stops working after a while, so download the photos you want to keep.
🧭 Which marketplace scraper do you need?
| If you want | Use |
|---|---|
| Facebook Marketplace listings for a search, in the cities you name | This one |
| Classified ads from one Craigslist city and category | Craigslist Scraper |
| Classified ads on Gumtree in the UK | Gumtree UK Scraper |
| What an item actually sold for on eBay | eBay Sold Listings Scraper |
| Posts from a public Facebook group, buy-and-sell groups included | Facebook Groups Scraper |
❓ Questions people ask
Do I need a Facebook account? No. Nothing of yours is used unless you paste cookies into sessionCookies. Do that only if you want the run to use your own account and rate limit instead of the one the actor shares between everyone who runs it. Treat those values like a password: anyone holding them can act as you, and Facebook may sign the session out.
Why do I have to give a place? Marketplace only searches locally. With no place the run writes a free NO_LOCATION row and stops before searching anything.
Why did I get fewer rows than maxItems? Each search stops at about 24, the budget is split evenly between your terms, and a listing found twice counts once.
Why did a search come back empty? Look at the diagnostic row. NO_RESULTS means the filters were too tight for that place, WRONG_LOCATION means try the plain city name or the short name Facebook uses in its own links, and BLOCKED means try again later.
Can I run it every day? Yes. Nothing is kept between runs, so use listingId to spot what's new and postedAt to sort it.
Is scraping Marketplace legal? The listings are public, though photos and descriptions sometimes carry personal details, so keep what you need and think before republishing it. Apify's article on whether web scraping is legal is worth reading first. None of this is legal advice.
🆘 If something breaks
Open the Issues tab on the actor page and send the input you used with the run ID. The diagnostic rows in the dataset usually name the reason already.