# Facebook Comments Scraper (`scrapio/facebook-comments-scraper`) Actor

Facebook Comments Scraper extracts public comments from Facebook posts, including comment text, author details, timestamps, reactions, replies, and post URLs. Ideal for audience research, sentiment analysis, engagement tracking, competitor monitoring, and social media insights.

- **URL**: https://apify.com/scrapio/facebook-comments-scraper.md
- **Developed by:** [Scrapio](https://apify.com/scrapio) (community)
- **Categories:** Social media, Automation, Lead generation
- **Stats:** 22 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$19.99/month + usage

To use this Actor, you pay a monthly rental fee to the developer. The rent is subtracted from your prepaid usage every month after the free trial period. You also pay for the Apify platform usage, which gets cheaper the higher Apify subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#rental-actors

## 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 Comments Scraper — Extract Comments, Replies and Profiles

Facebook Comments Scraper Pay Per Events extracts public comments, nested replies, and commenter profile data from any Facebook post, photo, or reel permalink, and returns them as one flat JSON row per top-level comment — no login, cookie, or Graph API access token required. Unlike scraping frameworks that hand back raw HTML, this Actor returns typed JSON, ready for a spreadsheet, a database, or a model's context window without any parsing. Pricing is pay-per-result: you're billed per comment row actually written to your dataset, never for the run itself. This guide covers every input and output field, plus the deployment patterns teams use to run it in production.

### 🧭 What Does Facebook Comments Scraper Pay Per Events Do?

Facebook Comments Scraper Pay Per Events reads the public comment thread on a Facebook post, photo, or reel permalink and returns every top-level comment — with its nested replies attached — as a flat, structured dataset row: author name and ID, comment text, timestamp, reaction count, and reply count. No Facebook account, login cookie, or Graph API access token is required — the Actor loads the public permalink logged-out through Apify's residential proxy and paginates Facebook's own GraphQL comment API directly.

- Extracts every top-level comment on a post, photo, or reel, up to `commentSettings.maxComments`
- Expands nested reply threads per comment, up to `commentSettings.maxRepliesPerComment`
- Orders output rows deterministically by `commentsSortOrder` (`most_relevant`, `newest`, or `all`)
- Filters to a date window with `onlyCommentsNewerThan` (absolute date or relative span like `2 weeks`)
- Returns commenter identity fields — `profileName`, `profileId`, `profileUrl`, `profilePicture` — with every row
- Attaches Facebook Ad Library metadata (`pageAdLibrary`) when a comment is tied to a Page running ads
- Bulk-processes multiple post URLs from one `startUrls` list in a single run

### ⚡ Features & Capabilities

Facebook Comments Scraper Pay Per Events groups its capabilities into three areas: what it extracts per comment, how it fits into the rest of the Scrapio Facebook toolset, and how it bills for results.

#### Core features

- Scrapes public comments from Facebook **post**, **photo**, and **reel** permalinks, with bulk URL paste supported in `startUrls`
- Attaches nested reply threads to their parent comment in the `reply` array, capped by `commentSettings.maxRepliesPerComment`
- Deterministic output ordering via `commentsSortOrder`: `most_relevant` (engagement-ranked), `newest` (date-descending), or `all` (Facebook's returned order)
- Date-window filtering via `onlyCommentsNewerThan`, applied after comments are fetched
- Every row carries author identity (`profileName`, `profileId`, `profileUrl`, `profilePicture`), comment content (`text`, `date`), and engagement (`likesCount`, `commentsCount`)
- Ad Library metadata (`pageAdLibrary.is_business_page_active`, `pageAdLibrary.id`) attached when a comment's author is a Page with an Ad Library presence
- Always-on Apify **residential** proxy routing — no manual proxy setup required, regardless of what is selected in `proxyConfiguration`
- Pay-per-result pricing: one `row_result` charge per top-level comment row delivered (nested replies inside that row are not billed separately); rows that fail to load are pushed without a charge

#### Facebook Comments Scraper Pay Per Events within the Scrapio data stack

Facebook Comments Scraper Pay Per Events covers comments and replies on individual post, photo, and reel permalinks. For comment threads inside public Facebook **Groups** instead of Pages, use `facebook-groups-comments-replies-scraper`. To discover post URLs at scale by keyword before feeding them into this Actor, use `facebook-posts-search-comments-scraper` or `facebook-page-posts-scraper-with-lead-contact-list`. For advertiser contact details behind the Pages running ads that show up in `pageAdLibrary`, see `facebook-ads-library-scraper-advertiser-contact-finder`.

### Why do developers and data teams scrape Facebook?

Different teams pull Facebook comment data for different reasons — the common thread is that the comment thread, not just the post, is the signal they actually want.

#### 🏢 Social listening, brand monitoring and moderation teams

Brand and community teams monitor comment threads on their own posts, and on competitor or influencer posts, to catch complaints, praise, and moderation-worthy content early. Feed a page's recent post URLs into `startUrls`, set `commentsSortOrder` to `newest` so freshly posted comments surface first, and use `onlyCommentsNewerThan` (e.g. `1 day`) to pull only what happened since the last check. Each row's `text`, `profileName`, `likesCount`, and `date` fields are enough to flag a spike in negative sentiment, a customer complaint needing a reply, or a comment worth reporting. Because replies are nested in the parent comment's `reply` array, teams can see whether a page admin already responded before escalating.

#### 📊 AI training data and RAG indexing

Comment `text` is the highest-information field for both use cases — short, first-person, unstructured natural language, exactly the shape RAG pipelines chunk and embed for retrieval, and exactly what makes useful data for fine-tuning sentiment or intent classifiers. For **RAG enrichment**, index `text` alongside `profileName`, `date`, and the parent `facebookUrl` so a retrieved snippet can cite who said what, when, and on which post. For **training data**, `likesCount` and `commentsCount` work as a weak engagement label, while `threadingDepth` distinguishes an original top-level opinion (`0`) from a reactive reply (`1`). Every field returns as a typed primitive straight out of the dataset — no HTML stripping or regex cleanup before it reaches an embedding model or a fine-tuning job.

#### 📱 Competitive and market intelligence

Marketing and competitive-intelligence teams point `startUrls` at a competitor's or industry page's public posts to track how audiences react — not just what a competitor posts, but how people respond to it. Sorting with `commentsSortOrder: most_relevant` surfaces the comments Facebook itself ranks as highest-engagement, a fast way to see which claims, offers, or product angles actually land. Tracking `likesCount` and `commentsCount` on the same post across repeated runs, using `onlyCommentsNewerThan` to pull only the delta, shows whether a competitor's engagement is genuinely accelerating or just accumulating slowly.

#### 🔬 Research and academic use

Academic and social-science researchers use public comment threads to study online discourse, sentiment, and community response to news, political, or public-health content, without a Facebook Graph API app review or data-partnership process. Because every row is built only from a **publicly reachable** post permalink, this Actor is scoped to public-data-only research designs — content behind a login wall, a private group, or a friends-only audience is never reachable and never appears in the output.

#### 🎥 Product and SaaS development

Teams building moderation dashboards, sentiment-monitoring tools, or lead-scoring products on top of Facebook engagement data use this Actor as the ingestion layer: schedule it against a client's own pages, normalize `text`, `likesCount`, and `profileName` into your own schema, and layer your product's scoring or alerting logic on top. Because output fields are stable JSON keys rather than scraped HTML, maintaining that ingestion layer doesn't mean rewriting a parser every time Facebook changes its front end.

### 🍚 Input Parameters

All parameters below are read directly from `.actor/input_schema.json` (embedded in `actor.json`), in schema order, with the same names, types, and defaults the Actor actually uses.

| Parameter | Required | Type | Description | Example Value |
| --- | --- | --- | --- | --- |
| `startUrls` | **Yes** | array of strings | One Facebook post, photo, or reel URL per line; bulk paste from a spreadsheet is supported. | `["https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl"]` |
| `commentSettings` | No | object | Grouped panel for comment limits and sort order (see nested fields below). | `{ "maxComments": 100, "maxRepliesPerComment": 2, "commentsSortOrder": "all" }` |
| `commentSettings.maxComments` | No | integer, minimum `1` | Hard cap on top-level comments fetched per URL. Default: `100`. | `100` |
| `commentSettings.maxRepliesPerComment` | No | integer, minimum `0` | Nested replies fetched per threaded comment. Default: `2`. | `5` |
| `commentSettings.commentsSortOrder` | No | string, enum: `most_relevant`, `newest`, `all` | Order of the comment rows in the output. Default: `all`. | `"newest"` |
| `onlyCommentsNewerThan` | No | string | Absolute date (`2024-01-15`) or relative window (`1 day`, `2 weeks`, `3 months`). Only comments and replies posted after this point are kept. Filtering happens **after** comments are fetched, so set `maxComments` generously for narrow windows. Leave blank to disable. | `"2 weeks"` |
| `proxyConfiguration` | No | object | Informational only — the Actor always attaches Apify **residential** proxy at runtime regardless of this setting. Prefill: `{ "useApifyProxy": false }`. | `{ "useApifyProxy": false }` |

**Example input:**

```json
{
  "startUrls": [
    "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl"
  ],
  "commentSettings": {
    "maxComments": 100,
    "maxRepliesPerComment": 5,
    "commentsSortOrder": "newest"
  },
  "onlyCommentsNewerThan": "2 weeks"
}
```

#### Supported URL types and input formats

`startUrls` accepts typical Facebook **post**, **photo**, and **reel** permalinks from `facebook.com` — anything starting with `http` is accepted for processing. The Actor then loads that URL as a Facebook permalink page and extracts the `doc_id`/`feedback_id` pair its GraphQL comment API needs; if that extraction fails (wrong URL type, removed post, or a page Facebook won't render logged-out), the row for that URL carries an `error` message instead of comments rather than stopping the run.

Real examples:

- Standard post permalink: `https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl`
- Bulk input — multiple posts in one run, one per line:
  ```
  https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl
  https://www.facebook.com/PageName/videos/1234567890123456
  ```
- Narrow time-window run — pair a recent post with a relative filter: `startUrls` set to the post, `onlyCommentsNewerThan` set to `"3 days"`, and `commentSettings.maxComments` raised (e.g. `500`) since the date filter is applied after the fetch.

### 📦 Output Format

Each top-level comment is pushed to the dataset as one flat row, with any nested replies carried inside that same row's `reply` array — replies are never written as separate dataset rows. Rows stream into the **Output** tab as the run works.

#### Output for Comments

```json
{
  "facebookUrl": "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl",
  "commentUrl": "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl?comment_id=1234567890123456",
  "id": "Y29tbWVudDoxMjM0NTY3ODkwMTIzNDU2",
  "feedbackId": "ZmVlZGJhY2s6MTIzNDU2Nzg5MDEyMzQ1Ng==",
  "date": "2026-06-02T14:08:31+00:00",
  "text": "This story hit hard. Thank you for sharing it.",
  "profilePicture": "https://scontent.xx.fbcdn.net/v/t1.6435-1/avatar_123.jpg",
  "profileId": "100004512378965",
  "profileName": "Maria Alvarez",
  "profileUrl": "https://www.facebook.com/maria.alvarez.921",
  "likesCount": 214,
  "commentsCount": 1,
  "threadingDepth": 0,
  "facebookId": "1234567890123456",
  "inputUrl": "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl",
  "expansionToken": "ZXhwYW5zaW9uOnRva2VuOjEyMzQ1Njc4OTA=",
  "reply": [
    {
      "facebookUrl": "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl",
      "commentUrl": "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl?comment_id=1234567890123456&reply_comment_id=9988776655443322",
      "id": "Y29tbWVudDo5OTg4Nzc2NjU1NDQzMzIy",
      "feedbackId": "ZmVlZGJhY2s6OTk4ODc3NjY1NTQ0MzMyMg==",
      "date": "2026-06-02T15:41:09+00:00",
      "text": "Agreed, one of the best ones this year.",
      "profilePicture": null,
      "profileId": "100009887766554",
      "profileName": "Devon Clarke",
      "likesCount": 8,
      "commentsCount": 0,
      "reply": [],
      "threadingDepth": 1,
      "facebookId": "9988776655443322",
      "inputUrl": "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl"
    }
  ],
  "url_key": "pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl",
  "full_url": "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl"
}
```

| Field | Type | Description |
| --- | --- | --- |
| `facebookUrl` | string | The input post/photo/reel URL this comment came from |
| `commentUrl` | string | Direct permalink to this specific comment |
| `id` | string | Facebook's internal comment node ID |
| `feedbackId` | string | GraphQL feedback ID used to paginate this comment's own replies |
| `date` | string (ISO 8601, UTC) | Comment timestamp |
| `text` | string | Comment body text |
| `profilePicture` | string | null | Commenter's profile picture URL |
| `profileId` | string | Commenter's numeric Facebook ID |
| `profileName` | string | Commenter's display name |
| `profileUrl` | string | Commenter's profile URL — present only when the author exposes one |
| `likesCount` | integer | Total reactions on the comment |
| `commentsCount` | integer | Number of direct replies Facebook reports for this comment |
| `reply` | array | Nested reply objects in this same shape, populated up to `maxRepliesPerComment`; empty on a reply object itself (only one reply level is expanded) |
| `threadingDepth` | integer | `0` for a top-level comment, `1` for a reply |
| `facebookId` | string | Legacy numeric Facebook ID for the comment |
| `inputUrl` | string | The input URL that produced this row (mirrors `facebookUrl`) |
| `expansionToken` | string | Present only when the comment has an expandable reply thread |
| `pageAdLibrary` | object | `{ is_business_page_active, id }` — present only when the comment's author is a Page with Ad Library data |
| `url_key` | string | Short identifier parsed from the end of the input URL |
| `full_url` | string | The original input URL (duplicate of `facebookUrl`) |

If a URL cannot be processed at all (bad permalink, blocked load, no comment pages returned), the Actor pushes a row with only `url_key`, `full_url`, `error`, and an empty `comments` array — **and that row is pushed without the charged event**, so failed URLs are never billed. To exclude these accounting rows from downstream processing, filter on the presence of `text` (real rows always have it) or the absence of `error`:

```json
{ "url_key": "pfbid0Xyz...", "full_url": "https://www.facebook.com/PageName/posts/pfbid0Xyz...", "error": "Failed to extract required data from the post page", "comments": [] }
```

#### Schema stability and export options

Field names stay stable across runs — the row shape comes from a fixed conversion function, not from whatever markup Facebook happens to render, so a front-end redesign on Facebook's side does not rename your columns. Optional fields (`profileUrl`, `expansionToken`, `pageAdLibrary`) are simply omitted, never sent as empty strings, when Facebook doesn't expose them for a given comment. Results live in a standard Apify dataset and can be exported from the **Output** tab, or via the API, to JSON, CSV, Excel (XLSX), or XML.

### 💡 Facebook Comments Scraper Pay Per Events Strategy Guide

#### 🎯 Strategy 1: Real-time enrichment pipeline

Trigger a run whenever a new post needs its comments attached to a lead, ticket, or CRM record: on the event (a new post detected by `facebook-page-posts-scraper-with-lead-contact-list`, a support ticket referencing a Facebook post, etc.), call this Actor with `startUrls` set to that one post URL and a modest `commentSettings.maxComments`. Poll the run's dataset via the Apify API, then append each row's `text`, `profileName`, and `likesCount` to the destination record. Because output is already typed JSON, no HTML parsing sits between the Actor and your CRM write.

#### 🎯 Strategy 2: Scheduled monitoring and alerting

For ongoing tracking, schedule a recurring run against the same post or page URLs using Apify's Scheduler, with `onlyCommentsNewerThan` set to a rolling window (`"1 day"` for a daily job) so each run only pulls what's new since the last one. Diff the incoming `id`/`facebookId` values against what you stored from the previous run, and alert when `commentsCount` spikes on a specific comment or a new reply lands with an unusually high `likesCount` — the signal that a thread is taking off or turning negative.

#### 🎯 Strategy 3: Bulk dataset build

For a research corpus or training set, paste every post URL you need into `startUrls` in one run — bulk paste is supported natively — and set `commentSettings.maxComments` and `maxRepliesPerComment` high enough for full coverage. Export the resulting dataset directly to CSV or JSON, or pull it via the API into a database. For very large URL lists, split them across multiple Actor runs within your Apify plan's concurrent-run allowance rather than relying on one oversized run.

#### Strategy comparison at a glance

| Strategy | Best for | Run pattern | Output format |
| --- | --- | --- | --- |
| Real-time enrichment | CRM/lead enrichment on inbound events | Single on-demand run per event, via API or Console | JSON, polled via API |
| Scheduled monitoring | Ongoing sentiment/volume tracking on key posts | Recurring run via Apify Scheduler with `onlyCommentsNewerThan` | Dataset diffed run-over-run |
| Bulk dataset build | Research corpora, training data | One run with many `startUrls` | CSV/JSON export |

### 🌴 Related Facebook Scrapers & Tools

| Scraper Name | What it extracts |
| --- | --- |
| `facebook-groups-comments-replies-scraper` | Posts, comments, and nested replies from public Facebook **Groups** |
| `facebook-posts-search-comments-scraper` | Posts discovered by keyword search, plus each post's top comments |
| `facebook-page-posts-scraper-with-lead-contact-list` | A Page's posts and public contact/lead details |
| `facebook-ads-library-scraper-advertiser-contact-finder` | Ad Library ads and advertiser contact details |
| `facebook-url-to-id-scraper-username-finder` | Resolves Facebook URLs, usernames, and numeric IDs to each other |
| `instagram-comments-scraper-with-engagement-analytics` | Instagram post/reel comments and replies with engagement metrics |
| `youtube-comments-scraper-with-reply-thread-expansion` | YouTube video comments with fully expanded reply threads |
| `reddit-comment-scraper-sentiment-lead-scoring` | Reddit post comments with sentiment and lead scoring |
| `LinkedIn-Company-Scraper-Post-Reactions-Comments-And-Engagement-Analytics` | LinkedIn company page posts, reactions, and comments |
| `facebook-user-search-scraper-with-lead-contact-enrichment` | Facebook profiles and Pages discovered by name/niche, with contact enrichment |

### How to integrate Facebook Comments Scraper Pay Per Events with your stack

Facebook Comments Scraper Pay Per Events works with any language or tool that can call the Apify API — there's no dedicated SDK beyond the official Apify client libraries.

#### Python

```python
from apify_client import ApifyClient
import csv

client = ApifyClient("<YOUR_APIFY_API_TOKEN>")

run_input = {
    "startUrls": [
        "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl",
    ],
    "commentSettings": {
        "maxComments": 100,
        "maxRepliesPerComment": 5,
        "commentsSortOrder": "newest",
    },
    "onlyCommentsNewerThan": "2 weeks",
}

run = client.actor("YOUR_USERNAME/facebook-comments-scraper-pay-per-events").call(run_input=run_input)

rows = []
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
    if item.get("error"):
        continue  # uncharged accounting row — skip
    rows.append({
        "post": item.get("full_url"),
        "author": item.get("profileName"),
        "text": item.get("text"),
        "likes": item.get("likesCount"),
        "date": item.get("date"),
        "replies": len(item.get("reply", [])),
    })

with open("facebook_comments.csv", "w", newline="", encoding="utf-8") as f:
    writer = csv.DictWriter(f, fieldnames=["post", "author", "text", "likes", "date", "replies"])
    writer.writeheader()
    writer.writerows(rows)

print(f"Saved {len(rows)} comments to facebook_comments.csv")
```

#### Node.js

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_API_TOKEN>' });

const input = {
    startUrls: ['https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl'],
    commentSettings: { maxComments: 50, maxRepliesPerComment: 2, commentsSortOrder: 'most_relevant' },
};

const run = await client.actor('YOUR_USERNAME/facebook-comments-scraper-pay-per-events').call(input);
const { items } = await client.dataset(run.defaultDatasetId).listItems();

const comments = items.filter((item) => !item.error);
console.log(`Fetched ${comments.length} comments`);
comments.forEach((c) => {
    console.log(`${c.profileName}: ${c.text} (${c.likesCount} likes, ${(c.reply || []).length} replies)`);
});
```

#### Async and scheduled pipelines

Every run is started on demand through the Apify Console or API and returns a dataset ID you can poll for completion — there is no actor-specific webhook or push mechanism in the source. For recurring jobs, use Apify's platform-level Scheduler to fire this Actor on a cron interval, and either poll the run status via the API or configure an Apify webhook on the run's completion event so your system is notified instead of polling continuously.

### 🎯 Who Needs Facebook Comments Scraper Pay Per Events? (Use Cases & Industries)

#### 🏢 Social listening, brand monitoring and moderation teams

A community manager pulls comments on a brand's latest campaign post with `commentsSortOrder: newest`, scans `text` and `likesCount` for spikes in complaints or praise, and escalates any comment that needs a public reply — using `profileName` and `commentUrl` to respond directly on the original thread.

#### 📊 AI/ML teams building training data and RAG pipelines

A data team indexes `text`, `profileName`, and `date` from thousands of comments into a vector store for a customer-sentiment RAG assistant, using `likesCount` as a lightweight relevance signal when ranking retrieved snippets.

#### 📱 Competitive intelligence and marketing analysts

An analyst tracks comment volume and `likesCount` on a competitor's product-launch posts week over week, using `onlyCommentsNewerThan` to isolate what changed since the last check and spotting which specific claims drew the most engaged responses.

#### 🔬 Researchers

Academic and social-science researchers collect public comment threads on news or public-health posts to study discourse patterns and public sentiment, scoped entirely to publicly reachable permalinks — no login-gated or private-group content is ever included.

#### 🎥 Product and SaaS builders

A SaaS team building a social-listening dashboard schedules this Actor against client-owned Pages, maps `text`/`profileName`/`likesCount` into their own normalized schema, and layers sentiment scoring or alerting on top without maintaining a Facebook HTML parser themselves.

### Is it legal to scrape Facebook?

Scraping publicly accessible Facebook posts and comments — content visible without logging in — is generally treated differently under U.S. law than bypassing a login wall or authentication barrier. In *hiQ Labs, Inc. v. LinkedIn Corp.* (9th Circuit Court of Appeals, 2019), the court held that scraping data that is not access-restricted does not constitute "unauthorized access" under the Computer Fraud and Abuse Act — a widely cited general principle for public-data scraping in the U.S., though it did not involve Facebook specifically and its reasoning may not extend to every jurisdiction or every category of data.

Separately, Meta's own Terms of Service prohibit automated data collection without permission; violating those terms is a civil contract matter — grounds for an account or IP ban, or a breach-of-contract claim — not a criminal offense. Because this Actor's output includes personal data about real individuals (`profileName`, `profileId`, `profileUrl`, `profilePicture`), storing or processing that data may also trigger obligations under regimes like the GDPR (EU/EEA) or CCPA (California) depending on who you are and where your users are.

Facebook Comments Scraper Pay Per Events returns only publicly accessible data. What you do with that data is your responsibility — consult legal counsel for commercial applications involving personal data.

### ❓ Frequently asked questions

#### Does Facebook Comments Scraper Pay Per Events work without a Facebook account?

Yes. The Actor loads the public post, photo, or reel permalink logged-out and paginates Facebook's own comment API directly — no login, session cookie, or Graph API access token is read from or required by the input schema.

#### How does it handle Facebook's anti-scraping measures?

It always routes every request through Apify's residential proxy pool, regardless of what's set in `proxyConfiguration`, and retries failed HTTP requests up to three times with exponential backoff before giving up on a given fetch.

#### Can I run it at scale without getting blocked?

`startUrls` accepts a bulk list of post URLs processed in a single run, and each run's size is governed by the `maxComments`/`maxRepliesPerComment` values you set — no uptime or success-rate figure is published for this Actor, so plan capacity by your own testing rather than an assumed number.

#### How fresh is the data it returns?

Live. Each run issues fresh GraphQL requests to Facebook at execution time; nothing is served from a cache.

#### Which fields work best for AI training and RAG indexing?

`text` is the primary field for both — it's the actual comment content. For RAG, pair it with `profileName`, `date`, and `facebookUrl` for citation context. For training data, `likesCount`, `commentsCount`, and `threadingDepth` (top-level vs. reply) give consistent, typed structure across every record with no normalization required.

#### Does this Actor collect personal data, and who's responsible for it?

Yes — `profileName`, `profileId`, `profileUrl`, and `profilePicture` identify real commenters. The Actor only returns what Facebook already displays publicly; the lawful basis for storing, processing, or acting on that data sits with you as the operator, not with the Actor.

#### Does Facebook Comments Scraper Pay Per Events work with Claude, ChatGPT, and other AI agent tools?

Yes, as an HTTP endpoint — any agent framework that can call the Apify API (directly, or through the official `apify-client` SDK) can start a run and read back typed JSON rows with no parsing step, which is what an LLM context window needs.

#### What happens when a URL fails to load?

The Actor pushes a row containing only `url_key`, `full_url`, `error`, and an empty `comments` array for that URL, and continues to the next one instead of failing the whole run. This accounting row is pushed **without** the charged event, so a failed URL is never billed.

#### How does the date filter (`onlyCommentsNewerThan`) actually work?

It's applied after comments are fetched, not as a query-time filter against Facebook — so for a narrow recent window, set `maxComments` generously to make sure enough of the thread is pulled before filtering trims it down.

#### What's the difference between `maxComments` and `maxRepliesPerComment`?

`maxComments` caps top-level comments fetched per URL. `maxRepliesPerComment` separately caps how many nested replies are fetched for each of those top-level comments — replies never count against the `maxComments` limit.

### ℹ️ Disclaimer

Facebook Comments Scraper Pay Per Events extracts only publicly available data from Facebook. This tool is intended for lawful use cases only. Users are responsible for complying with Facebook's terms of service and applicable data protection laws in their jurisdiction.

# Actor input Schema

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

📋 One URL per line — bulk paste from a spreadsheet is welcome.

✅ Works with typical **post**, **photo**, and **reel** permalinks from facebook.com.

💡 **Pro tip:** run a small test first, then scale up your max comments.

## `commentSettings` (type: `object`):

▶️ **One panel** — max comments, reply depth, and sort order live together. Tap the header to expand or collapse.

## `onlyCommentsNewerThan` (type: `string`):

Pick a date (Absolute, e.g. `2024-01-15`) or a relative window (Relative, e.g. `1 day`, `2 weeks`, `3 months`). Only comments and replies posted **after** this point will be kept. Leave blank to disable.

ℹ️ Filtering happens after comments are fetched, so set `maxComments` generously for narrow windows.

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

ℹ️ Informational only — the scraper **always** attaches Apify **residential** proxy at runtime regardless of what is selected here. Tap the header above to expand or collapse this section.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped items in the Actor's default dataset.

# 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": [
        "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("scrapio/facebook-comments-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": ["https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl"],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("scrapio/facebook-comments-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": [
    "https://www.facebook.com/humansofnewyork/posts/pfbid0BbKbkisExKGSKuhee9a7i86RwRuMKFC8NSkKStB7CsM3uXJuAAfZLrkcJMXxhH4Yl"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call scrapio/facebook-comments-scraper --silent --output-dataset

```

## MCP server setup

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