# Facebook Scraper — Pages, Posts, Comments & Marketplace (`brilliant_gum/facebook-scraper`) Actor

Scrape Facebook pages, posts, comments and Marketplace listings without logging in. Marketplace monitoring flags new listings and price drops between runs.

- **URL**: https://apify.com/brilliant\_gum/facebook-scraper.md
- **Developed by:** [Yuliia Kulakova](https://apify.com/brilliant_gum) (community)
- **Categories:** Social media, E-commerce, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.015 / post

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Scraper — Pages, Posts, Comments & Marketplace

Four Facebook scrapers in one actor: **page profiles, page posts, post comments and Marketplace listings**. No login, no cookies, no browser extension — just a URL and a mode. Marketplace runs can also watch prices and tell you what is new or cheaper since your last run.

![Facebook Scraper — Pages, Posts, Comments & Marketplace](https://api.apify.com/v2/key-value-stores/IuFu0Cw6PpOkNkDV7/records/facebook-scraper-banner)

***

### What you get

- **Four modes, one subscription.** Switch `mode` between `page-details`, `page-posts`, `post-comments` and `marketplace` instead of paying for four separate tools.
- **No login anywhere.** Every mode reads public Facebook data. You never hand over an account, a session cookie or a password, and nothing in your output depends on one.
- **All seven reactions, separately.** Every post and comment returns `like`, `love`, `care`, `haha`, `wow`, `sad` and `angry` as their own counts, plus the total — not one lumped number.
- **Real view counts.** `viewsCount` is the genuine play count on videos and Reels, and stays `null` on photo and text posts instead of a misleading `0`.
- **Comments from any post type.** Text posts, photos, videos and Reels all work — Facebook serves each of them through a different internal query, and all four are handled.
- **Deep pagination.** Posts and comments page far past the first batch, with automatic IP rotation when Facebook throttles.
- **Marketplace price monitoring.** Turn on `monitorMode` and each run compares against the previous one, flags `isNew` listings and price drops, and can POST the changes to your `webhookUrl`.
- **Fails loudly.** If Facebook blocks a run, it ends as FAILED with the reason. It never finishes green with an empty dataset and leaves you guessing.

***

### Modes

| `mode` | What you get | Output `_type` |
|--------|--------------|----------------|
| `page-details` | Profile: name, id, category, followers, likes, bio, pictures, verified owner, contact fields where public | `page` |
| `page-posts` | Posts from a page: text, timestamp, all reactions, comments/shares/views, media, author | `post` |
| `post-comments` | Comments on one post: text, author, reactions, reply count, permalink | `comment` |
| `marketplace` | Listings by keyword or category: price, price drops, photos, location, condition, delivery, seller when shown | `listing` |

***

### Quick start

Posts from a page:

```json
{
  "mode": "page-posts",
  "startUrls": [{ "url": "https://www.facebook.com/nintendo" }],
  "maxItems": 50
}
```

Comments on a post:

```json
{
  "mode": "post-comments",
  "startUrls": [{ "url": "https://www.facebook.com/NintendoAmerica/posts/1489262726562658" }],
  "maxCommentsPerPost": 100
}
```

Marketplace search with filters:

```json
{
  "mode": "marketplace",
  "searchKeywords": "iphone 13",
  "location": "Seattle",
  "priceMax": 400,
  "condition": ["used_good", "used_like_new"],
  "sortBy": "price_asc",
  "maxItems": 50
}
```

Watch a search for new listings and price drops — run it on a schedule:

```json
{
  "mode": "marketplace",
  "searchKeywords": "macbook pro",
  "location": "Chicago",
  "monitorMode": true,
  "webhookUrl": "https://your-endpoint.example.com/hook"
}
```

***

### Input

| Field | Type | Default | Description |
|-------|------|---------|-------------|
| `mode` | enum | `page-posts` | `page-details` / `page-posts` / `post-comments` / `marketplace` |
| `startUrls` | array | `[]` | Page, post or listing URLs. Vanity and tracking-laden URLs are cleaned up automatically |
| `entityIds` | array | `[]` | Numeric Facebook IDs instead of URLs |
| `names` | array | `[]` | Page handles, e.g. `nintendo` |
| `maxItems` | integer | `50` | Cap on dataset rows. `0` = unlimited |
| `onlyPostsNewerThan` | string | — | ISO date or relative (`2026-01-01`, `7 days`) |
| `onlyPostsOlderThan` | string | — | ISO date or relative |
| `maxCommentsPerPost` | integer | `50` | Comment ceiling per post |
| `commentsRanking` | enum | `all` | `all`, or `most_relevant` for Facebook's curated subset |
| `searchKeywords` | string | — | Marketplace keyword query |
| `location` | string | — | Marketplace city, e.g. `Seattle` |
| `category` | string | — | Marketplace category slug, e.g. `vehicles`. Ignored when keywords are set |
| `priceMin` / `priceMax` | integer | — | Marketplace price range |
| `condition` | array | `[]` | `new`, `used_like_new`, `used_good`, `used_fair` |
| `sortBy` | enum | `best_match` | `best_match`, `date`, `price_asc`, `price_desc`, `distance` |
| `daysSinceListed` | integer | — | Only listings posted within N days |
| `includeListingDetails` | boolean | `true` | Open each listing for description, condition, coordinates and category |
| `monitorMode` | boolean | `false` | Flag new listings and price drops against the previous run |
| `webhookUrl` | string | — | POST the new and cheaper listings here |
| `proxyConfiguration` | object | — | Optional. Proxies are included and configured automatically |

***

### Output

Every row carries `_type`, `mode`, `inputUrl` and `scrapedAt`.

#### Post

```json
{
  "_type": "post",
  "postId": "1489262726562658",
  "url": "https://www.facebook.com/reel/2595533354220747/",
  "text": "Three classic games are now available to play...",
  "timestamp": "2026-09-02T01:01:17.000Z",
  "reactions": { "like": 1521, "love": 480, "care": 12, "haha": 74, "wow": 38, "sad": 3, "angry": 1, "total": 2129 },
  "commentsCount": 267,
  "sharesCount": 190,
  "viewsCount": 58357,
  "postType": "reel",
  "media": [{ "type": "thumbnail", "url": "https://scontent.xx.fbcdn.net/...", "thumbnail": "https://scontent.xx.fbcdn.net/..." }],
  "author": { "name": "Nintendo of America", "id": "100064368354094", "url": "https://www.facebook.com/NintendoAmerica", "profilePic": "https://..." },
  "topLevelUrl": "https://www.facebook.com/NintendoAmerica/posts/pfbid02..."
}
```

`postId`, `url`, `text`, `timestamp`, `reactions{like,love,care,haha,wow,sad,angry,total}`, `commentsCount`, `sharesCount`, `viewsCount` (videos and Reels only, else `null`), `feedbackId`, `media[]{type,url,thumbnail}`, `ocrText` (the alt text Facebook generates for images), `link`, `textReferences[]`, `author{}`, `collaborators[]`, `topLevelUrl`, `postType` (`status`/`photo`/`video`/`reel`).

Media entries are deduplicated — Facebook serves the same asset under several size parameters, and you get each one once. A `type` of `photo` is a picture, `thumbnail` is a video's cover image.

#### Comment

```json
{
  "_type": "comment",
  "id": "1058329573485954",
  "text": "Where did their hair go",
  "url": "https://www.facebook.com/reel/2595533354220747/?comment_id=1058329573485954",
  "timestamp": "2026-09-02T01:13:47.000Z",
  "likesCount": 1,
  "reactions": { "like": 1, "love": null, "care": null, "haha": null, "wow": null, "sad": null, "angry": null, "total": 1 },
  "author": { "name": "Jack Treese III", "id": "pfbid0...", "url": "https://www.facebook.com/...", "pic": "https://..." },
  "replyCount": 13,
  "postId": "1489262726562658"
}
```

`id`, `text`, `url` (deep-links to the comment itself), `timestamp`, `likesCount`, `reactions{}`, `feedbackId`, `author{}`, `replyCount`, `depth`, `isReply`, `postUrl`, `postId`.

#### Marketplace listing

```json
{
  "_type": "listing",
  "listingId": "1725486794715446",
  "title": "iPhone 13 Anti Spy Tempered Glass Screen Protector",
  "url": "https://www.facebook.com/marketplace/item/1725486794715446",
  "priceCurrent": 5,
  "priceOriginal": 10,
  "priceDropped": true,
  "currency": "USD",
  "description": "When viewing from a side angle...",
  "images": ["https://scontent.xx.fbcdn.net/..."],
  "location": { "city": "Edmonds", "state": "WA", "coords": { "lat": 47.7987, "lng": -122.3712 } },
  "condition": "New",
  "category": "Mobile phones",
  "categoryId": "1557869527812749",
  "listingDate": "2025-05-25T18:41:56.000Z",
  "availability": "live",
  "deliveryTypes": ["IN_PERSON", "PUBLIC_MEETUP", "SHIPPING_ONSITE"]
}
```

`listingId` (always matches the id in `url`), `title`, `url`, `priceCurrent`, `priceOriginal`, `priceDropped`, `currency`, `description`, `images[]`, `video`, `location{city,state,coords}`, `seller{name,id,profileUrl,rating,ratingCount,sellerType,joinDate}`, `condition`, `category`, `categoryId`, `listingDate`, `availability` (`live`/`sold`/`pending`/`off`), `deliveryTypes[]`, `vehicleAttrs{make,model,year,...}`, `propertyAttrs{beds,baths,sqft}`. With `monitorMode`, rows also carry `isNew`.

#### Page

```json
{
  "_type": "page",
  "name": "Nintendo of America",
  "id": "100064368354094",
  "url": "https://www.facebook.com/NintendoAmerica/",
  "category": ["Video Game"],
  "followers": 5600000,
  "likes": 5632799,
  "talkingAbout": 20364,
  "about": "Welcome to the official Nintendo of America Facebook Page...",
  "profilePic": "https://...",
  "coverPic": "https://...",
  "website": "https://www.nintendo.com/us/",
  "confirmedOwner": true,
  "confirmedOwnerName": "NINTENDO OF AMERICA, INC."
}
```

Plus `email`, `phone`, `address`, `coordinates`, `rating`, `ratingCount`, `hours`, `priceRange`, `messenger`, `verified`, `info[]`, `relatedPages[]` — see the note below on which pages expose these. Outbound links such as `website` are unwrapped from Facebook's redirect, so you get the real destination.

***

### Pricing

You pay per result, by what the result is. Nothing else — no monthly fee, no charge for runs that return nothing.

| Result | Price per 1,000 |
|--------|-----------------|
| Post | **$15** |
| Marketplace listing | **$20** |
| Page profile | **$15** |
| Comment | **$10** |

What that means in practice:

- 500 posts from a competitor's page — **$7.50**
- 1,000 comments under a viral post — **$10**
- 200 Marketplace listings with full details — **$4**
- A daily price monitor on 50 listings, run 4× a day — **$120/month**

Marketplace costs more per row because each listing is opened individually for its description, condition, coordinates, delivery options and price history — a search card alone would tell you far less.

***

### Use cases

- **Competitor tracking** — run `page-posts` on a schedule and watch what a rival publishes, how much engagement each post earns, and which formats get views.
- **Deal hunting and reselling** — `marketplace` with `monitorMode` alerts you the moment a matching listing appears or drops in price. Built for flippers, car and property hunters.
- **Audience research** — pull `post-comments` with full reaction breakdowns to read sentiment on a campaign or announcement.
- **Lead lists** — collect `page-details` for local businesses: category, contact details where public, rating and page owner.
- **Price intelligence** — track the going rate for a product across a metro area, with `priceOriginal` showing what sellers first asked.

***

### Good to know

Everything below is how Facebook itself behaves for public visitors, not a gap in the scraper:

- **Seller identity on Marketplace appears intermittently.** Facebook includes `seller.name`, rating and join date on some responses and omits them on others — the same listing can return a seller on one run and not the next. When it is served, you get it.
- **Vehicle listings** expose `year`, `make` and `model`; `mileage`, `transmission` and `fuel` are not published on public listing pages, so they stay `null` rather than being guessed. Facebook also serves no category name for vehicles, only `categoryId`.
- **Page contact fields** (`email`, `phone`, `rating`, `hours`) are published mainly by local business pages. Large brand pages return `null` — they simply do not list them. `followers`, `category`, `likes`, `about`, `website` and pictures come through for any page that shows them.
- **`verified` is `null` unless Facebook states it.** The blue-badge flag is not published to logged-out visitors for every page, and an unknown badge is reported as `null` rather than guessed as `false`.
- **Video files themselves are not published** to logged-out visitors. For Reels and videos you get the cover image (`type: "thumbnail"`), the real view count, and every engagement metric — but not the .mp4.
- **Comments** are collected at the top level, each with a `replyCount`. Facebook throttles very deep comment pagination at roughly 2–3k per post.
- **Marketplace radius** is not a public filter — Facebook returns the whole metro area for a city regardless of any distance setting, so the actor does not pretend to offer one. Price, condition, sort order and "listed within N days" all work.

***

### FAQ

**Do I need a Facebook account, cookies or a token?**
No. Every mode reads public data, and there is no field to put an account into.

**How do I target a page?**
Any of `startUrls` (full or vanity URLs), `names` (`nintendo`), or `entityIds` (numeric ids). Tracking parameters are stripped automatically.

**Can it watch prices for me?**
Yes — set `monitorMode: true` on a `marketplace` run and schedule it. Each run compares against the previous one, marks `isNew` listings, sets `priceDropped` with the old price in `priceOriginal`, and POSTs the changes to `webhookUrl` if you provide one.

**Does it return all reaction types?**
Yes, all seven separately plus the total, for both posts and comments.

**Comments on a Reel or a video — do those work?**
Yes. Facebook serves those posts through different internal queries than text posts, and all of them are handled.

**Why did my run fail instead of returning an empty dataset?**
Because Facebook blocked it, and you should know that rather than receive a silent empty result. The status message says what happened. Blocks are usually momentary — rerunning generally works.

**Do I need to configure a proxy?**
No. Proxies are included and configured automatically.

***

### Support & feedback

**Something not working?** Open an issue on the Actor's **Issues** tab. Include the run ID and the input you used — that is usually enough to reproduce and fix it. Facebook changes its internals regularly, and issues are how those changes get spotted quickly.

**Missing a field or a filter?** Issues are the right place for that too. Several fields in this actor exist because users asked for them.

**If this actor saved you time, a review on the Store page would mean a lot.** Reviews are what keep a small independent actor visible next to the big ones.

***

### Legal

Scraping Facebook is contrary to Meta's Terms of Service, and this actor collects **public data only**. Personal data such as names and comment text falls under GDPR and CCPA — make sure you have a lawful basis for collecting it and honour deletion and opt-out requests. This actor is not affiliated with or endorsed by Meta.

Maintained by **brilliant\_gum**.

# Actor input Schema

## `mode` (type: `string`):

Which pipeline to run.

## `startUrls` (type: `array`):

Facebook URLs: pages, posts or Marketplace listings. Vanity and tracking-laden URLs are cleaned up automatically.

## `entityIds` (type: `array`):

Numeric Facebook IDs (page or listing) instead of URLs.

## `names` (type: `array`):

Page handles, e.g. 'nintendo'.

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

Hard cap on dataset rows. 0 = unlimited.

## `onlyPostsNewerThan` (type: `string`):

ISO date or relative, e.g. 2026-01-01 or '7 days'. Posts older than this are skipped.

## `onlyPostsOlderThan` (type: `string`):

ISO date or relative. Posts newer than this are skipped.

## `maxCommentsPerPost` (type: `integer`):

Comment ceiling per post. Facebook throttles deep comment pagination at roughly 2-3k.

## `commentsRanking` (type: `string`):

All comments, or only the ones Facebook ranks as most relevant (a smaller, curated subset).

## `searchKeywords` (type: `string`):

Keyword query for Marketplace search, e.g. 'iphone 13'.

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

City name for Marketplace search, e.g. 'Seattle'. Facebook returns the whole metro area — it ignores any distance radius for logged-out requests.

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

Category slug to browse, e.g. 'vehicles' or 'propertyrentals'. Ignored when keywords are set — Facebook cannot combine the two.

## `priceMin` (type: `integer`):

Minimum price filter.

## `priceMax` (type: `integer`):

Maximum price filter.

## `condition` (type: `array`):

Item condition: new, used\_like\_new, used\_good, used\_fair.

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

Sort order for Marketplace results.

## `daysSinceListed` (type: `integer`):

Only listings posted within the last N days.

## `includeListingDetails` (type: `boolean`):

Open every Marketplace listing for description, condition, coordinates and category. Slower, but the search cards alone carry only title, price, city and photo.

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

Compare against the previous run and flag new listings and price drops.

## `webhookUrl` (type: `string`):

POST new and price-dropped listings to this endpoint when monitor mode is on.

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

Optional. Proxies are included and configured automatically — leave this empty.

## Actor input object example

```json
{
  "mode": "page-posts",
  "startUrls": [
    {
      "url": "https://www.facebook.com/nintendo"
    }
  ],
  "entityIds": [],
  "names": [],
  "maxItems": 10,
  "onlyPostsNewerThan": "",
  "onlyPostsOlderThan": "",
  "maxCommentsPerPost": 50,
  "commentsRanking": "all",
  "searchKeywords": "",
  "location": "",
  "category": "",
  "condition": [],
  "sortBy": "best_match",
  "includeListingDetails": true,
  "monitorMode": false,
  "webhookUrl": ""
}
```

# Actor output Schema

## `results` (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 = {
    "mode": "page-posts",
    "startUrls": [
        {
            "url": "https://www.facebook.com/nintendo"
        }
    ],
    "maxItems": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("brilliant_gum/facebook-scraper").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 = {
    "mode": "page-posts",
    "startUrls": [{ "url": "https://www.facebook.com/nintendo" }],
    "maxItems": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("brilliant_gum/facebook-scraper").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 '{
  "mode": "page-posts",
  "startUrls": [
    {
      "url": "https://www.facebook.com/nintendo"
    }
  ],
  "maxItems": 10
}' |
apify call brilliant_gum/facebook-scraper --silent --output-dataset

```

## MCP server setup

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

```

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/OLirDRJaLyqVCYTWN/builds/dUrWkkG6I2Ti10PmN/openapi.json
