# Facebook Marketplace Scraper — New Listings Monitor (`inovaflow/facebook-marketplace-monitor`) Actor

Watch Facebook Marketplace searches by city, radius, price and condition. Every run flags new listings and price drops since the last run, with price, previous price, location, distance, seller, photo and link. Only-new mode for alerts; optional details. No login.

- **URL**: https://apify.com/inovaflow/facebook-marketplace-monitor.md
- **Developed by:** [inovaflow](https://apify.com/inovaflow) (community)
- **Categories:** E-commerce, Social media, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 listings

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

**Watch Facebook Marketplace searches and get the new listings and price drops, in any city, with no login.**

If you have ever hunted for a used road bike, a Herman Miller chair or a PS5 on Marketplace, you know how it goes: the good deals are gone within the hour. You run the same search ten times a day, scroll past everything you have already seen, and still miss the one that was cheap.

We had the same problem, so we built this for ourselves first and are now sharing it. It is a **monitor**. You tell it what to look for, where, and your price range. Run it on a schedule and every run tells you **which listings are new since the last run** and **which ones just got cheaper**, with the old price next to the new one. It remembers what it has already shown you under each monitor name, so "new" really means new.

It reads Marketplace the way the website does for a visitor who is not logged in, so no Facebook account is needed. One more thing we found out along the way: when you sort by newest, Facebook mixes in listings from far outside your radius. The Actor measures how far each listing's town is and drops the ones that are too far away, so "within 20 km" really means within 20 km.

### Who it's for

- **Deal hunters.** *"Tell me when a road bike under $600 is listed within 20 km of me."*
- **Resellers and flippers.** *"Which iPhones around Dallas dropped their price since this morning?"*
- **Collectors.** *"Any new vintage Pokémon cards in Toronto today?"*
- **Shops and sourcing teams.** *"New used office chairs in LA and San Diego, every hour."*
- **AI agents and automations.** One call returns flat rows with `isNew` and `priceDropped` already set, ready for a Slack, Discord or e-mail step.

### What you get per listing

```json
{
  "title": "Giant Defy Advanced SL1 – 60cm Carbon Road Bike",
  "price": 1100, "currency": "USD", "priceText": "$1,100",
  "isNew": false, "priceDropped": true, "previousPrice": 1200, "priceDropAmount": 100, "priceDropPercent": 8.3,
  "originalPrice": null,
  "location": "Brooklyn, NY", "distanceKm": 9.6,
  "listedAt": "2026-09-29T20:01:07.000Z", "firstSeenAt": "2026-09-29T20:30:00.000Z",
  "sellerName": null,
  "imageUrl": "https://scontent…jpg",
  "url": "https://www.facebook.com/marketplace/item/1895495058525960/",
  "deliveryTypes": ["IN_PERSON"], "localPickup": true, "shippingAvailable": false,
  "isSold": false, "isPending": false,
  "search": "road bike · New York, NY", "monitorName": "road-bike-deals"
}
```

- `previousPrice` is the price this monitor saw last time. `originalPrice` is Facebook's own crossed-out "was" price, when the seller lowered it.
- `sellerName` is filled when Facebook shows it to visitors who are not logged in, which is only sometimes.
- **Listing details add-on:** turn it on and each row also gets the full description, the condition ("Used - Good"), the category, the attributes (size, material…), every photo in full size, and the exact spot, so `distanceKm` becomes exact.

The Output tab has three views: **Listings**, **Deals** (only what changed, with the saving) and **Details**.

### Options

- **Monitor name.** Runs that use the same name share one memory. Pick a new name to start fresh.
- **Search queries × locations.** Every query is searched in every location. A location can be a city (`Austin, TX`, `Berlin`, `Toronto, ON`), a ZIP code, a Marketplace city slug (`nyc`) or `lat,lng`.
- **Radius (km).** Listings whose town is further away are dropped and never charged. To keep them anyway (each still gets its `distanceKm`), turn on *Keep listings outside the radius*.
- **Filters.** Min/max price, condition (new, like new, good, fair), category, listed within (24 h / 7 / 30 days), pick-up or shipping, sort order. These are the same filters as on the Marketplace search page.
- **Marketplace search URLs.** You can also paste a search or category page from facebook.com/marketplace. Use this for vehicles, rentals and free stuff, which the category list doesn't cover.
- **Max listings per search.** Default 100. Facebook serves 24 listings per page.
- **Only new listings and price drops.** Off: every listing, each one flagged. On: only what changed since the last run, which is what you want for alerts. The first run of a monitor counts everything as new.

### How to set it up

1. **Name the monitor** and add your queries, locations, radius and price range.
2. **Run it once.** This first run is the baseline, so every listing is new.
3. **Schedule it** (Console → Schedules, for example every 30 minutes) with *Only new listings and price drops* turned on.
4. **Connect a notification** (Slack, e-mail, or a webhook to Discord, Make or Zapier) that fires when the run's dataset isn't empty.

**And that's it.** From then on you only hear about listings you haven't seen and prices that went down.

### Pricing

**$1 per 1,000 listings** ($0.001 each), plus the platform's $0.005 start fee per run. The details add-on is $0.002 per listing on top. Listings outside your radius, duplicates across your searches and, in only-new mode, listings you have already seen are never charged.

> **Tip:** a monitor with only-new turned on costs very little. A quiet run is just the start fee, and a busy one adds a tenth of a cent per new listing or price drop. A run also stops paging early once the newest pages hold nothing new. For alerts, pair only-new with *Listed within: last 24 hours* so you only hear about fresh posts.

### Notes

This Actor reads public Marketplace listings the way a visitor who is not logged in sees them. It doesn't log in, message sellers, or collect anything that isn't publicly shown. Distances are measured to the listing's town centre, or to the exact spot when details are on. Facebook's "newest" order is approximate and its results shift a little between visits. So a monitor always looks a page or two past the first listing it already knows, and an older listing it simply never saw before can show up as new (`listedAt` tells you when it was actually posted). Use it in line with Facebook's terms and your local laws.

Found a bug, or want a filter or an alert channel added? Open an issue on the **Issues** tab.

# Actor input Schema

## `monitorName` (type: `string`):

Any name, e.g. `road-bike-deals`. Runs with the same name share one memory, so `isNew` and `priceDropped` compare against the previous run of this monitor. Use a new name to start fresh.

## `searchQueries` (type: `array`):

What to look for, one per line — the words you would type in Marketplace search: `road bike`, `iphone 15`, `herman miller chair`.

## `locations` (type: `array`):

Where to search, one per line: a city (`Austin, TX`, `Berlin`, `Toronto, ON`), a ZIP code, a Marketplace city slug (the part after /marketplace/ in its URL, like `nyc`), or coordinates `40.71,-74.00`.

## `radiusKm` (type: `integer`):

How far from the location to look. Facebook itself mixes in listings from well outside the radius when sorting by newest; the Actor measures each listing's distance and drops those further away (see the option below). 40 km ≈ 25 miles.

## `minPrice` (type: `integer`):

In the local currency. Leave empty for no minimum.

## `maxPrice` (type: `integer`):

In the local currency. Leave empty for no maximum.

## `conditions` (type: `array`):

Only these conditions. Leave empty for any.

## `category` (type: `string`):

Narrow the search to one Marketplace category. For categories not listed here (vehicles, rentals, free stuff…), paste the category page as a search URL below.

## `daysSinceListed` (type: `string`):

Only listings posted in this window.

## `deliveryMethod` (type: `string`):

`local_pickup` = pick-up / meet-up only, `shipping` = listings the seller ships.

## `sortBy` (type: `string`):

`newest` suits a monitor: fresh listings first, and a monitor run stops early once the latest pages hold nothing new.

## `searchUrls` (type: `array`):

Or paste searches straight from facebook.com/marketplace — a search or category page with the filters you set there. Each URL is monitored as its own search, with its own location and filters.

## `maxListingsPerSearch` (type: `integer`):

How many listings (within the radius) to check per search and run. Facebook serves 24 per page. Also caps what you pay.

## `onlyNew` (type: `boolean`):

On: each run returns only listings this monitor has not shown you before, plus listings whose price went down since the last run — ideal for alerts. Off: every listing, each flagged with `isNew` and `priceDropped`. The first run of a monitor counts everything as new.

## `includeDetails` (type: `boolean`):

Opens each returned listing for its description, condition, category, all photos and exact spot (so the distance is exact). Charged per listing on top of the listing price.

## `keepOutsideRadius` (type: `boolean`):

Off (default): listings whose town is further than the radius are dropped and never charged. On: keep everything Facebook returns, each with its `distanceKm`.

## `maxConcurrency` (type: `integer`):

Searches run at the same time. Lower it if the log shows many retries.

## `proxyConfiguration` (type: `object`):

Residential proxy is required — Facebook answers Marketplace searches only for residential IPs. Traffic is small (a few KB per listing).

## Actor input object example

```json
{
  "monitorName": "road-bike-deals",
  "searchQueries": [
    "road bike",
    "herman miller chair"
  ],
  "locations": [
    "Austin, TX",
    "nyc"
  ],
  "radiusKm": 40,
  "category": "any",
  "daysSinceListed": "any",
  "deliveryMethod": "all",
  "sortBy": "newest",
  "searchUrls": [
    "https://www.facebook.com/marketplace/austin/search/?query=couch&maxPrice=300&sortBy=creation_time_descend"
  ],
  "maxListingsPerSearch": 20,
  "onlyNew": false,
  "includeDetails": false,
  "keepOutsideRadius": false,
  "maxConcurrency": 3,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

## `listings` (type: `string`):

Every listing with price, place, distance, isNew and priceDropped.

## `deals` (type: `string`):

New listings and price drops with the old price and the saving.

## `summary` (type: `string`):

Per search: where it searched, pages read, listings checked, outside the radius, new, price drops and why it stopped.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "monitorName": "road-bike-deals",
    "searchQueries": [
        "road bike"
    ],
    "locations": [
        "New York, NY",
        "Los Angeles, CA"
    ],
    "maxListingsPerSearch": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("inovaflow/facebook-marketplace-monitor").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "monitorName": "road-bike-deals",
    "searchQueries": ["road bike"],
    "locations": [
        "New York, NY",
        "Los Angeles, CA",
    ],
    "maxListingsPerSearch": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("inovaflow/facebook-marketplace-monitor").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "monitorName": "road-bike-deals",
  "searchQueries": [
    "road bike"
  ],
  "locations": [
    "New York, NY",
    "Los Angeles, CA"
  ],
  "maxListingsPerSearch": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call inovaflow/facebook-marketplace-monitor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,inovaflow/facebook-marketplace-monitor"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/L2WUQa2GIKK5F3Idu/builds/aoX0mwhfa4X9OAcjU/openapi.json
