Request a tool
All toolsGuidesMCP serverRequest a toolPlatformsCategories
Facebook Marketplace Scraper icon

Facebook Marketplace Scraper

Scrape Facebook Marketplace listings by keyword and city: title, price, currency, location, link, photo, posted date, sold status. No login or cookies.

30 runs on Apify
Run this in the cloudRun on Apify →

Real Estate & Classifieds

How it works

  1. 1
    Open it on Apify

    Hit Run on Apify — it opens the tool in the cloud, no install.

  2. 2
    Set the inputs

    Adjust searchTerms, location, maxItems (sensible defaults are pre-filled).

  3. 3
    Click Run

    The tool runs on Apify’s cloud and collects the data for you.

  4. 4
    Export the results

    Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.

Inputs

FieldWhat it doesType
searchTermsWhat to look for on Marketplace. Up to 10 terms per run; the row budget below is shared evenly between them.array
locationWhere 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
maxItemsTotal 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
minPriceOnly listings at or above this price, in the currency of the place you are searching. Leave empty for no lower bound.integer
maxPriceOnly listings at or below this price, in the currency of the place you are searching. Leave empty for no upper bound.integer
conditionOnly listings the seller marked with these conditions. A single value is the most reliable; several are passed through exactly as the site's own filter sends them. Note that the condition is a filter you can search by, not a column that comes back - Facebook does not publish it in search results.array
daysSinceListedOnly listings posted in the last N days, from 1 to 30. Leave empty for all listings.integer
sortByHow Facebook should order the results. Defaults to its own relevance ranking.string
availabilitySearch available listings, or sold ones.string
exactMatchMake Facebook match your term as a phrase rather than loosely. Useful for a model number or an exact product name.boolean
categoryA Facebook Marketplace category id, if you want to narrow the search to one department. Leave empty to search everything.string
startUrlsMarketplace 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, place, price range, condition, sort order and category in the URL are all read out of it. Anything you set in the fields above wins over the URL.array
latitudeCentre the search on these exact coordinates instead of a place name, for example 30.2672. Set both latitude and longitude, or neither.string
longitudeCentre the search on these exact coordinates instead of a place name, for example -97.7431. Set both latitude and longitude, or neither.string
radiusKmSent to Facebook exactly as its own radius filter sends it. Be aware that the public search applies its own catchment around the coordinates: the same search at 2 km and at 500 km returns the same listings. The coordinates, not the radius, decide the search area.integer
proxyUrlsLeave this empty. The run brings its own egress and its cost is already inside the price you see. Fill it in only if you specifically want the traffic to leave through proxy servers you already pay for, in the form http://user:pass@host:port.array
sessionCookiesLeave 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=<value>; xs=<value>". 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:

searchTermlistingIdlistingUrltitlepricepriceFormattedcurrencyoriginalPricepriceMinpriceMaxcitystatelocationNameimageUrl

Export 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 iconReal Estate & Classifieds

Zillow Scraper

Zillow scraper at $0.0008 per property plus a $0.001 run start. Search results and full listing details: price, beds, baths, sqft, photos, price history.

Ready to run — no setup

Realtor.com Scraper iconReal Estate & Classifieds

Realtor.com Scraper

Scrape Realtor.com listings as JSON: address, price, beds, baths, sqft, lot size, year built, days on market, agent, broker, photos, coordinates.

Ready to run — no setup

Craigslist Scraper iconReal Estate & Classifieds

Craigslist Scraper

Scrape Craigslist listings by city, category and keyword at $0.85 per 1,000: id, title, price, neighborhood, date, images and URL. No account or API key.

Ready to run — no setup

Airbnb Listings Scraper iconTravel, Hotels & Events

Airbnb Listings Scraper

Scrape Airbnb search results by location, dates and guest count: listing ID, name, room type, price, rating, reviews and host. No account or API key.

Ready to run — no setup

Avito Listings Scraper iconReal Estate & Classifieds

Avito Listings Scraper

Scrape Avito.ru listings: id, title, price, category, city, seller name and type, publish date, photos. Filter by region, price and seller.

Ready to run — no setup

See all Real Estate & Classifieds →

Facebook Marketplace Scraper

Give it a search term and a place, and get back the Facebook Marketplace listings that match: title, price, currency, city, listing link, photo, and when it was posted. Filter by price range, category, item condition, how recently it was listed, and sort the way the site does. No Facebook account, no cookies, no login, no browser.

  • Search many terms in one run — each listing is one row, deduplicated across terms so you are never charged twice for the same item.
  • Works anywhere Marketplace does: give a city name, a Marketplace city slug, or raw coordinates, and the search is centred there.
  • Price range, item condition, listed-in-the-last-N-days, category and sort order are all real filters applied by Facebook, not filtered afterwards.
  • Paste a Marketplace search URL straight from your browser and it is parsed into the same filters.
  • Runs with empty input return one labelled sample row, free, so you can see the exact output shape before spending anything.

Price

$0.40 per 1,000 listings, plus a $0.0025 start fee per run (billed per gigabyte of run memory, so exactly that on the default 1 GB).

This is the cheapest Facebook Marketplace scraper on the market, and it is the same rate on every plan, free or paid. There are no volume tiers, no minimum spend, no subscription and no add-on fees. What you read here is what you pay on day one and on day four hundred.

ListingsTotal cost
100$0.0425
1,000$0.4025
10,000$4.0025
100,000$40.0025

What is actually charged

  • One listing-scraped event per listing row written to the dataset. Nothing else is metered per row.
  • Free: the sample row an empty run returns, and every diagnostic row — a blocked target, a dead URL, a search that matched nothing. Those rows all carry "charged": false.
  • Listings that already appeared earlier in the same run are dropped before they are charged.
  • A search term that matches nothing produces an uncharged diagnostic row, not a bill.
  • A run that finds nothing costs the start fee and nothing more.
  • Rows never leave the dataset without a charge, and are never charged without a row. The billed event is a named one, so there is no price quietly attached to apify-default-dataset-item — the trick that makes some scrapers bill you for their own error messages.

Input

{
  "searchTerms": [
    "road bike",
    "mountain bike"
  ],
  "location": "Austin, TX",
  "minPrice": 100,
  "maxPrice": 800,
  "daysSinceListed": 7,
  "sortBy": "newest",
  "maxItems": 60
}
FieldWhat it does
searchTermsOne or more things to search for. Up to 10 per run. The row budget is shared evenly between them.
locationWhere 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 location-based, so this is required unless you set latitude and longitude yourself or paste a URL that carries them.
latitude / longitudeExact coordinates to centre the search on, if you would rather not rely on a place name.
startUrlsMarketplace search URLs copied from your browser. The search term, place, price range, condition, sort order and category in the URL are all read out of it and applied.
minPrice / maxPricePrice range, in the currency of the place you are searching. Both optional.
conditionAny of new, used_like_new, used_good, used_fair. One value is the most reliable; several are passed through exactly as the site sends them.
daysSinceListedOnly listings posted within the last N days, 1 to 30.
categoryA Marketplace category id, if you want to narrow to one department.
sortByOne of best_match, newest, price_low_to_high, price_high_to_low, distance. Defaults to Facebook's own relevance order.
exactMatchSet true to make Facebook match the phrase more strictly instead of loosely.
availabilitySet to sold to look at sold listings instead of available ones.
radiusKm / radiusMilesPassed through to Facebook exactly as its own filter sends it. Read the limitations section before relying on it.
maxItemsTotal rows across all terms. Default 20, hard ceiling 1,000. Keep it low while testing — you pay per row.
proxyUrlsLeave empty. Fill it in only if you want the traffic to leave through proxy servers you already pay for, as http://user:pass@host:port.

Run it with empty input and you get one clearly labelled sample row, free, so you can see the output shape before you spend anything.

Output

One row per listing. A real row from a real run:

{
  "ok": true,
  "charged": true,
  "recordType": "listing",
  "searchTerm": "road bike",
  "listingId": "1510649247532466",
  "listingUrl": "https://www.facebook.com/marketplace/item/1510649247532466/",
  "title": "RoyalBaby Freestyle 20 Inch Kids Bicycle with Kickstand and Water Bottle, White",
  "price": 68,
  "priceFormatted": "$68",
  "currency": "USD",
  "originalPrice": null,
  "priceMin": null,
  "priceMax": null,
  "city": "New York",
  "state": "NY",
  "locationName": "New York, New York",
  "imageUrl": "https://scontent.xx.fbcdn.net/v/t39.84726-6/767388547_2298847434264202_example_n.jpg",
  "videoUrl": null,
  "postedAt": "2026-08-07T14:44:36.000Z",
  "postedAtTimestamp": 1786301076,
  "daysListed": 9,
  "isSold": false,
  "isPending": false,
  "isLive": true,
  "categoryId": "1658310421102081",
  "deliveryTypes": [
    "IN_PERSON",
    "PUBLIC_MEETUP"
  ],
  "subtitle": null,
  "fromGroup": null,
  "scrapedAt": "2026-08-16T09:14:02.771Z"
}

Field notes

  • listingUrl — the permanent link to the item. Stable, and safe to use as a primary key across runs.
  • price — a plain number in the listing currency. A "Free" listing is 0. A listing with no price at all is null.
  • priceFormatted — exactly the string Facebook shows, symbol included.
  • currency — the ISO code, read from the symbol Facebook formats the price with. See the limitations section.
  • originalPrice — the crossed-out price when the seller has cut it; null otherwise. originalPrice minus price is the discount.
  • priceMin / priceMax — only populated for listings sold as a price range rather than a single figure.
  • city / state / locationName — where the seller says the item is. state is empty in countries that do not use one.
  • imageUrl — the primary photo, as a Facebook CDN link. Those links expire after a while, so download what you want to keep.
  • postedAt / postedAtTimestamp — when the listing was created, as ISO 8601 in UTC and as epoch seconds.
  • daysListed — how long the item has been sitting there, in days. Useful for spotting stale listings.
  • isSold / isPending / isLive — the item status at read time.
  • categoryId — Facebook's internal department id for the item. Stable, so you can group by it, but Facebook does not publish a public name for it.
  • deliveryTypes — how the seller will hand it over, e.g. IN_PERSON, PUBLIC_MEETUP, SHIPPING.
  • subtitle — the extra line Facebook shows under vehicle listings — mileage and similar. Null for most categories.
  • fromGroup — set when the item was cross-posted from a buy-and-sell Group; null otherwise.

Every real row carries "charged": true. Sample rows carry "_sample": true and diagnostic rows carry "_diagnostic": true with an errorCode you can filter on, and neither is ever billed.

How it works

  • It calls the same public search endpoint the Marketplace page itself calls, and reads the listings straight out of the JSON it returns — no page rendering, no headless browser, no Facebook account, no cookies and no login.
  • Only the search results are fetched, which is about 2.6 KB of traffic per listing. That is deliberate: the equivalent rendered page is seventeen times bigger for the same rows, and paying for those bytes is what makes most scrapers of this site expensive.
  • Requests go out through the kind of addresses Facebook serves Marketplace to, and the cost of that egress is already inside the price you see — there is nothing for you to configure and no proxy of your own to buy.
  • Each search is paged until your maxItems is reached, and listing ids already seen in the run are skipped so you are never charged for the same item twice.
  • If Facebook rotates the internal id of its own search query, the Actor re-reads the current one from the page and carries on instead of failing.

What people use it for

  • Reselling and arbitrage — run the same terms every morning, sort by postedAt, and see only what appeared since yesterday.
  • Price research before buying or listing something: pull 200 comparable items, then take the median of price rather than guessing.
  • Local market monitoring for a category you trade in — furniture, bikes, tools, phones — with daysSinceListed set to 1 so each run is only new stock.
  • Spotting price drops: originalPrice minus price gives you every listing whose seller has already cut the asking price.
  • Feeding a dashboard or spreadsheet with a clean typed table instead of scrolling an infinite feed by hand.
  • Lead lists for dealers and buyers in one metro area — search a term, centre it on the city, keep everything under a price ceiling.

Reading the output

Every run writes three kinds of row, and they are easy to tell apart:

  • Real rows carry "charged": true and "recordType": "listing". These are the rows you paid for, one billed event each.
  • The sample row carries "_sample": true and "charged": false. There is exactly one, it only appears when the input had no search terms and no URLs, and it exists so you can look at the shape of the output before you spend anything.
  • Diagnostic rows carry "_diagnostic": true, "charged": false and an errorCode you can switch on: NO_LOCATION when the run had no usable place to search, NO_RESULTS when a term matched nothing, BLOCKED when Facebook refused every address tried for that term, NETWORK when it could not be reached at all, BAD_INPUT when a supplied URL was not a Marketplace URL, and TIME_BUDGET when the run ran out of time before reaching a term.

If you only want the data, filter on charged == true. The count of those rows always equals the number of events you were billed for, so the dataset is its own invoice.

Searching by URL instead of by term

If you have already built the search you want in a browser, paste the URL into startUrls and it is taken apart for you. All of these work:

https://www.facebook.com/marketplace/nyc/search?query=road%20bike
https://www.facebook.com/marketplace/la/search?query=sofa&minPrice=50&maxPrice=400
https://www.facebook.com/marketplace/austin/search?query=guitar&daysSinceListed=7&sortBy=creation_time_descend

The place in the path becomes the search location, and query, minPrice, maxPrice, itemCondition, daysSinceListed, sortBy, exact and category_id all become the matching filters. Anything you also set in the input fields wins over what the URL said, so you can paste one URL and vary one knob.

Limitations

  • The seller's name is not returned. Facebook does not put it on the public search results at all — the field comes back empty for every logged-out caller, and the only page that carries it costs far more in traffic than a listing is worth. Rather than sell you a column that is always blank, it is left out.
  • Item condition is a filter you can search by, but not a field that comes back, for the same reason: it lives on the individual listing page rather than in the search results.
  • radiusKm is sent to Facebook exactly as its own radius filter sends it, but the public search applies its own catchment around the coordinates: the same search at 2 km and at 500 km returned the same listings in the same order. Treat the coordinates, not the radius, as what decides the search area.
  • Facebook returns 24 listings per page and caps it there, so a large maxItems means several pages and a longer run. Very deep paging eventually stops returning new items — Marketplace itself does the same.
  • currency is read from the symbol Facebook formats the price with. Facebook disambiguates the ones that matter (CA$, MX$, A$, R$), so this is reliable, but a locale using a symbol shared by two currencies can be ambiguous. priceFormatted always holds the literal string if you want to check.
  • Photo links point at Facebook's CDN and expire after a period. Download anything you intend to keep.
  • categoryId is Facebook's internal department id. There is no public name for it, so no name is invented.
  • Marketplace throttles hard at peak hours. A term that is refused produces an uncharged BLOCKED diagnostic row and the run carries on to your other terms; re-running usually succeeds.
  • Only listings visible to a logged-out visitor are returned. Anything Facebook restricts to signed-in users, or to members of a private Group, is out of reach and always will be — this Actor never signs in.
  • The hard ceilings are 1,000 rows and 10 search terms (or Marketplace URLs) per run. Split bigger jobs across runs.

Questions

Do I need a Facebook account or cookies?

No, and you should not supply any. The Actor reads only what Facebook serves to the public, with no session of any kind. Nothing you own is ever logged in and nothing is ever at risk of being flagged.

Why do I have to give a location?

Because Marketplace is a local marketplace — the search endpoint returns an empty result for a query with no coordinates. A plain city name is enough; it is turned into coordinates for you.

Why is there no seller name?

Facebook does not include it in public search results. It is only on the individual listing page, and fetching that page per item would cost many times what a row sells for. Selling you an always-blank column would be worse than saying so.

What happens if a term matches nothing?

You get one uncharged diagnostic row for that term with errorCode: "NO_RESULTS", and the run carries on to your other terms. You are never billed for a term that returned nothing.

Will the run fail if Facebook blocks it?

No. A refused search produces an uncharged BLOCKED diagnostic row and the run still finishes as succeeded. A failed run would still bill you the start fee, which would mean paying to be told something went wrong.

Can I run this on a schedule?

Yes. Nothing is held between runs, so the same input is safe to repeat. Use listingId to work out which rows are new since last time, and postedAt to sort them.

How do I get exactly the rows I paid for?

Filter the dataset on "charged": true. Sample and diagnostic rows are always false, and the number of charged rows always equals the number of billed events.

Does it work outside the United States?

Yes. Any place Marketplace operates in works — city names in the UK, Canada, Australia, Europe, Latin America and Asia all resolve, and prices come back in the local currency.