SocialAPIs
Sources
PricingBlogFAQContact
← Back to blog
facebook-marketplacepythonscrapingprice-trackingapi

How to Get Facebook Marketplace Listings with Python (Search, Filter, Track Prices)

Meta has no public Marketplace API and BeautifulSoup scripts break. Search Facebook Marketplace by keyword, location and price with one API call, export listings to CSV, and get alerts for new listings and price drops, in Python.

SocialAPIs Team·October 28, 2026

The reliable way to get Facebook Marketplace listings in Python is to call a Marketplace search API instead of parsing Facebook's pages: send a keyword, a location (latitude and longitude) and optional price filters, and get back JSON with each listing's title, price, location, photo, status and link. Meta has no public Marketplace API, and Marketplace pages are rendered with JavaScript behind login prompts, so requests + BeautifulSoup scripts break constantly. Below: the API call, the real response, a script that exports listings to CSV, and one that alerts you when a new matching listing appears.

Why the BeautifulSoup approach doesn't hold up

Most tutorials show requests.get("https://www.facebook.com/marketplace/...") plus CSS selectors. In practice:

  • The listings aren't in the HTML: Marketplace loads them with JavaScript after the page opens, so the HTML you download has no listing cards.
  • Facebook shows a login wall after a few pages, and changes its class names often, so selectors stop matching.
  • Headless browsers (Playwright, Selenium) get further, but need a logged-in account to stay useful, which is fragile and against Facebook's terms for automation.

An API returns the same public listings as structured data and handles the collection side for you.

What you need

  • A SocialAPIs API key: the free plan has 200 calls a month, no card (sign up).
  • Python 3.9+ and requests (pip install requests).

The API call

GET /facebook/marketplace/search:

bash
1curl -G "https://api.socialapis.io/facebook/marketplace/search" \
2  -H "x-api-token: $SOCIALAPIS_API_KEY" \
3  --data-urlencode "query=hot wheels" \
4  --data-urlencode "filter_location_latitude=40.7142" \
5  --data-urlencode "filter_location_longitude=-74.0064" \
6  --data-urlencode "filter_radius_km=40" \
7  --data-urlencode "filter_price_upper_bound=100"
ParameterWhat it does
querykeyword, e.g. iphone 15
filter_location_latitude, filter_location_longitudesearch center; get them for a city name with /facebook/marketplace/city-coordinates
filter_radius_kmradius around the center, e.g. 40
filter_price_lower_bound, filter_price_upper_boundwhole numbers in the local currency
commerce_search_and_rp_conditionnew, used_like_new, used_good, used_fair
commerce_search_sort_byBEST_MATCH, CREATION_TIME_DESCEND (newest first), PRICE_ASCEND…
posted_todaytrue for today's listings only
category_urla category slug from /facebook/marketplace/categories
end_cursornext page, from page_info.end_cursor

Each call costs 1 credit and returns about 24 listings (pricing). For cars and rentals there are dedicated endpoints with mileage, year, bedroom and bathroom filters: /facebook/marketplace/vehicles and /facebook/marketplace/rentals.

The response

Trimmed to one listing (seller name removed):

json
1{
2  "data": {
3    "page_info": { "end_cursor": "{\"pg\":0,…}", "has_next": true },
4    "items": [
5      {
6        "id": "1647394070433636",
7        "listingUrl": "https://www.facebook.com/marketplace/item/1647394070433636",
8        "marketplace_listing_title": "Toy cars lot (read description) disney pixar",
9        "listing_price": { "formatted_amount": "$20", "amount": "20.00" },
10        "strikethrough_price": { "formatted_amount": "$35", "amount": "35.00" },
11        "location": { "reverse_geocode": { "city": "Paterson", "state": "NJ" } },
12        "is_live": true,
13        "is_pending": false,
14        "is_sold": false,
15        "delivery_types": ["IN_PERSON", "PUBLIC_MEETUP", "DOOR_PICKUP"],
16        "primary_listing_photo": { "photo_image_url": "https://scontent…" },
17        "listing_video": null,
18        "marketplace_listing_seller": { "name": "…", "id": "…" }
19      }
20    ]
21  },
22  "meta": { "creditsCharged": 1, "creditsRemaining": 199 }
23}

The fields you'll use most: id, listingUrl, marketplace_listing_title, listing_price.amount (a string, convert it to a number), strikethrough_price (set when the seller lowered the price, null otherwise), location.reverse_geocode, is_sold / is_pending, and delivery_types (IN_PERSON, SHIPPING_ONSITE, PUBLIC_MEETUP…). For a listing's full description and all photos, call /facebook/marketplace/listing with its id.

Script 1: search and export to CSV

python
1import csv
2import os
3
4import requests
5
6API_KEY = os.environ["SOCIALAPIS_API_KEY"]
7URL = "https://api.socialapis.io/facebook/marketplace/search"
8
9
10def search(query, lat, lng, radius_km=40, max_price=None, pages=2):
11    params = {
12        "query": query,
13        "filter_location_latitude": lat,
14        "filter_location_longitude": lng,
15        "filter_radius_km": radius_km,
16    }
17    if max_price is not None:
18        params["filter_price_upper_bound"] = max_price
19
20    listings = []
21    for _ in range(pages):
22        response = requests.get(URL, headers={"x-api-token": API_KEY}, params=params, timeout=60)
23        response.raise_for_status()
24        data = response.json().get("data", {})
25        listings.extend(data.get("items", []))
26        page_info = data.get("page_info") or {}
27        if not page_info.get("has_next"):
28            break
29        params["end_cursor"] = page_info["end_cursor"]
30    return listings
31
32
33def to_row(item):
34    place = (item.get("location") or {}).get("reverse_geocode") or {}
35    was = item.get("strikethrough_price") or {}
36    return {
37        "id": item["id"],
38        "title": item.get("marketplace_listing_title", ""),
39        "price": float((item.get("listing_price") or {}).get("amount") or 0),
40        "was": float(was["amount"]) if was.get("amount") else "",
41        "city": place.get("city", ""),
42        "state": place.get("state", ""),
43        "sold": item.get("is_sold", False),
44        "shipping": "SHIPPING_ONSITE" in (item.get("delivery_types") or []),
45        "url": item.get("listingUrl", ""),
46    }
47
48
49if __name__ == "__main__":
50    rows = [to_row(i) for i in search("hot wheels", 40.7142, -74.0064, max_price=100)]
51    rows.sort(key=lambda r: r["price"])
52    with open("listings.csv", "w", newline="") as f:
53        writer = csv.DictWriter(f, fieldnames=rows[0].keys() if rows else ["id"])
54        writer.writeheader()
55        writer.writerows(rows)
56    print(f"Saved {len(rows)} listings to listings.csv")

Two pages is about 48 listings for 2 credits. The script keeps only what you need for a price comparison; it doesn't store seller names.

Script 2: alert on new listings and price drops

Run it every 30 minutes; it remembers each listing's last price and prints only new listings and price drops (swap print for a Slack webhook, email or Telegram).

python
1import json
2from pathlib import Path
3
4from marketplace_search import search, to_row
5
6STATE = Path("marketplace_state.json")
7
8
9def main():
10    known = json.loads(STATE.read_text()) if STATE.exists() else {}
11    first_run = not known
12
13    for row in map(to_row, search("hot wheels", 40.7142, -74.0064, max_price=100, pages=1)):
14        if row["sold"]:
15            continue
16        previous = known.get(row["id"])
17        known[row["id"]] = row["price"]
18        if first_run:
19            continue
20        if previous is None:
21            print(f"New: {row['title']} for ${row['price']:.0f} in {row['city']}\n{row['url']}")
22        elif row["price"] < previous:
23            print(f"Price drop: {row['title']} ${previous:.0f} → ${row['price']:.0f}\n{row['url']}")
24
25    STATE.write_text(json.dumps(known))
26
27
28if __name__ == "__main__":
29    main()

Save Script 1 as marketplace_search.py next to it. Add commerce_search_sort_by=CREATION_TIME_DESCEND to the search parameters if you want the newest listings first. Every 30 minutes is about 1,440 calls a month for one search.

No code: n8n, Make, Zapier

The same flow works in any automation tool: a schedule, an HTTP request to /facebook/marketplace/search with the x-api-token header, a split on data.items, a "remove duplicates" step on id, and a Slack, email or Google Sheets step. In n8n that's Schedule Trigger → HTTP Request → Split Out (data.items) → Remove Duplicates (previous executions, {{ $json.id }}) → Slack.

With an AI assistant

The SocialAPIs MCP server gives Claude, ChatGPT or Cursor a facebook_marketplace tool, so you can ask "find used road bikes under $400 within 30 km of Austin and sort them by price" and get the listings back.

Is this allowed?

These are listings anyone can see on Marketplace without logging in. Keep it that way: use public listing data for search, price research and alerts; don't collect sellers' names or profiles unless your use case needs them (in the EU and UK they're personal data under GDPR); and don't contact sellers in bulk or republish their photos as your own.

Common questions

How do I search a different city? Call /facebook/marketplace/city-coordinates?city=Austin for its latitude and longitude, or use any coordinates you already have, plus filter_radius_km.

Can I get the listing description? Yes, with /facebook/marketplace/listing?listing_id=<id> (1 credit per listing). The search result only carries the title.

Prices are strings? Yes: listing_price.amount is "20.00". Convert with float(); formatted_amount has the currency symbol for display.

Is there a cars-only search? /facebook/marketplace/vehicles filters by price, year, mileage and individual sellers; /facebook/marketplace/rentals by bedrooms, bathrooms and price.

Get a free API key and run Script 1 on your own search: sign up, 200 calls a month free.

Try the SocialAPIs platform

Build on Facebook + Instagram data today (TikTok, X, LinkedIn, and YouTube on the roadmap). 200 free calls / month, no card.

Create a free account

More from the blog

Facebook Ads Library API Without App Review: Search Competitors' Ads and Track New Ones

Meta's Ad Library API covers political and EU ads and needs identity confirmation. Here's how to search any ad…

How to Monitor a Facebook Group's New Posts Automatically (After the Groups API Shutdown)

Meta removed the Groups API on April 22, 2024. Here's how to watch a public Facebook group for new posts and s…

SocialAPIs

Public Facebook & Instagram data API, built for developers and AI agents.

Now in MCP Registry

Product

  • Get Started
  • API Reference
  • Pricing
  • Documentation
  • Blog
  • Compare vs others
  • Integrations
  • Social Search
  • Social Tracker

Free Tools

  • Facebook Follower Count
  • Network Inspector
  • Visual Selector
  • JSON Selector
  • cURL Converter
  • Leads Generator
  • Hashtag Generator
  • JSON Formatter
  • URL Encoder

Libraries & SDKs

  • Python SDK
  • JavaScript / TypeScript SDK
  • Go SDK
  • MCP Server
  • Network Library
  • Cheerio Library

Resources

  • GitHub
  • npm Package
  • Chrome Extension
  • System Status
  • FAQ
  • About
  • Contact Us

Legal

  • Privacy Policy
  • Terms of Service

© 2026 SocialAPIs. All rights reserved.