# Facebook Pages Scraper — Public Page Details & Posts (`thirdwatch/facebook-pages-scraper`) Actor

Extract public Facebook Page data — About details, follower counts, contact info, posts and comment threads — via Facebook's own payloads, no login or cookies. Clean JSON for brand research, monitoring and lead gen.

- **URL**: https://apify.com/thirdwatch/facebook-pages-scraper.md
- **Developed by:** [Thirdwatch](https://apify.com/thirdwatch) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.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?

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

## Facebook Scraper — Page Posts, Group Posts, Comments & Page Details

### What you get

Scrape public Facebook data over plain HTTP: **posts from a Page**, **posts from a public Group**, **comments and reply threads on a post**, **public Page details**, and **keyword search** over the public web index.

No Facebook account, no cookies, no `c_user`/`xs` session, no cookie pool and no browser. Every request is the request an anonymous visitor's browser makes, and the Actor reads the same public payload Facebook renders for that visitor.

### Modes

| Mode | Input | Returns |
|---|---|---|
| `page_posts` | `pageUrls` | Posts from a public Page or profile timeline |
| `group_posts` | `groupUrls` | Posts from a public Group discussion feed |
| `post_comments` | `postUrls` | Comments and replies on a public post |
| `page_details` | `pageUrls` | Public About block: category, followers, contact info |
| `search` | `query` | Public Facebook URLs matching a keyword |

#### `page_posts` — posts by Page URL or username

Accepts a full URL (`https://www.facebook.com/nasa`), a bare username (`nasa`), a `/posts/` URL, or a `profile.php?id=...` URL.

```json
{
  "mode": "page_posts",
  "pageUrls": ["nasa", "https://www.facebook.com/BBCNews"],
  "maxResults": 100
}
```

#### `group_posts` — posts by public group URL

```json
{
  "mode": "group_posts",
  "groupUrls": ["https://www.facebook.com/groups/1443890352589739/"],
  "maxResults": 100
}
```

Private, closed and members-only groups are **not** readable without a login. The Actor reports them as a failure rather than returning an empty result set.

#### Post fields (`page_posts`, `group_posts`)

| Field | Description |
|---|---|
| `post_id`, `post_url`, `story_id` | Identifiers and the public permalink |
| `text` | Full post text |
| `created_at`, `timestamp` | ISO 8601 UTC and raw Unix seconds |
| `author_name`, `author_id`, `author_url` | Poster identity |
| `reactions_count`, `reactions_breakdown` | Total plus per-type counts (Like, Love, Care, Haha, Wow, Sad, Angry) |
| `comments_count`, `shares_count`, `video_views` | Engagement |
| `media_type`, `image_urls`, `link_url` | Attached media and the unwrapped outbound link |
| `source_url`, `source_type`, `source_name` | The Page or Group the post came from |

#### `post_comments` — comments and replies by post URL

Accepts a Page post (`/posts/...`, including the `pfbid...` form), a **public group post**
(`/groups/<group>/posts/<id>/`), `/photo/?fbid=...`, `/videos/...` and `permalink.php` URLs.

Reels (`/reel/...`) are **not** supported: Facebook renders no comment payload at all for a
logged-out reel viewer. A reel URL fails the run with that reason rather than returning zero
comments.

```json
{
  "mode": "post_comments",
  "postUrls": ["https://www.facebook.com/NASA/posts/1619357056226331"],
  "maxCommentsPerPost": 100,
  "includeReplies": true,
  "maxRepliesPerComment": 10
}
```

`maxCommentsPerPost` caps **top-level** comments; replies are returned in addition and capped
separately by `maxRepliesPerComment`.

Facebook serves anonymous visitors only part of a busy thread. A post whose counter reads 87
comments typically streams around 30 of them before the public cursor runs out; the run ends
successfully at that point, because the source genuinely stopped serving, and the log says how
many the post claims to have.

#### Comment fields

| Field | Description |
|---|---|
| `comment_id`, `comment_url` | Identifier and direct `?comment_id=` link |
| `post_id`, `post_url` | The post the comment belongs to |
| `text` | Comment body |
| `created_at`, `timestamp` | ISO 8601 UTC and raw Unix seconds |
| `author_name`, `author_id`, `author_url` | Commenter identity |
| `depth`, `is_reply`, `parent_comment_id` | Thread position — join replies to their parent |
| `replies_count` | Replies under this comment |
| `reactions_count`, `reactions_breakdown` | Reaction total and per-type counts |
| `attachment_urls` | Images attached to the comment |

Rebuild a thread by grouping on `parent_comment_id`: rows with `is_reply: false` are the roots, rows with `is_reply: true` hang off the root whose `comment_id` matches their `parent_comment_id`.

#### `page_details` — public About info

```json
{"mode": "page_details", "pageUrls": ["nasa", "bbcnews"]}
```

Returns `page_id`, `name`, `username`, `url`, `intro`, `categories`, `followers_text`, `likes_text`, `talking_about_text`, `websites`, `emails`, `phones`, `addresses`, `other_fields`, `profile_picture_url`, `cover_photo_url`.

#### `search` — keyword search over the public index

```json
{
  "mode": "search",
  "query": "artificial intelligence",
  "search_type": "posts",
  "max_posts": 25,
  "location": "United States"
}
```

`search_type` is `posts`, `pages`, `places` or `global`. Optional `location`, `recent_posts`,
`start_date`, `end_date` and `queries` (up to 19 extra terms) narrow the search. This is public
web-index search, not Facebook's personalized logged-in search: coverage and ranking differ from
facebook.com, and de-indexed or very new content may be missing. Facebook's own search routes
require a logged-in account, so no logged-out equivalent is pretended here.

`places` pairs well with `page_details`: search for `dentist` in `Austin, Texas`, then feed the
returned page URLs straight into a `page_details` run to get each business's phone, address,
website and opening hours.

### Use cases

- **Brand and competitor monitoring** — track a competitor's Page posts and the engagement each one earns.
- **Community and audience research** — pull discussion from public Groups in your niche.
- **Comment mining and sentiment analysis** — full comment threads with author, timestamp, reactions and reply structure, ready for an LLM or a sentiment model.
- **Lead generation** — `page_details` returns the public website, email, phone and address a business chose to publish.
- **Content and creative research** — see which post formats and topics earn reactions in a category.
- **Crisis and reputation watch** — re-run a post's comments on a schedule and diff the result.

### Example post record

```json
{
  "record_type": "post",
  "post_id": "1620874212741282",
  "post_url": "https://www.facebook.com/reel/28631238109803230/",
  "text": "AvGeeks, assemble!\n\nMAX POWER, America's newest aerospace expo...",
  "created_at": "2026-09-04T15:07:02+00:00",
  "timestamp": 1788534422,
  "author_name": "NASA - National Aeronautics and Space Administration",
  "author_id": "100044561550831",
  "author_url": "https://www.facebook.com/NASA",
  "reactions_count": 871,
  "reactions_breakdown": [{"type": "Like", "count": 750}, {"type": "Love", "count": 101}],
  "comments_count": 71,
  "shares_count": 82,
  "video_views": 20785,
  "media_type": "video",
  "image_urls": ["https://scontent.xx.fbcdn.net/v/t15.5256-10/796096241_..."],
  "source_type": "page",
  "source_name": "NASA - National Aeronautics and Space Administration",
  "mode": "page_posts",
  "scraped_at": "2026-09-07T18:31:00+00:00"
}
```

### Example comment record

```json
{
  "record_type": "comment",
  "comment_id": "1064578393220354",
  "comment_url": "https://www.facebook.com/NASA/posts/pfbid02UW...?comment_id=1064578393220354",
  "post_id": "1619357056226331",
  "text": "Rayleigh scattering filtering out blue light explains that red moon colour.",
  "created_at": "2026-09-03T00:51:39+00:00",
  "author_name": "Tushar Arora",
  "author_id": "61583456871751",
  "author_url": "https://www.facebook.com/profile.php?id=61583456871751",
  "depth": 0,
  "is_reply": false,
  "parent_comment_id": "",
  "replies_count": 4,
  "reactions_count": 3,
  "reactions_breakdown": [{"type": "Like", "count": 3}],
  "mode": "post_comments"
}
```

### Proxy

Leave `proxyConfiguration` empty to use the tested defaults. Facebook's verdict is per exit IP, so the Actor pins each mode to the pool that works:

| Mode | Default pool | Why |
|---|---|---|
| `page_posts` | Residential | Facebook rate-limits the timeline pagination query on datacenter IPs |
| `group_posts` | Residential | Public group pages return a login shell to datacenter and Unblocker exits |
| `post_comments` | Shared pool | Comment payloads are served to every exit type |
| `page_details` | Shared pool | About pages are served to every exit type |
| `search` | Google SERP | Required by the public index |

### Measured throughput and cost

One verification run per mode on Apify, September 2026, 1024 MB, defaults for everything else:

| Mode | Sources | Records | Runtime | Compute units | Platform cost | Cost per record |
|---|---|---|---|---|---|---|
| `page_posts` | 2 Pages | 40 | 67 s | 0.019 | $0.0362 | $0.00091 |
| `group_posts` | 2 Groups | 30 | 32 s | 0.009 | $0.0374 | $0.00125 |
| `post_comments` | 2 posts | 38 | 23 s | 0.006 | $0.0022 | $0.00006 |
| `page_details` | 4 Pages | 4 | 35 s | 0.010 | $0.0032 | $0.00081 |
| `search` | 1 query | 15 | 30 s | 0.008 | $0.0102 | $0.00068 |

Residential proxy transfer is 83-92% of the cost of the two feed modes; the comment and About
modes need no residential exit and are an order of magnitude cheaper per record.

### Honest failures

A login wall is a **failure**, never an empty success. If Facebook serves its logged-out shell instead of the public payload, the Actor rotates the exit IP and retries; if no source is readable the run fails with the reason. A run that ends with rows at zero means the source genuinely had no public items — not that the Actor was blocked. The same rule applies to search: if the index returns results the parser cannot read, the run fails rather than reporting zero matches.

### Limitations

- Only content Facebook shows to logged-out visitors is available. Private profiles, closed or members-only groups, friends-only posts, and login-gated content are out of reach by design and are reported as failures rather than silently skipped.
- **As of September 2026, `post_comments` is degraded**: Facebook now serves its logged-out shell for comment surfaces on most posts, so comment requests increasingly fail with a login-wall error instead of returning comments. `page_posts`, `group_posts`, `page_details` and `search` all still return real data. Comment-mode runs that reach no source fail honestly rather than billing empty results.
- `mbasic.facebook.com` is dead — Meta redirects it to the login wall for every exit type — so it is not used.
- Keyword `search` runs against DuckDuckGo's public HTML index rather than Google — Google stopped embedding real destination URLs in its result markup, which made index results unreadable. Result coverage and recency differ slightly from Google's index.
- Anonymous feed pagination is capped by Facebook, and the two feeds differ sharply. A Page
  timeline renders **one** post to a logged-out visitor and then yields roughly three per
  pagination request, so 40 posts is about 14 requests. A public Group renders around 19 up front
  and 3-9 per request after that. Very deep back-catalogues take proportionally longer.
- Facebook refuses the Page timeline's *root* feed query to every logged-out caller (`Rate limit
  exceeded`, code 1675004) on every exit type and at every page size. The Actor therefore reads
  the rendered page and continues with the refetch query, which is served normally. Nothing is
  lost, but it is why the first page of a Page timeline is a single post.
- Reaction breakdowns cover the reaction types Facebook surfaces in the public bling bar, which is
  the top few, not always all seven.
- Group posters appear as rotating opaque `pfbid...` ids rather than numeric ones; that is
  Facebook's own anonymisation, and the id is not stable between runs.

The Actor accesses only public URLs. Use personal data lawfully and in accordance with Facebook's terms and applicable privacy laws.

### Output fields

- One row per result with stable keys.

### Input parameters

| Parameter | Required | Description |
|---|---:|---|
| `mode` | Yes | Page posts, public group posts, post comments and replies, public page details, or keyword search over the public web index. |
| `pageUrls` | No | Used by Page posts and Page details. Accepts https://www.facebook.com/nasa, a bare username like nasa, or a profile.php?id=... URL. |
| `groupUrls` | No | Used by Group posts. Example: https://www.facebook.com/groups/pygame/. Private, closed and members-only groups are not readable without a login; they are reported as a failure rather than returned empty. |
| `postUrls` | No | Used by Post comments. Accepts Page post URLs (/posts/..., including the pfbid form), public group post URLs (/groups/<group>/posts/<id>/), /photo/?fbid=..., /videos/... and permalink.php URLs. Reels (/reel/...) are not supported - Facebook renders no comment payload for a logged-out reel viewer. |
| `maxResults` | No | Maximum records for Page posts, Group posts and Page details, shared across all supplied sources. |
| `maxCommentsPerPost` | No | Used by Post comments. Caps TOP-LEVEL comments per post; replies are returned in addition, capped separately by the replies limit below. Facebook serves anonymous visitors only part of a busy thread - roughly 30 comments on a post whose counter reads 87 - so a run can finish below this cap because the source stopped serving. |
| `includeReplies` | No | Fetch the replies under each top-level comment. Replies carry parent_comment_id so threads can be rebuilt. |
| `maxRepliesPerComment` | No | Cap on replies fetched under each top-level comment. |
| `proxyConfiguration` | No | Leave as-is for the tested defaults: residential exits for Page posts and Group posts, the shared pool for Post comments and Page details. Facebook returns a login shell for public Group pages to datacenter IPs, and rate-limits Page timeline pagination there. Choosing a group, a country or your own proxy URLs overrides the default. |
| `query` | No | Search mode only. Keyword or phrase to find in public Facebook results. |
| `search_type` | No | Search mode only. Search public posts, pages/profiles, places, or all indexed Facebook result types. |
| `max_posts` | No | Search mode only. Maximum number of unique results across all queries. The minimum of 5 protects the Actor's per-run economics; public search-index depth varies by keyword. |
| `recent_posts` | No | Search mode only. For post searches, prefer results indexed during the past week. Explicit dates take precedence. |
| `location` | No | Search mode only. Optional city, region or country added to the search, for example Austin, Texas or London, UK. |
| `start_date` | No | Search mode only. Optional earliest index date in YYYY-MM-DD format. |
| `end_date` | No | Search mode only. Optional latest index date in YYYY-MM-DD format. |
| `queries` | No | Search mode only. Optional additional search terms processed in the same run. |

### Related Actors

- [Douyin Scraper](https://apify.com/thirdwatch/douyin-scraper) — Thirdwatch
- [Facebook Ad Library Scraper - Active Ads & Creatives](https://apify.com/thirdwatch/fb-ad-library-scraper) — Thirdwatch
- [Facebook Marketplace Scraper - Listings, Prices & Alerts](https://apify.com/thirdwatch/facebook-marketplace-scraper) — Thirdwatch
- [Instagram Scraper - Posts, Reels, Comments & Profiles](https://apify.com/thirdwatch/instagram-scraper) — Thirdwatch

Last verified: 2026-09

More scrapers at [thirdwatch.dev](https://thirdwatch.dev).

# Actor input Schema

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

Page posts, public group posts, post comments and replies, public page details, or keyword search over the public web index.

## `pageUrls` (type: `array`):

Facebook page/profile URLs or @usernames

## `maxResults` (type: `integer`):

Maximum records for Page posts, Group posts and Page details, shared across all supplied sources.

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

Used by Post comments. Caps TOP-LEVEL comments per post; replies are returned in addition, capped separately by the replies limit below. Facebook serves anonymous visitors only part of a busy thread - roughly 30 comments on a post whose counter reads 87 - so a run can finish below this cap because the source stopped serving.

## `includeReplies` (type: `boolean`):

Fetch the replies under each top-level comment. Replies carry parent_comment_id so threads can be rebuilt.

## `maxRepliesPerComment` (type: `integer`):

Cap on replies fetched under each top-level comment.

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

Leave as-is for the tested defaults: residential exits for Page posts and Group posts, the shared pool for Post comments and Page details. Facebook returns a login shell for public Group pages to datacenter IPs, and rate-limits Page timeline pagination there. Choosing a group, a country or your own proxy URLs overrides the default.

## Actor input object example

```json
{
  "mode": "page_details",
  "pageUrls": [],
  "maxResults": 10,
  "maxCommentsPerPost": 50,
  "includeReplies": true,
  "maxRepliesPerComment": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# 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_details"
};

// Run the Actor and wait for it to finish
const run = await client.actor("thirdwatch/facebook-pages-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_details" }

# Run the Actor and wait for it to finish
run = client.actor("thirdwatch/facebook-pages-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_details"
}' |
apify call thirdwatch/facebook-pages-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thirdwatch/facebook-pages-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/Z45L9MsdIgOJi4GQB/builds/XsAwg6S6c7sRzIW4H/openapi.json
