# Facebook Posts Scraper - Page & Profile Posts, No Login (`benthepythondev/facebook-posts-scraper`) Actor

Returns the posts of public Facebook pages and profiles: text, date, reactions by type, comments, shares, video views, pictures, video and link of every post, newest first. Works from page links, names or ids, with a date range and an only-new mode for monitoring. No login, no cookies, no browser.

- **URL**: https://apify.com/benthepythondev/facebook-posts-scraper.md
- **Developed by:** [Ben](https://apify.com/benthepythondev) (community)
- **Categories:** Social media, Marketing, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.40 / 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

## 📰 Facebook Posts Scraper

Returns the posts of public Facebook pages and profiles without a login, a cookie or a browser. Enter page links, names or ids and get one row per post: text, date, reactions by kind, comments, shares, video views, pictures, video and link. Read a page newest first, cut out a date range, or run it on a schedule and receive only the posts that are new.

**Price:** $4.00 per 1,000 posts on the Apify Free plan, down to $3.40 from the Gold plan up. A page Facebook does not show to visitors costs nothing. Export to JSON, CSV or Excel, run on a schedule, call via API, or connect to Make, Zapier or n8n.

### 🔎 What is the Facebook Posts Scraper?

A public page shows its posts to any visitor, three at a time, while you scroll. This Actor makes the same requests the page makes and reads several pages side by side: 360 posts from six pages in a little over a minute. Your own Facebook account is never involved, so nothing can happen to it.

#### What data does it extract?

- **Post:** id, link, text, publication time, and its type (video, photo, link, event, share or text)
- **Engagement:** reactions in total and by kind (like, love, care, haha, wow, sad, angry), comments, shares, video views
- **Media:** every picture, the video file with its length, a preview picture, and the outside link of a link post with its headline
- **Shares:** the link, author and text of the post that was shared
- **Page:** id, name and link on every row

#### How it reads the site

The Actor does not open a browser. It sends the page's own data requests directly, so a run needs 512 MB of memory instead of the gigabytes a browser takes, and several pages are read side by side. Facebook accepts a date with these requests: a week from last year is read without scrolling through the months after it. A limit is exact: with `maxResults` 4, four rows per page are saved and charged, although Facebook hands out posts in threes.

### ⬇️ Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `pages` | array | | Links of public pages or profiles, their names (`NASA`) or numeric ids. An empty input reads a sample page |
| `maxResults` | integer | 15 | Posts to save per page, up to 2,000 |
| `postedAfter` | string | empty | Lower date limit: a day (YYYY-MM-DD) or a period back from now (`3 days`, `2 weeks`, `6 months`) |
| `postedBefore` | string | empty | Upper date limit, same forms. The read starts there instead of paging down to it |
| `onlyNewPosts` | boolean | false | Skip every post an earlier run with the same monitor name delivered |
| `monitorId` | string | empty | Name of that memory |

Links of the forms `facebook.com/NASA`, `facebook.com/profile.php?id=…`, `facebook.com/people/Name/id` and `facebook.com/p/Name-id` are understood, with or without a trailing path such as `/posts`.

#### Example input

The latest 100 posts of three pages:

```json
{
  "pages": [
    "https://www.facebook.com/NASA",
    "https://www.facebook.com/bbcnews",
    "natgeo"
  ],
  "maxResults": 100
}
```

One week from a year ago. The read starts at September 7, so only that week is fetched and charged:

```json
{
  "pages": ["NASA"],
  "postedAfter": "2025-09-01",
  "postedBefore": "2025-09-07",
  "maxResults": 200
}
```

A daily watch that delivers only new posts:

```json
{
  "pages": ["bbcnews", "natgeo"],
  "maxResults": 60,
  "onlyNewPosts": true,
  "monitorId": "news-pages"
}
```

#### Coming from another Facebook posts Actor?

The input names `startUrls`, `resultsLimit`, `onlyPostsNewerThan` and `onlyPostsOlderThan` are read as well, so an input written for one of the common Facebook posts Actors runs here unchanged:

```json
{
  "startUrls": [{ "url": "https://www.facebook.com/natgeo" }],
  "resultsLimit": 50,
  "onlyPostsNewerThan": "2 days"
}
```

### ⬆️ Output

One row per post. A video post of a page (the two media links are shortened here):

```json
{
  "postId": "1645617416933628",
  "url": "https://www.facebook.com/reel/1665351285019129/",
  "pageId": "100044561550831",
  "pageName": "NASA - National Aeronautics and Space Administration",
  "pageUrl": "https://www.facebook.com/NASA",
  "type": "video",
  "text": "This October, you can look forward to these sights in the night sky:\n- A good look at Saturn\n- The Orionid meteor shower peaks mid-month\n- The Moon passes by the Seven Sisters\n\nLearn the tricks to spotting these celestial treats: https://go.nasa.gov/4z9LlWU",
  "title": null,
  "createdAt": "2026-10-02T14:15:12+00:00",
  "authorName": "NASA - National Aeronautics and Space Administration",
  "authorId": "100044561550831",
  "authorUrl": "https://www.facebook.com/NASA",
  "reactions": 2048,
  "reactionCounts": { "like": 1671, "love": 320, "care": 32, "wow": 15, "haha": 10 },
  "comments": 53,
  "shares": 233,
  "videoViews": 19991,
  "imageUrls": [],
  "videoUrl": "https://video-iad6-1.xx.fbcdn.net/o1/v/t2/f2/m366/AQPpeR0gP4nq8obbaWrZPWtxkSEH….mp4?…",
  "videoSeconds": 162.4,
  "thumbnailUrl": "https://scontent-iad6-1.xx.fbcdn.net/v/t15.5256-10/831402639_1080742941480555_4837841491824040290_n.jpg?…",
  "linkUrl": null,
  "isShare": false,
  "sharedPost": null,
  "position": 2,
  "scrapedAt": "2026-10-04T08:53:50.272784+00:00"
}
```

A link post fills `title` with the headline and `linkUrl` with the outside page; an event post puts the event's name into `title`. A share fills `sharedPost` with the link, author and text of the original post. `position` is the post's place in the page's feed, newest first. The run also writes a `SUMMARY` record that names the pages that were not shown or had no posts and the reason a run stopped.

### 💰 What a run costs

| Apify plan | Per 1,000 posts |
|---|---|
| Free | $4.00 |
| Bronze | $3.80 |
| Silver | $3.60 |
| Gold, Platinum, Diamond | $3.40 |

Apify's standard start event ($0.00005) is the only other charge; proxies are included. Not charged: a page Facebook does not show to visitors, a page that does not exist, a post already delivered in only-new mode, and posts outside your date range. Set the run's maximum charge and the Actor stops at it with the rows it has saved.

### ⏱️ Measured on Apify (October 4, 2026)

| Run | Posts | Time |
|---|---|---|
| Empty input (sample page), twelve runs | 15 | 9 to 30 s, half of them under 14 s |
| Six pages, 60 posts each, four runs | 360 | 57 to 75 s |
| One busy page (BBC News), three runs | 300 | 155 to 194 s |
| One week of one page from a year earlier | 4 | 14 s |
| A profile back to November 2021 | 342 | 10 min |
| Only-new watch on one page, second run | 0 new | 9 s |

All at 512 MB. An aborted and resumed run of 630 posts saved no post twice.

Recent posts arrive within one or two seconds per request. Older posts come slower: in the profile test above, half of the requests took more than 4.5 seconds and some took 16, so a long history is a job for a date range or a longer run. At the very end of a page's history Facebook can take half a minute to confirm that nothing older exists.

### 🔔 Watching pages for new posts

Turn on `onlyNewPosts`, give the watch a `monitorId` and put the run on a schedule. The first run delivers the latest posts up to `maxResults`. Later runs read each page from its newest post and stop when they reach posts they have already delivered, so a quiet page costs nothing. The memory is a key-value store named `facebook-posts-monitor` in your own account; delete a record there to start a watch over.

### 🤖 For AI agents

Smallest useful call:

```json
{"pages": ["https://www.facebook.com/NASA"], "maxResults": 30}
```

Each row is one post with `text`, `createdAt`, `type`, `reactions`, `reactionCounts`, `comments`, `shares`, `videoViews`, `imageUrls`, `videoUrl`, `linkUrl` and `url`. `pages` takes several entries at once. A page that is not shown to visitors returns no rows; the status message and the `SUMMARY` record name it. No credentials are needed.

### 💡 Use cases

- 📊 **Competitor and brand tracking:** what a company posts, how often, and which posts get reactions, comments, shares and views.
- 📰 **Media monitoring:** new posts of publishers and institutions as a daily feed.
- 🎬 **Content research:** which formats (video, photo, link) work on the pages of your market.
- 🗂️ **Archiving and reporting:** the posts of a campaign period, cut out by date.

### ⚠️ Limits, stated plainly

- **Public pages and profiles only.** Facebook shows some pages only to logged-in users, for example pages with an age or country limit such as alcohol brands. Those are reported as not shown; this Actor does not log in.
- **Three posts per request.** That is what Facebook gives a visitor. One page yields about 100 recent posts a minute (300 posts of BBC News took a little under three minutes); several pages run side by side.
- **Comments are counted, not exported.** The number of comments is on every row; the comment texts are not part of this Actor. The [Facebook Comments Scraper](https://apify.com/benthepythondev/facebook-comments-scraper) returns them when you give it the `url` of a post, reel, video or photo row.
- **No keyword search and no groups.** This Actor reads pages you name. For groups there is the Facebook Groups Scraper.
- **2,000 posts per page and run.** For more, run again with `postedBefore` set to the day of the oldest post you have. That day's posts are delivered again; `postId` identifies them.
- **Video views appear where Facebook shows them.** In a test of 193 video posts, 187 carried a view count.
- **Media links are Facebook's own and expire after a few days.** Download pictures and videos soon after the run if you need the files.
- **Facebook limits how often one address may ask.** The Actor changes addresses by itself. If Facebook stops answering in the middle of a page, the rows saved so far stay and the status message names the page.

### ❓ FAQ

**Do I need a Facebook account or cookies?** No. The Actor reads public pages the way a visitor without an account sees them.

**Does it work for personal profiles?** For profiles whose posts are public to everyone, such as public figures. Posts that only friends can see are not visible to a visitor and are not returned.

**Why is a page reported as "not shown to visitors"?** The page does not exist under that name, or Facebook asks visitors to log in before showing it. Open the link in a private browser window: if Facebook shows a login form or "This content isn't available" instead of the page, no visitor can read it.

**Why are there fewer posts than I asked for?** The page has fewer public posts, or your date range was reached. The status message says what happened.

**How do I get posts from a certain period?** Set `postedAfter` and `postedBefore`. Facebook starts the list at the upper limit, so a month from two years ago costs only that month.

**Does it return the comments?** The count, not the texts. For the texts, pass the `url` of a row to the [Facebook Comments Scraper](https://apify.com/benthepythondev/facebook-comments-scraper).

**Can the same post appear twice?** No. Facebook sometimes lists a post a second time further down a page; the Actor saves it once.

**Can I run it every hour?** Yes. With `onlyNewPosts` a page without new posts is left after its two newest pages of posts.

**How do I call it from code?** With the Apify API or the Python and JavaScript clients; every run returns a dataset you can fetch as JSON or CSV. It also works as a tool through Apify's MCP server.

**Is it legal?** The Actor reads what Facebook shows to everyone without a login. Posts can contain personal data: GDPR, CCPA and similar rules apply to how you store and use them, and Facebook's terms apply to you as well. Collect only what you need.

### 🔗 You might also like

- [Facebook Comments Scraper](https://apify.com/benthepythondev/facebook-comments-scraper): the comments and replies under a post
- [Facebook Groups Scraper](https://apify.com/benthepythondev/facebook-groups-scraper): posts of public Facebook groups
- [Facebook Pages Scraper](https://apify.com/benthepythondev/facebook-pages-scraper): business information and contacts of public pages
- [Meta Ad Library Scraper](https://apify.com/benthepythondev/meta-ad-library-scraper): the ads a brand runs on Facebook and Instagram
- [Instagram Posts Scraper](https://apify.com/benthepythondev/instagram-posts-scraper): posts of public Instagram accounts with likes and comments

**Keywords:** facebook posts scraper, facebook page posts, scrape facebook page, facebook page scraper, facebook posts export, facebook post engagement, facebook reactions data, facebook video views, facebook page monitoring, competitor facebook posts, facebook posts by date, facebook posts csv, facebook posts api alternative, no login facebook scraper, public facebook pages, social media monitoring

# Actor input Schema

## `pages` (type: `array`):

Links of public pages or profiles (https://www.facebook.com/NASA), their names (NASA) or numeric ids. Several pages are read side by side. A page that Facebook shows only to logged-in users (age or country limits) is reported and costs nothing.

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

Posts to save for each page, newest first. Facebook gives a visitor three posts per request, so 100 posts of one page take about one minute.

## `postedAfter` (type: `string`):

Lower date limit: a day (YYYY-MM-DD) or a period back from now such as 3 days, 2 weeks or 6 months. Facebook ends the list there, so older posts are neither read nor charged.

## `postedBefore` (type: `string`):

Upper date limit: a day (YYYY-MM-DD, included) or a period back from now. The read starts at that day instead of paging down to it, so a month from two years ago costs only that month.

## `onlyNewPosts` (type: `boolean`):

For scheduled runs: skips every post an earlier run with the same monitor name delivered, so you pay only for new posts. The memory is a key-value store in your own account.

## `monitorId` (type: `string`):

Name of the memory used by the option above. Give each watch its own name; without a name the list of pages is the name.

## Actor input object example

```json
{
  "pages": [
    "https://www.facebook.com/NASA"
  ],
  "maxResults": 15,
  "onlyNewPosts": false
}
```

# Actor output Schema

## `results` (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 = {
    "pages": [
        "https://www.facebook.com/NASA"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("benthepythondev/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 = { "pages": ["https://www.facebook.com/NASA"] }

# Run the Actor and wait for it to finish
run = client.actor("benthepythondev/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 '{
  "pages": [
    "https://www.facebook.com/NASA"
  ]
}' |
apify call benthepythondev/facebook-posts-scraper --silent --output-dataset

```

## MCP server setup

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