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

Scrape posts from any Facebook Page: text, date, reactions by type, comments, shares, video views, photos, videos, links, collaborators and video transcripts. Filter by date range. No login or cookies needed. Export to JSON, CSV or Excel, or use via API.

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

## Pricing

from $2.00 / 1,000 posts

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

### What is Facebook Posts Scraper?

**Facebook Posts Scraper** collects posts from public Facebook Pages and turns them into clean, structured data. Paste in one or more Page URLs, click **Start**, and get every post with its text, date, reactions, comments, shares, video views, photos, videos and links. No Facebook login or cookies needed.

- 📝 Scrape **posts from many Pages in one run**
- 👍 Get **engagement**: reactions by type (Like, Love, Care, Haha, Wow, Sad, Angry), comments, shares and video views
- 🖼 Get **media**: photos, albums, videos and reels with thumbnails and video URLs
- 🎥 Get **video transcripts** (Facebook's captions, including auto-generated ones)
- 📅 Filter by **date range**: only posts newer than, older than, or between two dates
- 🔓 **No login or cookies**, so your accounts are never at risk
- 💾 Download the data as **JSON, CSV, Excel, XML or HTML**, or use it through the API

### What data can I extract from Facebook posts?

| | |
| --- | --- |
| 📝 Post text and links in it | 🔗 Post URL and ID |
| 📅 Publication date and time | 👤 Author (Page) name, ID and picture |
| 👍 Total reactions | ❤️ Reactions by type |
| 💬 Number of comments | 🔁 Number of shares |
| ▶️ Video plays and views | 🎥 Video transcript |
| 🖼 Photos with their alt text | 📹 Videos and reels with thumbnails |
| 🌐 Shared external link | 🤝 Collaborators and paid partnership label |
| 📚 Ad Library Page ID | |

### How do I scrape Facebook posts?

1. Create a free Apify account with your email.
2. Open **Facebook Posts Scraper**.
3. Add one or more Facebook Page URLs, for example `https://www.facebook.com/humansofnewyork/`.
4. Optionally set **Max posts per Page**, a **date range**, and turn on **video transcripts**.
5. Click **Start** and download your data as JSON, CSV, Excel, XML or HTML, or fetch it through the API.

### How much does it cost to scrape Facebook posts?

You pay **per post scraped**; the platform usage and residential proxies are included. To control costs, set **Max posts per Page** and a date range, or set a maximum cost per run in the run options. The scraper stops as soon as that limit is reached.

| Apify plan | Price per 1,000 posts |
| --- | --- |
| Free | $5.00 |
| Starter | $4.00 |
| Scale | $2.50 |
| Business | $2.00 |

Each run also has a $0.001 start fee. Video transcripts cost nothing extra.

**Date filter add-on:** when you set "Posts newer than" or "Posts older than", each post also costs $2.00 / $1.00 / $0.80 / $0.60 per 1,000 (Free / Starter / Scale / Business).

**Failed requests:** when Facebook blocks or errors a request and the scraper has to retry it, the Apify Proxy traffic of that failed attempt is charged at $0.008 per MB (billed per 100 KB). Successful requests are covered by the per-post price, and runs that use your own proxies are never charged for traffic. The total is shown as `failedRequestsProxyTrafficMB` in the run's `RUN_SUMMARY`. The $5 monthly credit on the Free plan covers about 1,000 posts without a date filter.

### ⬇️ Input

| Field | Description |
| --- | --- |
| `startUrls` | Page URLs (`https://www.facebook.com/BPP`), `profile.php?id=` URLs or plain Page names. |
| `resultsLimit` | Maximum number of posts per Page. Leave empty for all posts (within the date range). |
| `onlyPostsNewerThan` | Only posts published after this date: `2025-03-12`, a UTC timestamp such as `2025-09-23T10:02:01`, or a relative period such as `7 days`, `2 months` or `3 hours`. |
| `onlyPostsOlderThan` | Only posts published before this date, same formats. Combine both for a custom date range. |
| `captionText` | Download the transcript of video posts into `captionText`. Default `false`. |
| `proxy` | Proxy settings. Residential proxies (the default) work best. You can also use your own proxies in `proxyUrls`. |

Example input:

```json
{
    "startUrls": [{ "url": "https://www.facebook.com/BPP" }],
    "resultsLimit": 1000,
    "onlyPostsNewerThan": "2025-03-12",
    "captionText": false,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": ["RESIDENTIAL"]
    }
}
```

### ⬆️ Output

The results are stored in a dataset, which you can find in the **Storage** tab. Each post is one item. Here are a reel and a photo album (long fields shortened):

```json
[
    {
        "facebookUrl": "https://www.facebook.com/SamsoniteCanada",
        "postId": "1663728452429357",
        "pageName": "SamsoniteCanada",
        "url": "https://www.facebook.com/reel/1082907384553622/",
        "time": "2026-09-28T13:00:52.000Z",
        "timestamp": 1790600452,
        "user": {
            "id": "100063766545121",
            "name": "Samsonite Canada",
            "profileUrl": "https://www.facebook.com/100063766545121",
            "profilePic": "https://scontent.xx.fbcdn.net/v/t39.30808-1/...png"
        },
        "collaborators": [],
        "text": "Meet your new favourite travel Companions. ✨\n\nVoici vos nouveaux Companions de voyage préférés. ✨",
        "likes": 1,
        "comments": 0,
        "shares": 0,
        "topReactionsCount": 1,
        "isVideo": true,
        "viewsCount": 141,
        "videoPostViewCount": 37,
        "liveViewerCount": 0,
        "media": [
            {
                "thumbnail": "https://scontent.xx.fbcdn.net/v/t15.5256-10/...jpg",
                "__typename": "Video",
                "id": "1082907384553622",
                "playable_duration_in_ms": 6016,
                "url": "https://www.facebook.com/reel/1082907384553622/",
                "width": 1080,
                "height": 1920,
                "videoDeliveryLegacyFields": {
                    "browser_native_sd_url": "https://video.xx.fbcdn.net/o1/v/t2/f2/m412/...mp4",
                    "browser_native_hd_url": "https://video.xx.fbcdn.net/o1/v/t2/f2/m266/...mp4"
                },
                "...": "..."
            }
        ],
        "feedbackId": "ZmVlZGJhY2s6MTY2MzcyODQ1MjQyOTM1Nw==",
        "reactionLikeCount": 1,
        "paidPartnership": false,
        "topLevelUrl": "https://www.facebook.com/100063766545121/posts/1663728452429357",
        "facebookId": "100063766545121",
        "pageAdLibrary": { "id": "303801648645", "pamv_comms_data": null },
        "inputUrl": "https://www.facebook.com/SamsoniteCanada"
    },
    {
        "facebookUrl": "https://www.facebook.com/SamsoniteCanada",
        "postId": "1660881599380709",
        "pageName": "SamsoniteCanada",
        "url": "https://www.facebook.com/SamsoniteCanada/posts/pfbid0KbCscbDdKvnto8h9iA9EK7Sw3NofzoMyQTcQoC2Yy7DGhhp7URAt5128myaG1w2cl",
        "time": "2026-09-25T22:00:17.000Z",
        "timestamp": 1790373617,
        "user": { "id": "100063766545121", "name": "Samsonite Canada", "profileUrl": "https://www.facebook.com/100063766545121", "profilePic": "https://scontent.xx.fbcdn.net/..." },
        "collaborators": [],
        "text": "Pack beautifully. Travel effortlessly.\n\nEmballez avec élégance. Voyagez sans effort.",
        "likes": 0,
        "comments": 0,
        "shares": 0,
        "topReactionsCount": 0,
        "media": [
            { "mediaset_token": "pcb.1660881599380709", "url": "https://www.facebook.com/SamsoniteCanada/posts/pfbid0KbCscbDdKv...", "comet_product_tag_feed_overlay_renderer": null },
            {
                "thumbnail": "https://scontent.xx.fbcdn.net/v/t39.30808-6/...jpg",
                "__typename": "Photo",
                "image": { "uri": "https://scontent.xx.fbcdn.net/v/t39.30808-6/...jpg", "height": 590, "width": 472 },
                "id": "1660881579380711",
                "url": "https://www.facebook.com/photo/?fbid=1660881579380711&set=pcb.1660881599380709",
                "ocrText": "May be an image of suitcase"
            }
        ],
        "feedbackId": "ZmVlZGJhY2s6MTY2MDg4MTU5OTM4MDcwOQ==",
        "paidPartnership": false,
        "topLevelUrl": "https://www.facebook.com/100063766545121/posts/1660881599380709",
        "facebookId": "100063766545121",
        "pageAdLibrary": { "id": "303801648645", "pamv_comms_data": null },
        "inputUrl": "https://www.facebook.com/SamsoniteCanada"
    }
]
```

Other fields, when they apply:

- `reactionLikeCount`, `reactionLoveCount`, `reactionCareCount`, `reactionHahaCount`, `reactionWowCount`, `reactionSadCount`, `reactionAngryCount`: reactions by type (only the types the post received).
- `link`: the external link the post shares.
- `textReferences`: links and mentions inside the post text.
- `captionText`: the video transcript, with **Include video transcript** turned on (`null` when the video has no captions).
- `viewsCount` is the number of plays; `videoPostViewCount` the number of views Facebook shows under the post.

Media URLs are signed by Facebook and expire after a few days, so download the files if you need to keep them.

A summary of each run (which Pages succeeded, failed or were skipped, and why) is saved as `RUN_SUMMARY` in the run's key-value store.

When a Page cannot be scraped (deleted, age-restricted, not a Page URL, ...), the dataset gets one free item for it with `inputUrl`, `error` (the code, e.g. `NOT_FOUND`) and `errorDescription`, shown in the **Errors** view. Such a run still ends as succeeded, with the reasons in its status message; it only fails when the scraper itself could not get through to Facebook.

### ❓ FAQ

#### Can I scrape posts from personal profiles?

Only from public profiles that Facebook shows to visitors who are not logged in, such as public figures. Most personal profiles are private and return nothing.

#### Why does a Page return fewer posts than it has?

Facebook only shows logged-out visitors the posts that are public. Posts limited to a country or age group, and posts the Page has hidden, are skipped. Pinned posts are skipped too, because they would break the date order.

#### Why does a Page fail as age-restricted?

Pages about alcohol, gambling and similar topics can be age-restricted by their owners. Facebook shows them only to logged-in adults, so the scraper cannot open them and reports them as failed with the code `AGE_RESTRICTED` right away instead of retrying.

#### How does the date filter work?

Facebook filters by date on its side, so asking for an old period (for example, posts older than 2024-01-01) does not page through all newer posts first. Dates without a time are read as midnight UTC.

#### Why are some video view counts empty?

Facebook does not show view counts for some videos, for example videos attached to events or shared from other Pages.

#### Can I use the scraper through the API?

Yes. Every run can be started, scheduled and monitored through the [Apify API](https://docs.apify.com/api/v2), and you can fetch the results from the run's dataset. For Node.js use the [`apify-client`](https://www.npmjs.com/package/apify-client) NPM package, and for Python the [`apify-client`](https://pypi.org/project/apify-client/) PyPI package. The **API** tab has ready-to-use code examples.

#### Can I use it with AI agents through MCP?

Yes. Through the [Apify MCP server](https://docs.apify.com/platform/integrations/mcp) you can let AI assistants such as Claude, or your own agents, run the scraper and read its results.

#### Do I need proxies?

Facebook blocks most server IPs, so proxies are needed. On the Apify platform residential proxies are used by default and you do not have to set anything up. You can also plug in your own proxies in the **Proxy configuration** input. If a request fails on your own proxy (blocked, rate-limited, out of traffic, wrong password) or you run without a proxy, the scraper gives it one more try on Apify residential proxy, so the Page is still scraped. That try is billed like any Apify Proxy run: only if it fails, at $0.008 per MB of its traffic.

#### Can I connect the data to other apps?

Yes. Through [Apify integrations](https://apify.com/integrations) you can send the results to Google Sheets, Google Drive, Slack, Make, Zapier, Airbyte, GitHub, Keboola and more, or set up [webhooks](https://docs.apify.com/platform/integrations/webhooks) to act whenever a run finishes.

#### Is it legal to scrape Facebook posts?

This scraper collects only posts that Pages choose to show publicly, and it never logs in. However, your results may contain personal data, which is protected by regulations such as the GDPR in the European Union. Do not scrape personal data unless you have a legitimate reason to. If you are unsure, consult a lawyer. You can also read the Apify blog post on the [legality of web scraping](https://blog.apify.com/is-web-scraping-legal/).

### Your feedback

If you have technical feedback or found a bug, please open an issue in the **Issues** tab and include the run link and the Pages you tried.

# Actor input Schema

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

Pages to scrape posts from, e.g. <code>https://www.facebook.com/humansofnewyork/</code>. Accepts Page URLs, <code>profile.php?id=</code> URLs and plain Page names. Only public Pages and Profiles work.

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

Maximum number of posts to scrape from each Page. Leave empty to scrape as many posts as the Page has (within the date range). You are charged per post, so keep this as low as you need.

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

Only scrape posts published after this date. Use an absolute date (<code>2025-03-12</code>), a UTC timestamp (<code>2025-09-23T10:02:01</code>) or a relative period (<code>7 days</code>, <code>2 months</code>, <code>1 year</code>, <code>3 hours</code>).

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

Only scrape posts published before this date. Same formats as above. Combine both to get a custom date range; Facebook filters by date on its side, so old periods are reached quickly.

## `captionText` (type: `boolean`):

Download the captions of video posts (when Facebook has them, including auto-generated ones) and return them as plain text in <code>captionText</code>. Adds one small request per video.

## `proxy` (type: `object`):

Facebook blocks datacenter IPs quickly. Residential proxies give the most reliable results. You can also use your own proxies.

## Actor input object example

```json
{
  "startUrls": [
    {
      "url": "https://www.facebook.com/humansofnewyork/"
    }
  ],
  "resultsLimit": 20,
  "captionText": false,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

Scraped posts with text, date, reactions, comments, shares, video views and media.

## `engagement` (type: `string`):

Reactions by type, comments, shares and video views of each post.

## `runSummary` (type: `string`):

Which Pages succeeded, failed or were skipped, and why.

# 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 = {
    "startUrls": [
        {
            "url": "https://www.facebook.com/humansofnewyork/"
        }
    ],
    "resultsLimit": 20,
    "proxy": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("arisma_tech/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 = {
    "startUrls": [{ "url": "https://www.facebook.com/humansofnewyork/" }],
    "resultsLimit": 20,
    "proxy": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("arisma_tech/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 '{
  "startUrls": [
    {
      "url": "https://www.facebook.com/humansofnewyork/"
    }
  ],
  "resultsLimit": 20,
  "proxy": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call arisma_tech/facebook-posts-scraper --silent --output-dataset

```

## MCP server setup

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