spyderproxy

How to Scrape Facebook Marketplace (2026): Listings, Prices, Sellers

A

Alex R.

|
Published date

2026-04-21

Facebook Marketplace is the largest peer-to-peer classifieds platform on the internet, bigger than Craigslist, OfferUp, and eBay Classifieds combined. For resellers, price-intelligence teams, and brand-protection analysts, scraping it is high value — but Meta's anti-bot stack treats Marketplace as core infrastructure and defends it accordingly.

This guide is the practical 2026 playbook: what endpoints are reachable, what tokens you need, which proxy type keeps your account alive, and working code for listings, price history, and seller profiles.

What You Can Scrape From Facebook Marketplace

  • Listings — title, price, location, photos, description, posted timestamp, seller handle
  • Category feeds — "Cars", "Apparel", "Electronics" in a given radius/city
  • Search results — keyword search within a location
  • Seller profiles — public listing history, active listings, response time indicator
  • Price changes — by polling the same listing over time

What you cannot scrape: private messages, buyer/seller personal data beyond their public Facebook profile, listings that have been removed (Meta purges them fast from public endpoints), or anything from a region where you're not logged in via an IP in that region.

The Three Technical Approaches

Approach 1: The Public Listing URL (Unauthenticated)

Individual Marketplace listings at facebook.com/marketplace/item/<id> partially render without login. Meta returns a trimmed HTML document with Open Graph tags (title, price, image) and a JSON blob inside a script tag. This is enough for basic price-monitoring and brand-protection tasks.

Limits: no seller detail, no description beyond a snippet, no message link, no photos beyond the hero image. Rate limits bite fast — around 30–60 requests per hour per IP.

Approach 2: Authenticated GraphQL (facebook.com/api/graphql/)

Once logged in, Marketplace uses a single GraphQL endpoint at /api/graphql/. Every query has a doc_id (the precompiled query hash), variables (what you're asking for), and a session-bound fb_dtsg CSRF token. Scraping here gives you the full data, including descriptions, photo URLs, seller details, and location to the kilometer.

This is the production path. The effort goes into session management — maintaining a pool of warm Facebook accounts, each behind a stable mobile or ISP proxy in the target country.

Approach 3: Commercial Scraping APIs

Apify, Bright Data, SerpApi, and several others sell Marketplace scraping as a service. Expect $2–$5 per 1,000 listings. If your volume is under ~50k listings/month, this is almost always cheaper than building a session pool.

Proxy Type Matters More Than Anywhere Else

Facebook is the most aggressive anti-scraping target in 2026, full stop. What works:

  • Static residential (ISP) proxies — Best for authenticated scraping. Each account gets one stable ISP IP it keeps across sessions. Facebook builds a trust profile around that pairing over weeks. SpyderProxy Static Residential at $3.90/day is the canonical fit.
  • Mobile LTE proxies — Best for account warming and high-risk logins. CGNAT means thousands of real Facebook users share the IP, so Meta can't ban it. Use LTE proxies at $2/IP when you need to spin up new accounts.
  • Rotating residential — Useful only for unauthenticated listing-URL scraping (Approach 1). Do not use rotating IPs on a logged-in account — Facebook flags session/IP drift within minutes.
  • Datacenter proxies — Effectively blocked. Every major datacenter ASN is on Meta's known-infrastructure list.

Working Python — Unauthenticated Listing Scrape

The lightest-weight path: pull the public listing page and extract the embedded data:

import httpx
import json
import re

PROXY = "http://username:[email protected]:8000"

def scrape_marketplace_listing(listing_id: str) -> dict:
    url = f"https://www.facebook.com/marketplace/item/{listing_id}/"
    headers = {
        "User-Agent": (
            "Mozilla/5.0 (Windows NT 10.0; Win64; x64) "
            "AppleWebKit/537.36 (KHTML, like Gecko) "
            "Chrome/125.0.0.0 Safari/537.36"
        ),
        "Accept-Language": "en-US,en;q=0.9",
    }
    with httpx.Client(proxies=PROXY, headers=headers, timeout=30) as client:
        r = client.get(url, follow_redirects=True)
        r.raise_for_status()
        # Marketplace embeds listing JSON in a script block
        m = re.search(
            r'"marketplace_listing_title":"([^"]+)".*?'
            r'"formatted_amount":"([^"]+)".*?'
            r'"reverse_geocode_detailed":\{[^}]*"city":"([^"]*)"',
            r.text,
            re.DOTALL,
        )
        if not m:
            raise RuntimeError("listing JSON not found — IP may be blocked")
        title, price, city = m.groups()
        return {
            "id": listing_id,
            "title": title.encode().decode("unicode_escape"),
            "price": price,
            "city": city,
        }

print(scrape_marketplace_listing("1234567890123456"))

This is fragile — the regexes break whenever Meta reorders fields. For production, parse the __isScriptWithServerHeaders JSON blob properly. But the pattern is enough for price-check tasks.

Authenticated GraphQL Scrape — Category Listings

For category browsing you need: a logged-in session cookie (c_user, xs, datr), the fb_dtsg CSRF token extracted from the page, and the current doc_id for the MarketplaceSearch query (changes every few weeks).

import httpx

PROXY = "http://username:[email protected]:8000"
COOKIES = {
    "c_user": "YOUR_USER_ID",
    "xs": "YOUR_XS_TOKEN",
    "datr": "YOUR_DATR",
}
FB_DTSG = "EXTRACTED_FROM_PAGE_LOAD"
DOC_ID = "8134567890123456"  # rotate — inspect network tab

def search_marketplace(query: str, city_id: str, radius_km: int = 65):
    variables = {
        "buyLocation": {"latitude": 0, "longitude": 0},
        "count": 24,
        "cursor": None,
        "query": query,
        "marketplaceBrowseContext": "CATEGORY_FEED",
        "marketplaceCategoryID": "",
        "locationID": city_id,
        "radius": radius_km,
    }
    data = {
        "av": COOKIES["c_user"],
        "fb_dtsg": FB_DTSG,
        "fb_api_caller_class": "RelayModern",
        "doc_id": DOC_ID,
        "variables": str(variables).replace("'", '"').replace("None", "null"),
    }
    with httpx.Client(
        proxies=PROXY,
        cookies=COOKIES,
        headers={"User-Agent": "Mozilla/5.0 Chrome/125"},
        timeout=30,
    ) as c:
        r = c.post("https://www.facebook.com/api/graphql/", data=data)
        r.raise_for_status()
        j = r.json()
    listings = (
        j.get("data", {})
         .get("marketplace_search", {})
         .get("feed_units", {})
         .get("edges", [])
    )
    return [
        {
            "id": n["node"]["listing"]["id"],
            "title": n["node"]["listing"]["marketplace_listing_title"],
            "price": n["node"]["listing"]["listing_price"]["formatted_amount"],
            "city": n["node"]["listing"].get("location", {}).get("reverse_geocode", {}).get("city"),
        }
        for n in listings
        if n.get("node", {}).get("listing")
    ]

Geo-Targeting — How Marketplace Filters by Region

Marketplace results are heavily geo-filtered. If you log in from a US IP and search "iPhone 15", you get US listings priced in USD. Same query from a UK IP returns UK listings in GBP. Meta determines this from both the IP geolocation and the account's saved location preference.

To scrape a specific city, pair a residential or ISP proxy in that city with an account whose saved location matches. SpyderProxy supports city-level targeting on Budget Residential and Static Residential pools, which is the critical feature.

Account Warming (For Authenticated Scrapers)

Fresh Facebook accounts get checkpoint-challenged within hours if they immediately start scraping. The rule of thumb we see working in 2026:

  1. Register via a mobile proxy in the target country, phone verify with a local number
  2. First 72 hours: manual-feeling browsing only — scroll news feed, like 5–10 posts, add a profile photo
  3. Days 4–7: light Marketplace browsing (search some common queries, save a few listings)
  4. After day 7: start structured scraping at 200–400 requests/hour
  5. Pin the account to one static ISP proxy in the account's country — never rotate IPs on the session

Cost per warmed, scraping-ready account: ~$5–$15 including phone verification, LTE warmup, and the first week of ISP proxy time.

Common Failure Modes

  • "Something Went Wrong" checkpoint — account has been challenged. Requires a real browser + photo ID or phone re-verification. Often recoverable; sometimes permanent.
  • Empty search results for known-good queries — shadow throttle. Wait 24h or switch accounts.
  • HTTP 400 on GraphQL — expired doc_id or stale fb_dtsg. Re-scrape the page to get fresh values.
  • Radius doesn't apply — account location preference overrides query params. Update the account's saved city.
  • Login requires a checkpoint on every new IP — you're IP-rotating on a warm session. Switch to a pinned ISP proxy.

Legal Notes

Publicly visible Marketplace listings have been treated as scrapable public data in recent US case law. Meta's Terms of Service prohibit automated access, which gives them grounds to ban accounts but is not a criminal matter. Do not scrape buyer/seller PII beyond what is publicly visible, do not circumvent login walls with stolen credentials, and do not aggregate personal data on EU residents without a GDPR lawful basis. When in doubt, ask counsel.

FAQs

Can I scrape Facebook Marketplace without logging in?

Yes, but only individual listing URLs — the public page returns enough HTML for basic title, price, and city. Category feeds and search require a logged-in session.

What proxy type works best for Facebook Marketplace?

Static residential (ISP) proxies for authenticated scraping, because Facebook ties account trust to a stable IP. LTE mobile proxies for account creation and warming. Never use rotating residential IPs on a logged-in session.

How many accounts do I need?

One warmed account per 200–400 requests/hour you want to run. For 10k listings/day, budget 3–5 accounts in a rotation.

Will Facebook ban my personal account if I scrape?

Yes, eventually. Never scrape from a personal account you care about. Use purpose-built, separately-warmed scraping accounts, each pinned to its own ISP proxy.

How do I scrape listings in a specific city?

Two things must match: the proxy IP must geolocate to that city (or nearby), and the scraping account's saved location must be set there. Use a SpyderProxy residential or ISP IP with city-level targeting.

What's the GraphQL doc_id and how do I find it?

It's the hash Facebook uses to identify a precompiled query. Open Marketplace in Chrome DevTools, switch to the Network tab, filter for "graphql", and copy the doc_id from a MarketplaceSearch request. It rotates every few weeks.

Can I scrape seller phone numbers or emails?

No — these are not exposed publicly. Messaging happens through Facebook's own chat. Attempting to exfiltrate contact info likely violates both Meta's ToS and data-protection law in most jurisdictions.

How do I detect when a listing's price has changed?

Re-scrape the listing URL on a schedule (e.g. every 6 hours) and diff the price field. Marketplace preserves the same URL across price edits, so re-scraping is the standard approach.

Bottom Line

Scraping Facebook Marketplace in 2026 requires investment: warmed accounts, ISP proxies, a stable session architecture, and a tolerance for periodic doc_id and DTSG rotation. For low volume, buy a commercial scraping API. For serious volume, build the session pool and pair each account with SpyderProxy Static Residential ($3.90/day) for the account's lifetime. Start new accounts from LTE Mobile proxies during the warmup week.

Related Resources