🎉 Premium Proxies · 3-Day Free TrialClaim Now →
Guides

How to Scrape Facebook Marketplace Listings and Prices

Scrape Facebook Marketplace public listings, prices, and locations the right way: past the login wall, out of the GraphQL JSON, with residential proxies.

S SparkProxy 0 22 min read
Share
How to Scrape Facebook Marketplace Listings and Prices

To scrape Facebook Marketplace you have to beat the one defense that stops most people on request one: the login wall. Marketplace is a login-first surface bolted onto the public web, its listing data hides inside GraphQL JSON rather than the HTML you can see, and Meta runs one of the harshest anti-bot stacks online. This guide stays in the narrow, defensible lane of public data only. It opens with the law, because Meta lost a public-data scraping case in 2024 and that shapes what is safe to collect, then shows exactly where price and location fields live, which URL parameters target a city, and why a residential IP plus a real rendered browser is the price of entry.

Ethics and law come first

Facebook Marketplace is not a neutral product catalog. Behind most listings sits a real, identifiable person selling a couch or a car, so the ethics carry more weight than on a pure e-commerce target, and they decide the design before you write any code.

Start with the case that changed the calculus. In Meta Platforms v. Bright Data (N.D. Cal., January 2024), a federal judge granted summary judgment to the scraper on Meta's contract claims, and the reasoning matters: Meta's terms bind logged-in members, and Bright Data collected public data while logged out, so the court found no breach of those terms for that activity. That ruling is the strongest signal you will find that logged-out public collection sits on defensible ground, and it also draws the bright line for this guide. The moment you log in, you are a member bound by the terms, and the analysis flips.

Three legal questions sit underneath any Marketplace project, and "it's public" only answers the first one:

  • Unauthorized access. In the US, the Ninth Circuit's ruling in hiQ Labs v. LinkedIn (2022) held that scraping data that is publicly accessible, meaning no login and no authentication wall, generally does not violate the Computer Fraud and Abuse Act. That is about access, not a licence to do whatever you like with what you collect.
  • Contract. Meta's terms prohibit automated collection. Bright Data found those terms apply to logged-in members, so staying logged out is not a nicety here, it is the whole legal footing. Never authenticate.
  • Data protection. A listing ties to a seller, and a seller is a person. Under GDPR and similar laws, public personal data is still personal data, and public availability is not a lawful basis on its own.

Guardrails that keep a Marketplace project defensible:

  • Collect public, logged-out data only. No sessions, no cookies from a real account, no bypassing the login modal.
  • Login-walled content is out of scope. Seller profiles, message threads, "reply" contact details, and anything the site hides behind the gate stay off limits. If a page only renders after login, treat it as unreachable.
  • Take listing facts (title, price, coarse location, image, category), not dossiers on the people posting them.
  • Rate-limit yourself and back off on errors so you never degrade the service for real buyers and sellers.
  • Honour deletion. If a listing disappears, drop it from your store.
  • Get counsel involved before anything commercial. This is engineering guidance, not legal advice.

The legitimate reasons to want this data are real: price research on used goods, local supply and demand analysis, resale arbitrage, and competitive pricing. If your use case is broader social listening, the business-side patterns live in Using Proxies for Social Media Monitoring. For the sibling Meta property with its own privacy weight, see How to Scrape Instagram Public Data. The point of this section is that the use case has to survive scrutiny before the pipeline is worth building.

The login wall is the whole game

Every Marketplace scraper lives or dies on one behaviour: Facebook increasingly gates the browse experience behind a login or "continue" modal, and the gate frequently returns HTTP 200 with a page that carries no listings. If your code trusts the status code, response.ok is True, you save the page, and you have stored a login prompt instead of results. You have to read the body.

The gate is not uniform, and that inconsistency is the single most useful thing to understand before you build. Two surfaces behave very differently for a logged-out client:

  • Individual item pages at /marketplace/item// are the URLs people paste into chats and forums, and Facebook serves them to logged-out visitors far more often, complete with Open Graph tags and embedded JSON. These are your most reliable public source.
  • Search and category browse grids at /marketplace//search are gated more aggressively. Sometimes they render for a clean residential IP with a real browser, sometimes they bounce you to /login/?next=. Treat a rendered grid as a bonus, not a guarantee.

So the practical strategy is not "hammer the search page until it gives up". It is: pull what the search grid gives you when it renders, and treat individual item URLs as the dependable layer underneath. Detect the wall explicitly on every response, because a 200 that contains a login form is a block wearing a disguise:

def is_login_wall(html: str) -> bool:
    """Marketplace's login gate returns HTTP 200, so the status code lies."""
    markers = (
        "login_form",
        '"loginbutton"',
        "you must log in to continue",
        "/login/?next=",
        "log in to see more",
    )
    low = html.lower()
    return any(m.lower() in low for m in markers)

If a specific URL returns the wall persistently even through a clean residential IP with rendering, that content is login-gated, and login-gated content is out of scope. Do not reach for a logged-in session to get past it. That is the exact line the Bright Data ruling draws, and crossing it trades your legal footing for a few extra rows.

Free trial

Scraping at scale? Skip the blocks.

Fast, unblockable datacentre proxies with unlimited bandwidth.

What public Marketplace data you can collect

A logged-out item page exposes a stable set of fields through Open Graph meta tags and an embedded JSON blob. The markup drifts and the JSON keys get obfuscated between releases, but the fields you can reach are consistent. Here is the reference set worth pulling as of mid-2026, with an honest note on which are reachable without login.

FieldWhere it lives (logged-out)Logged-out reachable?
Listing title`og:title`, `marketplace_listing_title` in JSONYes, on item pages
Price`product:price:amount` meta, `listing_price` in JSONYes, on item pages
Location (city, region)`og:title`/`og:description`, `location.reverse_geocode`Often, and only coarse (city level)
Primary image`og:image`, `primary_listing_photo`Yes
Listing URL / ID`/marketplace/item//`Yes
CategoryJSON `marketplace_listing_category_id`Usually
Posted / creation timeJSON `creation_time`Sometimes
Description`og:description`, `redacted_description`Partial, often truncated
Seller name / profileBehind loginNo, out of scope
Seller contact / messagesBehind loginNo, out of scope
Exact GPS coordinatesNot exposed publiclyNo, approximate city only

Two field notes save you time. Marketplace deliberately shows an approximate location, usually a city or neighbourhood, never a precise pin, so do not build a workflow that expects street-level coordinates. And the price comes back as a formatted string in some places ($450) and a raw amount plus currency in others (450, USD), so normalize to an integer of minor units downstream and keep the currency code beside it.

Where the data lives: GraphQL and embedded JSON

Here is the part most tutorials get wrong. Facebook Marketplace is a Relay app, so the listings you see are fetched through GraphQL POST requests to https://www.facebook.com/api/graphql/, each carrying a doc_id and a variables blob. Open your browser network tab on a Marketplace search and you will watch those XHR responses stream in as JSON. It is tempting to replay them directly.

Resist that for logged-out scraping. Those GraphQL calls depend on rotating doc_id values and per-session tokens (fb_dtsg, lsd) that Facebook mints on page load and cycles constantly, so a replayed request breaks within days and often needs a session you should not have. The durable path for public data is different: render the URL and read the JSON the page bootstraps itself with. Facebook ships the first screen of Relay data inside