# Facebook Marketplace Deal Alert (`mrdoe/facebook-marketplace-deal-alert`) Actor

Monitor Facebook Marketplace for new listings and price drops. Track keywords or categories by location, radius, and price, and get only the deals that are new or cheaper.

- **URL**: https://apify.com/mrdoe/facebook-marketplace-deal-alert.md
- **Developed by:** [MrDoe](https://apify.com/mrdoe) (community)
- **Categories:**
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.00 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

![Facebook Marketplace Deal & Price-Drop Alert — new listings and price drops from a saved search](./assets/hero.png)

### What does Facebook Marketplace Deal & Price-Drop Alert do?

Facebook Marketplace Deal & Price-Drop Alert monitors one saved Facebook Marketplace search — a keyword or category, a location and radius, and an optional price range — and returns only the listings that are **new** or that **dropped in price** since the previous run. It runs fully logged out, with no Facebook account or cookies, and writes one clean row per listing with title, price, currency, price-drop amount, location, category, condition, seller type, posted date, listing URL, image URLs, and description. Turn on monitor mode, put it on an hourly or daily schedule, and each run's dataset is a ready-to-act list of what just appeared or got cheaper in your local market.

### Why use Facebook Marketplace Deal & Price-Drop Alert?

- **Only what changed.** In monitor mode the Actor compares the search against what earlier runs already saw and returns just the new and price-dropped listings — not a full re-scrape every time.
- **Price-drop detection.** Every listing's lowest seen price is remembered, so a later markdown is reported with an exact `priceDropAmount`.
- **Schedule-friendly.** Designed for recurring runs: the monitoring memory persists between runs, so a scheduled task stays fast and quiet until something actually happens.
- **Clean, structured output.** 12 normalised fields per listing, ready for JSON, CSV, Excel, XML, a webhook, or Google Sheets.
- **No login, no account.** Works entirely against the public, logged-out Marketplace view.
- **Deal sourcing.** Resellers, flippers, and bargain hunters get a continuous feed of fresh inventory and reduced prices for their exact search.

### What makes this different

Most Marketplace scrapers re-download the entire result set on every run and hand you a big list you have to diff yourself. This Actor keeps a per-search memory of every listing it has seen and the lowest price recorded for each, so a scheduled run returns a short, meaningful batch: listings posted since last time, plus listings whose price fell, each with the drop amount already calculated. That turns a one-off export into a recurring monitoring product you can wire straight into alerts or a sourcing workflow.

If a listing's price history can't be established yet (for example on the very first run of a new saved search), `priceDropAmount` is `null` rather than a guessed value — but Facebook's own struck-through "original price" is used when it is shown, so genuine markdowns are still caught on first sighting.

### How it works

![How the Facebook Marketplace Deal & Price-Drop Alert works: saved search in, collection engine, only new and price-dropped listings out](./assets/how-it-works.png)

1. **Describe one saved search** — a keyword (e.g. `bicycle`) or a category slug, a `location` and `radius`, and optionally `minPrice` / `maxPrice`.
2. **The Actor checks it** — it reads the current public listings for that search in two orderings (newest first, and lowest price first) for wider coverage, then compares them to what previous runs recorded.
3. **You get back only the changes** — one row per new listing and per price drop, with the drop amount already worked out. Nothing that stayed the same is returned again.

On the first run, leave **monitor mode** off: the Actor returns every current match and stores today's prices as the baseline. On every run after that, turn monitor mode on.

### What data can you extract?

| Field             | Description                                                                                                                                                                            |
| ----------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `title`           | Listing title.                                                                                                                                                                         |
| `price`           | Current price as shown, formatted (e.g. `"$600"`).                                                                                                                                     |
| `currency`        | ISO currency code (e.g. `"USD"`). Available when full listing details are included.                                                                                                    |
| `priceDropAmount` | How much the price fell, as a number, versus the lowest price earlier runs recorded (or Facebook's own struck-through original price on first sighting). `null` when there is no drop. |
| `location`        | Listing location — city and region, or the listing's own location text.                                                                                                                |
| `category`        | Marketplace category name (e.g. `"Home Goods"`). Available when full listing details are included.                                                                                     |
| `condition`       | Seller-stated condition (e.g. `"Used - like new"`). Available when full listing details are included.                                                                                  |
| `sellerType`      | `"dealership"` for Marketplace shop / dealer listings; `null` for private sellers, which are the majority (Facebook does not reveal seller identity to logged-out visitors).           |
| `postedDate`      | When the listing was posted, ISO 8601.                                                                                                                                                 |
| `itemUrl`         | Canonical listing URL.                                                                                                                                                                 |
| `imageUrls`       | Array of listing photo URLs (full gallery when details are included, otherwise the cover photo).                                                                                       |
| `description`     | Full listing description. Available when full listing details are included.                                                                                                            |

Any field Facebook does not show a logged-out visitor is returned as `null` — never guessed.

### How to use Facebook Marketplace Deal & Price-Drop Alert

![Filled input example: keyword bicycle, location austin, radius 65 km, max price 400, residential proxy](./assets/input.png)

1. Open the Actor and click **Start** to try it with the built-in example (`bicycle` near `austin`, 65 km).
2. Set your own **Search keyword** or **Category slug**, the **Location** slug (from a Marketplace URL, e.g. `los-angeles`), and the **Search radius**.
3. Optionally add **Minimum price** / **Maximum price** and lower **Max items** for a quick test.
4. Run once with **Monitor mode** off to build the baseline, then open the **Dataset** tab to see every current match.
5. Turn **Monitor mode** on, save the input as a **Task**, and put it on a **Schedule** (hourly or daily). Each scheduled run's dataset now contains only new listings and price drops.

### Input parameters

| Parameter            | Type    | Required                      | Default               | Description                                                                                          |
| -------------------- | ------- | ----------------------------- | --------------------- | ---------------------------------------------------------------------------------------------------- |
| `searchQuery`        | string  | one of searchQuery / category | `bicycle`             | Keyword to search Marketplace for.                                                                   |
| `category`           | string  | one of searchQuery / category | —                     | Category slug from a Marketplace category URL (e.g. `bikes`, `furniture`, `vehicles`).               |
| `location`           | string  | yes                           | `austin`              | Marketplace location slug, taken from a Marketplace URL (`facebook.com/marketplace/<location>/`).    |
| `radius`             | integer | yes                           | `65`                  | Search radius in kilometres around the location.                                                     |
| `minPrice`           | integer | no                            | —                     | Only return listings at or above this price.                                                         |
| `maxPrice`           | integer | no                            | —                     | Only return listings at or below this price.                                                         |
| `maxItems`           | integer | no                            | `10`                  | Stop after this many listings are written to the dataset.                                            |
| `monitorMode`        | boolean | no                            | `false`               | When `true`, return only listings that are new or that dropped in price since the previous run.      |
| `fetchDetails`       | boolean | no                            | `true`                | Also open each listing for its description, currency, condition, category, and full photo set.       |
| `proxyConfiguration` | object  | yes                           | Apify residential, US | A residential proxy is required — Facebook Marketplace does not serve results to datacenter traffic. |

### Output data

![Dataset output: one row per new or price-dropped listing, with a price-drop batch on the next run](./assets/output.png)

One row per listing. In monitor mode a row means the listing is either new or cheaper than before; `priceDropAmount` tells you which.

![Every field labelled on one real price-drop record](./assets/fields.png)

A real example row (a listing first recorded at `$700`, now `$600`):

```json
{
    "title": "Gray Sectional Set need gone asap moving",
    "price": "$600",
    "currency": "USD",
    "priceDropAmount": 100,
    "location": "Austin, TX",
    "category": "Home Goods",
    "condition": "Used - like new",
    "sellerType": null,
    "postedDate": "2026-09-03T05:59:38.000Z",
    "itemUrl": "https://www.facebook.com/marketplace/item/1834261091575337/",
    "imageUrls": [
        "https://scontent.xx.fbcdn.net/v/t39.84726-6/792046899_1732232338030109_7220855386382271255_n.jpg",
        "https://scontent.xx.fbcdn.net/v/t45.5328-4/794034202_1699585828440696_7199487737593007747_n.jpg"
    ],
    "description": "Gray Sectional Sofa + Coffee Table + Side Table/Ottoman – $700 OBO. Moving and selling my complete living room set..."
}
```

A newly posted listing looks the same, with `"priceDropAmount": null`.

### Usage examples

**Watch a keyword in one city**

```json
{
    "searchQuery": "herman miller aeron",
    "location": "seattle",
    "radius": 40,
    "maxPrice": 600,
    "monitorMode": true,
    "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }
}
```

**Watch a whole category for price drops**

```json
{
    "category": "furniture",
    "location": "austin",
    "radius": 65,
    "minPrice": 100,
    "monitorMode": true,
    "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }
}
```

**First full snapshot before scheduling**

```json
{
    "searchQuery": "mountain bike",
    "location": "denver",
    "radius": 80,
    "maxItems": 60,
    "monitorMode": false,
    "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"], "apifyProxyCountry": "US" }
}
```

### Tips for best results

- Run once with `monitorMode: false` (a higher `maxItems`, e.g. 60) to seed the baseline, then switch it on for every scheduled run.
- Keep the same `searchQuery`, `category`, `location`, `radius` and price band between runs — the monitoring memory is tied to that exact combination. Change any of them and it starts a fresh baseline.
- A tighter search (specific keyword, sensible radius, a `maxPrice`) gives a cleaner, more relevant feed and fewer loosely-matched results.
- Schedule frequency to how fast your market moves — hourly for hot categories, daily for slower ones.
- Leave `fetchDetails` on if you want description, condition, category and the full photo gallery; turn it off for a faster, lighter run.

### Known limitations

- **Logged-out view only.** Fields Facebook hides from anonymous visitors — seller name and profile, exact seller type for private sellers, listing videos — are returned as `null`. `sellerType` is only populated for shop / dealer listings.
- **Bounded result window.** The public Marketplace view returns roughly 24 listings per ordering with no deep pagination. The Actor reads two orderings to widen coverage, but a very large market is not fully enumerable in one run; monitor mode is designed around this by tracking the listings it does see over time.
- **Occasional re-notification.** Because the result window rotates slightly between runs, a listing that dropped out of the window and came back can be reported as new again.
- **Region support.** Prices, currency and locations are returned as Facebook presents them for the chosen location; the built-in defaults and proxy target the United States.
- **Category slugs.** `category` must be the slug used in Facebook's own Marketplace URLs; an unknown slug returns no results.
- **First run.** With no price history yet, `priceDropAmount` is `null` unless Facebook itself shows a struck-through original price.

### Integrations

Connect this Actor to the rest of your stack with Apify's built-in integrations: **Webhooks** (fire on each run so new listings and drops push straight into Slack, email, or your own endpoint), **Google Sheets**, **Make**, **Zapier**, **Airbyte**, the **Apify API**, and **scheduled tasks** for hands-off recurring runs.

### Export formats

Download the dataset as **JSON**, **CSV**, **Excel**, or **XML** from the Dataset tab, or pull it from the Apify API.

### Frequently asked questions

#### Do I need a Facebook account or login?

No. The Actor only reads Facebook Marketplace's public, logged-out view. No account, password, or cookies are used or required.

#### How does monitor mode know what it saw last time?

It keeps a small memory for each saved search — the listings seen and the lowest price recorded for each — and reuses it on the next run. The memory persists between runs, including scheduled ones, so you don't have to diff anything yourself.

#### Why is `priceDropAmount` null on some rows?

That row is a new listing, not a price drop — or it's the first run for that search and there's no earlier price to compare against.

#### Can I monitor a category instead of a keyword?

Yes. Set `category` to the slug from a Marketplace category URL (e.g. `furniture`). You can combine it with `searchQuery` to narrow further.

#### How many listings will one run return?

As many as match, up to `maxItems` (default 10). Facebook's public view caps a single search at roughly 24 listings per ordering; the Actor reads two orderings for wider coverage.

#### Can I schedule it?

Yes — this is the intended use. Save your input as a Task and add a Schedule (hourly or daily). Each run returns only the new and price-dropped listings since the run before.

#### Does it download the listing photos?

No. It collects photo URLs in the `imageUrls` field. You can fetch the images yourself from those URLs.

#### How fresh is the data?

Each run reads Facebook Marketplace live at the moment it runs, so results reflect what's on the site right then.

#### Am I charged for failed results?

No. You're only charged for listings actually written to the dataset. Turning **Include full listing details** off returns fewer fields per listing for a lighter run; turning it on adds the description, condition, category and full photo set.

#### Why do I sometimes see a listing reported as new twice?

Facebook's public result window rotates a little between runs, so a listing can briefly drop out and reappear. Tightening the search reduces this.

### Support

Found a bug or want a feature? Open an issue on the **Issues** tab of this Actor's page. Include your input and the run ID.

### Legal and responsible use

You are responsible for how you use this Actor and the data it returns, including compliance with Facebook's Terms of Service, applicable law, and data-protection rules (such as GDPR or CCPA) for any personal data contained in listings or descriptions. This Actor is not affiliated with or endorsed by Facebook or Meta. It accesses only data shown publicly to logged-out visitors.

# Actor input Schema

## `searchQuery` (type: `string`):

What to look for on Facebook Marketplace, e.g. "bicycle", "herman miller chair", "iphone 15". Provide this or a Category (or both).

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

Restrict the search to one Marketplace category, using the slug from the category page URL (facebook.com/marketplace/<location>/<slug>), e.g. "bikes", "furniture", "vehicles". Leave blank to search all categories.

## `location` (type: `string`):

The Facebook Marketplace location slug to search around, taken from the Marketplace URL (facebook.com/marketplace/<location>/), e.g. "austin", "los-angeles", "nyc".

## `radius` (type: `integer`):

How far around the location to search, in kilometres. Facebook applies this approximately around the location's centre.

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

Only return listings at or above this price.

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

Only return listings at or below this price.

## `maxItems` (type: `integer`):

Stop once this many listings have been written to the dataset. Keep it low for a quick check; raise it for a first full snapshot of a saved search.

## `monitorMode` (type: `boolean`):

When on, the run compares the search against what previous runs already saw and returns only listings that are new or that dropped in price. When off, every matching listing is returned and the current prices are recorded as the baseline for the next run. Turn this on for scheduled runs.

## `fetchDetails` (type: `boolean`):

Also open each listing for its full description, exact currency, condition, category, and complete photo set. Turn off for a faster, lighter run with only the fields shown on the results page.

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

A residential proxy is required - Facebook Marketplace does not serve results to datacenter traffic. The default uses Apify's residential proxy in the United States.

## Actor input object example

```json
{
  "searchQuery": "bicycle",
  "location": "austin",
  "radius": 65,
  "maxItems": 10,
  "monitorMode": false,
  "fetchDetails": true,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}
```

# Actor output Schema

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

No description

# 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 = {
    "searchQuery": "bicycle",
    "location": "austin",
    "radius": 65,
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "US"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("mrdoe/facebook-marketplace-deal-alert").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 = {
    "searchQuery": "bicycle",
    "location": "austin",
    "radius": 65,
    "maxItems": 10,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "US",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("mrdoe/facebook-marketplace-deal-alert").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 '{
  "searchQuery": "bicycle",
  "location": "austin",
  "radius": 65,
  "maxItems": 10,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "US"
  }
}' |
apify call mrdoe/facebook-marketplace-deal-alert --silent --output-dataset

```

## MCP server setup

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

```

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/ugm73IN4981umG0cm/builds/AoN6gLLmwaiIHabN6/openapi.json
