# Facebook Posts Scraper (`scraper_creator/facebook-posts-scraper`) Actor

Scrape public Facebook page posts with text, timestamps, reactions, comments, shares, video views, and follower counts. Supports cursor pagination, multi-session completeness checks, and standalone profile follower extraction.

- **URL**: https://apify.com/scraper_creator/facebook-posts-scraper.md
- **Developed by:** [Scraper Creator](https://apify.com/scraper_creator) (community)
- **Stats:** 1 total users, 1 monthly users, 81.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 facebook results

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

## Facebook Page Statistics

Collect public Facebook page posts, engagement statistics, and exact follower counts without supplying login cookies or an API token.

### How to use

1. Add 1–5 public Facebook page URLs under **Page URLs**.
2. Set **Posts per page** (`resultsLimit`, default 100, maximum 10,000). Choose a limit large enough to cover the accessible feed: the Actor must reach the end and verify matching post IDs across independent sessions.
3. Keep the default Malaysian (`MY`) residential proxy or supply your own supported proxy configuration. Cloud runs require a proxy; residential traffic adds cost.
4. Start the Actor and wait for verification. It reads the feed at least twice, so results may not appear immediately.
5. Check the run status and `RUN-SUMMARY`, then export the dataset or retrieve it through the Apify API. Use successful runs for complete snapshots.

For **followers only**, switch to JSON input and use the profile example below. Remove `resultsLimit`; setting it to zero does not select followers-only mode.

Run memory defaults are managed in Apify Console under Actor Settings. The source does not declare `defaultMemoryMbytes`; explicit run, task, or API memory settings can override the cloud default. Memory is a run option, not an input JSON field.

### Input

#### Example

```json
{
  "startUrls": [{ "url": "https://www.facebook.com/facebook" }],
  "resultsLimit": 100
}
```

#### Fields

| Field | Required | Description |
| --- | --- | --- |
| `startUrls` | Yes | Array of 1–5 objects containing a public page `url`. Plain URL strings are not accepted. |
| `resultsLimit` | For posts | Maximum posts per page, from 1 to 10,000. The form prefills 100. Remove this field for followers-only mode. |
| `proxyConfiguration` | No | Defaults to an Apify MY residential proxy. Cloud runs reject an explicit no-proxy setting. |

Use a page URL such as `https://www.facebook.com/facebook`. Numeric page URLs using `/profile.php?id=...` are also accepted. Individual post, Reel, group, and watch URLs are not supported.

#### Followers-only input

For profile followers, omit `resultsLimit`:

```json
{
  "startUrls": [{ "url": "https://www.facebook.com/facebook" }]
}
```

Followers-only mode returns one profile row per page and no post rows.

### Output

Each dataset row represents one post.

#### Example

The following is a synthetic example, not live statistics:

```json
{
  "postId": "123",
  "facebookId": "456",
  "facebookUrl": "https://www.facebook.com/example",
  "followers": 59,
  "inputUrl": "https://www.facebook.com/example",
  "url": "https://www.facebook.com/example/posts/123",
  "topLevelUrl": "https://www.facebook.com/456/posts/123",
  "user": {
    "id": "456",
    "name": "Example"
  },
  "text": "Title\nBody #example",
  "time": "2026-10-19T00:00:00.000Z",
  "timestamp": 1792368000,
  "likes": 0,
  "comments": 0,
  "shares": 0,
  "viewsCount": 5,
  "hashtags": [
    "#example"
  ],
  "scrapedAt": "2026-10-19T06:00:00.000Z",
  "warnings": []
}
```

#### Fields

| Field | Description |
| --- | --- |
| `postId`, `facebookId`, `facebookUrl`, `inputUrl` | Post and page identity, page URL, and requested source. |
| `url`, `topLevelUrl` | Post permalink and URL built from the verified numeric page/post IDs. |
| `user.id`, `user.name` | Author identity and name. |
| `text`, `hashtags` | Post text and hashtags. |
| `time`, `timestamp`, `scrapedAt` | Publication time and collection time. |
| `likes`, `comments`, `shares`, `viewsCount` | Total reactions, comments, shares, and video plays. Plays are not a separate video-view metric. |
| `followers`, `warnings` | Current exact page follower count, repeated on its posts, and data notices. |

Followers-only rows contain `pageId`, `facebookId`, `pageUrl`, `facebookUrl`, `inputUrl`, `followers`, and `scrapedAt`. Use this mode for a page with no posts. Counts are snapshots and may change after collection.

#### Data accuracy

Unavailable metrics remain `null`; confirmed zero remains `0`. Text-only and photo posts can have no play count. Missing or rounded followers fail the target rather than returning an estimate. Only English follower labels are supported.

### Viewing and exporting results

Open the run's dataset to view the returned rows. Export JSON to preserve nested fields such as `user` and arrays such as `hashtags`, or use a tabular export for spreadsheet analysis. API integrations can retrieve items from the run's default dataset.

Open `RUN-SUMMARY` in the run's default key-value store to check each requested page. A dataset containing rows does not by itself mean the whole run completed successfully.

### Pricing

Check the Actor page for current prices. In pay-per-event runs, each returned result is billable. Proxy usage may add separate charges. Results delivered before a failure or budget stop may already be charged; a failed run does not mean no cost.

Post verification reads the feed at least twice and consumes proxy traffic before output. A low result budget does not cap those verification costs.

### Limits and failures

- Posts must reach end-of-feed and pass independent verification before they are returned. **Reaching `resultsLimit` before end-of-feed fails the run** with `RESULTS_LIMIT_BEFORE_END_OF_FEED` in `RUN-SUMMARY`. That profile is not retried and its buffered posts are not published or charged as results; the attempt still incurs platform usage. Increase the limit to cover the accessible feed, up to 10,000. A page ending exactly at the limit can succeed after the usual matching complete traversals.
- Inconsistent results produce `COMPLETENESS_UNVERIFIED`. Inaccessible feeds, invalid required data, interrupted collection, and storage errors can also fail the run. Previously written verified results may remain; import successful runs only.
- Verification reduces transient omissions but cannot prove that all historical posts are public or accessible. Compare with your own saved post list when full historical coverage matters.
- A budget stop produces an incomplete, failed run with `partial: true` and `stopReason: MAX_TOTAL_CHARGE_REACHED` in `RUN-SUMMARY`.
- Cloud runs require a proxy. If you see `PROXY_REQUIRED`, restore the default MY residential proxy or provide a supported configuration. Proxy access is not guaranteed.
- Private analytics, comment bodies, media downloads, video transcription, and individual-post refresh are not supported.

### Refreshing statistics

Start a new run with the same input and a fresh dataset. Posts mode collects and verifies the accessible feed again; it does not refresh individual post URLs. For a follower-only update, use the profile input above.

For API compatibility and operator setup, see [DEVELOPMENT.md](DEVELOPMENT.md).

# Changelog

This Actor's version history is a separate document: https://apify.com/scraper_creator/facebook-posts-scraper/changelog.md

# Actor input Schema

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

One to five public Facebook page URLs.

## `resultsLimit` (type: `integer`):

Must cover the accessible feed for completeness verification. Truncating the feed fails with RESULTS_LIMIT_BEFORE_END_OF_FEED without retrying that page or returning its posts. A feed ending exactly at the limit can pass verification. Omit this for followers-only output.

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

Defaults to an Apify residential proxy in Malaysia. In Apify cloud tests (2026-10-19), direct connections were redirected away from the page and the timeline never loaded; a Malaysian residential proxy read the feed. Posts mode traverses the feed at least twice, so residential proxy traffic adds noticeable cost. On Apify, choosing no proxy stops the run immediately with PROXY_REQUIRED.

## Actor input object example

```json
{
  "resultsLimit": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "MY"
  }
}
```

# Actor output Schema

## `posts` (type: `string`):

No description

## `summary` (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 = {
    "resultsLimit": 100,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "apifyProxyCountry": "MY"
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scraper_creator/facebook-posts-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 = {
    "resultsLimit": 100,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
        "apifyProxyCountry": "MY",
    },
}

# Run the Actor and wait for it to finish
run = client.actor("scraper_creator/facebook-posts-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 '{
  "resultsLimit": 100,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "apifyProxyCountry": "MY"
  }
}' |
apify call scraper_creator/facebook-posts-scraper --silent --output-dataset

```

## MCP server setup

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