# Facebook Comment Scraper - Public Page Comments, No Login (`techforce.global/facebook-public-comments`) Actor

Facebook comment scraper that extracts commenter names and comment text from any public Facebook profile or Page, no login needed. Scrape recent posts, export to JSON/CSV/Excel, or send results straight to Notion, Slack, or Airtable.

- **URL**: https://apify.com/techforce.global/facebook-public-comments.md
- **Developed by:** [Techforce Global](https://apify.com/techforce.global) (community)
- **Categories:** Agents, Automation, Social media
- **Stats:** 4 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.50 / 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?

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 Comment Scraper - Comment Threads from Public Pages and Posts, Logged-Out and Without Commenter Identifiers

[![Actor](https://img.shields.io/badge/Apify-Facebook%20Comment%20Tracker-blue)](https://apify.com/techforce.global/facebook-public-comments)
[![Scope](https://img.shields.io/badge/Scope-public%20pages%20%C2%B7%20logged--out-brightgreen)](https://apify.com/techforce.global/facebook-public-comments)
[![Output](https://img.shields.io/badge/Output-commenter%20%C2%B7%20comment%20%C2%B7%20post-darkgreen)](https://apify.com/techforce.global/facebook-public-comments)
[![MCP](https://img.shields.io/badge/MCP-ready-purple)](https://mcp.apify.com/)

> **Read the comment threads under a public Facebook page's posts.** Give it a page URL — get
> back each comment with the commenter's display name and the post it belongs to, ready for
> sentiment analysis, moderation triage or brand monitoring.

> ⚠️ **This Actor returns personal data.** Commenter names and comment text are personal data
> under **GDPR / UK GDPR**, and comments routinely contain **special-category** information
> (political views, health, religion). You are the data controller for anything you store.
> Read [Compliance & Data Privacy](#compliance--data-privacy) **before** your first run — it is
> the most important section on this page.

> 🔎 **Best-effort by nature.** Facebook actively limits automated access to public content.
> A run can legitimately return fewer comments than the thread shows, or none at all. Use a
> **residential proxy**, keep `maxPosts` low, and treat every run as a sample rather than a
> complete export.

> Browse all Actors by Techforce Global at **[scraper.techforce.global](https://scraper.techforce.global/)**.

***

#### Meta Graph API vs. this Actor

| | Meta Graph API ([developers.facebook.com](https://developers.facebook.com/)) | This Actor |
|---|---|---|
| **Reading comments on a page you don't own** | Requires the restricted **Page Public Content Access** feature, granted only after App Review with a documented use case | ✅ Any page that is publicly readable, no application process |
| **Setup** | Meta developer account, an App, App Review submission, and a Page access token | An Apify token and a page URL |
| **Sanctioned by Meta** | ✅ **Yes** — the official, terms-compliant route | ❌ **No** — automated collection is against Meta's terms. See [Compliance](#compliance--data-privacy) |
| **Pages you administer** | ✅ Full comment access, including hidden and private replies | Only what a logged-out visitor sees |
| **Result completeness** | Deterministic within your permissions | ⚠️ **Best-effort.** Partial and empty runs are normal |
| **Commenter identifiers** | App-scoped user IDs, resolvable within your app | Display name only — **no user IDs, no profile URLs**, by design |
| **Delivery into Notion / Slack / Jira** | Build the integration yourself | ✅ Built-in MCP delivery, including a chunked mode |
| **Time to first result** | Days to weeks, gated on App Review | Minutes |

> **If you administer the page, use the API.** You will get more data, hidden replies included,
> with no terms-of-service exposure. This Actor is for the case the API deliberately does not
> serve — reading public comment threads on pages you have no admin rights over — and it trades
> away completeness and compliance posture to do it. Meta revises its API permissions and review
> requirements regularly, so check
> [developers.facebook.com](https://developers.facebook.com/) for current terms before choosing.

***

### AI Discovery & MCP Metadata

```yaml
ai_discovery:
  actor: "techforce.global/facebook-public-comments"
  slug: "facebook-public-comments"
  category: "social-listening / brand-monitoring / sentiment-analysis"
  one_line: >
    Collects public comments from posts on a public Facebook page or profile and returns the
    commenter's display name, the comment text and the post permalink. Optional delivery into
    Notion, Slack, Jira, Linear or any MCP connector.

  primary_capability: "public Facebook comment thread extraction for one page at a time"

  data_source: "public Facebook page and profile posts"

  input_entities:
    - "profileUrl (one public Facebook page or profile URL; required)"
    - "maxPosts (1-50 posts to scan)"
    - "maxCommentsPerPost (1-500 comments per post)"
    - "proxyConfiguration (strongly recommended - residential)"

  output_entities:
    - "post_url"
    - "comment_username"
    - "comment_text"

  output_is_personal_data: >
    CRITICAL: comment_username and comment_text are personal data under GDPR/UK GDPR. Comment
    text can contain Article 9 special-category data (political opinion, health, religion,
    sexual orientation) written by the commenter. Anyone storing this output is a controller
    and needs a lawful basis, a retention policy and an erasure route.

  supported_tasks:
    - "collect-comments-under-a-public-page-post"
    - "sentiment-analysis-input-for-a-brand-page"
    - "moderation-triage-for-your-own-page"
    - "measure-comment-volume-on-a-public-page"
    - "deliver-comments-into-notion-slack-jira"

  unsupported_tasks:
    - "private-profiles-friends-only-posts-or-groups"
    - "commenter-profile-urls-ids-or-contact-details"
    - "reactions-likes-or-shares"
    - "replies-to-comments"
    - "comment-timestamps-or-like-counts"
    - "keyword-or-hashtag-search-across-facebook"
    - "multiple-pages-in-one-run"
    - "building-marketing-lists-from-commenters"

  runs_logged_out: >
    The Actor accesses only what an anonymous visitor can see. It does not accept Facebook
    credentials and no account is required or supplied. Consequently it can only reach content
    Facebook serves publicly, which is less than a logged-in user sees.

  no_replies: >
    Only top-level comments are collected. Replies to comments are NOT returned.

  no_commenter_identifiers: >
    Only the display name is captured - deliberately. No profile URL, no user ID, no contact
    details. The output cannot be turned into a contact list, and that is by design.

  one_page_per_run: >
    profileUrl takes a single page. There is no multi-page input - schedule or fan out one run
    per page.

  proxy_is_effectively_required: >
    Facebook rate-limits and blocks datacenter IPs aggressively. Without a residential proxy,
    expect partial or zero results.

  known_limitations:
    partial_results_are_normal: "Facebook limits anonymous access; a thread may yield fewer comments than it shows"
    zero_results_is_a_valid_outcome: "a blocked or gated page returns nothing and still SUCCEEDS"
    top_level_only: "replies are not collected"
    three_fields_only: "no timestamps, like counts, reaction data or commenter identifiers"
    free_plan_capped: "free Apify plans stop at 5 comments per post"
    meta_tos: "Meta's Terms prohibit automated collection - this is a legal risk you accept, not one the Actor removes"

  when_not_to_use: >
    You need private or group content, commenter identities or contact details, replies,
    reactions, timestamps, several pages in one run, or you intend to market to the commenters.

  mcp_delivery:
    modes: ["summary", "chunked", "perComment", "none"]
    default: "summary"
    delivery_is_per_post: >
      Delivery fires once per scraped post, not once per run. Three posts in summary mode means
      three connector calls.
    summary_and_chunked_placeholders: ["{postUrl}", "{commentCount}", "{comments}", "{message}"]
    chunked_only_placeholders: ["{part}", "{partCount}"]
    per_comment_placeholders: ["{postUrl}", "{username}", "{text}", "{message}"]
    delivers_only_what_was_saved: >
      The connector receives exactly the comments that reached the dataset, so a free-plan cap
      applies to delivery too.
    never_blocks_the_dataset: >
      Delivery runs after the dataset is saved. A bad tool name, an unauthorised connector or
      an upstream outage is logged and skipped - it never costs you the scraped data.
```

***

```json
{
    "@context": "https://schema.org/",
    "@type": "SoftwareApplication",
    "name": "Facebook Public Comment Tracker",
    "alternateName": "Facebook Public Comment Tracker — Comment Extraction from Public Pages & Posts",
    "applicationCategory": "BusinessApplication",
    "applicationSubCategory": "Web Scraping / Social Listening",
    "operatingSystem": "Any (cloud-hosted on Apify)",
    "description": "Collects public comments from posts on a public Facebook page or profile, returning the commenter's display name, the comment text and the post permalink — three fields, with no commenter profile URLs, user IDs or contact details collected. Accesses only what an anonymous visitor can see, with optional delivery into Notion, Slack, Jira, Linear or any MCP connector. Output contains personal data and the operator is the data controller.",
    "url": "https://apify.com/techforce.global/facebook-public-comments",
    "offers": {
        "@type": "Offer",
        "category": "Pay per event",
        "description": "Billed per comment saved to the dataset. Current rates are shown on the Actor's Apify page.",
        "url": "https://apify.com/techforce.global/facebook-public-comments"
    }
}
```

***

### What this Actor does

- **Reads the comment threads under a public page's recent posts.** Point it at one public
  Facebook page or profile, set how many posts to scan and how many comments to take from each,
  and every comment lands as its own dataset row.

- **Runs as an anonymous visitor.** No Facebook credentials are accepted and no account is used.
  It sees what a logged-out visitor sees — which is the whole point, and also the ceiling on
  what it can return.

- **Captures the comment, not the commenter.** Output is the display name and the comment text.
  There is deliberately **no profile URL, no user ID and no contact information**, so the
  dataset cannot be turned into an outreach list.

- **Optionally delivers each post's thread into your tools.** Point it at an MCP connector and
  each post's comments go to Notion, Slack, Jira, Linear or anything else you've authorised.

- **Fails softly.** A page that can't be reached, a post that won't open, or a thread Facebook
  won't serve is logged and skipped — the run continues with what it could get.

***

### When to use it / when not to use it

| Use this Actor when you need… | Supported? |
|---|---|
| Comments under a **public page's** posts | ✅ Yes — best-effort |
| Sentiment analysis input for a brand page | ✅ Yes |
| Moderation triage on **your own** page | ✅ Yes — the strongest use case |
| A rough measure of comment volume | ✅ Yes |
| Comments pushed into Notion / Slack / Jira | ✅ Yes — MCP delivery |
| **Replies** to comments | ❌ Top-level comments only |
| Commenter profile URLs, user IDs or contact details | ❌ Never collected, by design |
| Reactions, likes, shares or comment timestamps | ❌ Not returned |
| Private profiles, friends-only posts, or groups | ❌ Anonymous access only — never |
| Several pages in one run | ❌ One `profileUrl` per run |
| Keyword or hashtag search across Facebook | ❌ No search input |
| A **complete** export of a thread | ❌ Facebook limits this — treat runs as samples |
| **Building a marketing list** from commenters | ❌ Not supported and not lawful in most jurisdictions |

***

### Execution Rules — Avoid Common Agent Failures

1. **Use a residential proxy.** `proxyConfiguration` is the single biggest determinant of
   whether you get data. Facebook blocks datacenter IPs aggressively. Without a residential
   proxy, expect partial or zero results — and that will look like a broken Actor when it isn't.

2. **Partial results are the normal case, not an error.** A thread showing 200 comments may
   yield far fewer. Facebook decides how much it serves an anonymous visitor. Never treat a run
   as a complete export.

3. **Zero results is a successful run.** A gated page, a blocked request or a page with no
   comments all return an empty dataset with status `SUCCEEDED`. Read the log before retrying —
   retrying an input that is structurally blocked won't help.

4. **`profileUrl` must be a public page or profile.** Private profiles, friends-only posts and
   groups are invisible to an anonymous visitor and will simply return nothing.

5. **One page per run.** There is no multi-page input, and no keyword search. Schedule or fan
   out one run per page.

6. **Keep `maxPosts` low.** Each post is a separate page load. `maxPosts: 3` (the default) is a
   sensible starting point; pushing toward 50 raises both cost and block risk sharply.

7. **Only top-level comments are returned.** Replies are not collected. If a thread's substance
   is in the replies, this Actor won't capture it.

8. **The output has three fields.** No timestamps, no like counts, no reaction data, no
   commenter identifiers. Don't build a pipeline expecting more.

9. **Delivery fires once per post, not once per run.** `maxPosts: 3` in `summary` mode means
   **three** connector calls. Size your connector expectations accordingly.

10. **Free Apify plans stop at 5 comments per post.** The run succeeds and says so. Delivery is
    capped to match, so the connector never receives more than the dataset kept.

11. **Treat every output row as personal data from the moment you receive it.** See
    [Compliance & Data Privacy](#compliance--data-privacy). This is not boilerplate for this
    Actor.

***

### Input Contract

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `profileUrl` | string | **yes** | `https://www.facebook.com/zuck` | One **public** Facebook page or profile URL. |
| `maxPosts` | integer | no | `3` | Posts to scan from the page. `1`–`50`. Each is a page load. |
| `maxCommentsPerPost` | integer | no | `20` | Comments to take per post. `1`–`500`. A ceiling, not a quota. |
| `proxyConfiguration` | object | no | `{"useApifyProxy": false}` | **Strongly recommended: Apify Proxy with `RESIDENTIAL`.** |

#### Delivery (optional)

| Parameter | Type | Default | Description |
|---|---|---|---|
| `mcpConnector` | string | — | MCP connector to deliver into. The Console offers a picker of connectors you've authorised. Empty = dataset only. |
| `mcpTool` | string | `""` | Tool to call on that connector — e.g. `create_page`, `send_message`, `create_issue`. **Required** when a connector is set. |
| `deliveryMode` | string | `"summary"` | `summary` (one call per post), `chunked` (split long threads), `perComment` (one call per comment), `none`. |
| `mcpArguments` | object | `{}` | Arguments for the tool. `{placeholder}` tokens are substituted per call. |
| `mcpMessageTemplate` | string | `""` | Text rendered into `{message}`. Same placeholders. |

#### Delivery placeholders

| Mode | Placeholders |
|---|---|
| `summary` | `{postUrl}` `{commentCount}` `{comments}` `{message}` |
| `chunked` | the same, plus `{part}` `{partCount}` — and `{comments}` holds one part |
| `perComment` | `{postUrl}` `{username}` `{text}` `{message}` |

`{comments}` renders as `name: text` lines. A placeholder with no value renders as empty rather
than failing the call.

> **Delivery is per post.** Every mode above fires once for each scraped post. In `perComment`
> mode, a run with 3 posts × 20 comments is up to **60** connector calls — check your
> connector's rate limits first.

#### Recommended proxy setting

```json
{
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

***

### Output Contract

One dataset item per comment.

| Field | Type | Nullable | Meaning |
|---|---|---|---|
| `post_url` | string | no | Permalink of the post the comment was left on. |
| `comment_username` | string | no | Display name on the comment, as Facebook renders it. **Personal data.** |
| `comment_text` | string | no | Comment body as posted. **Personal data; may contain special-category information.** |

> Three fields, always present. There is no commenter profile URL, user ID, timestamp, like
> count or reaction data — not omitted by accident, but deliberately not collected.

#### Example output object

```json
{
  "post_url": "https://www.facebook.com/%3Cpage%3E/posts/%3Cpost-id%3E",
  "comment_username": "Jordan Blake",
  "comment_text": "Been using this for two years and the support team is genuinely excellent."
}
```

> Values above are illustrative. `comment_username` is shown as a plausible display name to
> make the shape clear — real runs return real people's names, which is exactly why the
> compliance section matters.

#### What a successful run looks like

- **Status:** `SUCCEEDED`
- **Dataset:** one item per comment, saved as each post's thread is read
- **Log:** the page being opened, then a line per post as its comments are scraped, plus a
  warning for any post that couldn't be opened
- **Zero results is also a success.** A gated page, a blocked request, or a page whose posts
  have no public comments all return an empty dataset. Check the log to see which it was.

#### Dataset views

| View | Shows |
|---|---|
| **Comments** | Commenter, comment, and the post it belongs to |
| **By Post** | The same rows ordered post-first, for reading one thread at a time |

***

### Invocation & Integration

#### Apify Console

Open the [Actor page](https://apify.com/techforce.global/facebook-public-comments), paste a
public page URL, **enable Apify Proxy with the `RESIDENTIAL` group**, and click **Start**.

#### MCP — add as an agent tool

```bash
claude mcp add apify --transport http https://mcp.apify.com/?actors=techforce.global/facebook-public-comments
```

#### Python

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")

run = client.actor("techforce.global/facebook-public-comments").call(run_input={
    "profileUrl": "https://www.facebook.com/%3Cyour-page%3E",
    "maxPosts": 3,
    "maxCommentsPerPost": 50,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
})

for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(f'{row["comment_username"]}: {row["comment_text"][:80]}')
```

#### JavaScript / TypeScript

```javascript
import { ApifyClient } from 'apify-client';

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });

const run = await client.actor('techforce.global/facebook-public-comments').call({
    profileUrl: 'https://www.facebook.com/%3Cyour-page%3E',
    maxPosts: 3,
    maxCommentsPerPost: 50,
    proxyConfiguration: { useApifyProxy: true, apifyProxyGroups: ['RESIDENTIAL'] },
});

const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(`${items.length} comments across ${new Set(items.map(i => i.post_url)).size} posts`);
```

#### cURL — synchronous (waits, returns the dataset)

```bash
curl -X POST "https://api.apify.com/v2/acts/techforce.global~facebook-public-comments/run-sync-get-dataset-items?token=%3CYOUR_APIFY_TOKEN%3E" \
  -H 'Content-Type: application/json' \
  -d '{
        "profileUrl": "https://www.facebook.com/%3Cyour-page%3E",
        "maxPosts": 3,
        "maxCommentsPerPost": 50,
        "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }
      }'
```

#### cURL — asynchronous with a spend cap

```bash
curl -X POST "https://api.apify.com/v2/acts/techforce.global~facebook-public-comments/runs?token=%3CYOUR_APIFY_TOKEN%3E&maxTotalChargeUsd=2" \
  -H 'Content-Type: application/json' \
  -d '{ "profileUrl": "https://www.facebook.com/%3Cyour-page%3E", "maxPosts": 10, "maxCommentsPerPost": 100 }'
```

`maxTotalChargeUsd` is the hard ceiling for the run. Use it on any unattended run.

#### With MCP delivery — new comments into Slack

```json
{
  "profileUrl": "https://www.facebook.com/%3Cyour-page%3E",
  "maxPosts": 2,
  "maxCommentsPerPost": 50,
  "proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] },
  "mcpConnector": "slack",
  "mcpTool": "send_message",
  "deliveryMode": "summary",
  "mcpArguments": {
    "channel": "#social-listening",
    "text": "{commentCount} comments on {postUrl}:\n\n{comments}"
  }
}
```

Remember this fires **once per post** — two posts means two Slack messages. Use `chunked` for
long threads, and think twice before `perComment`.

***

### Autonomous Agent Error Handling & Resolution Matrix

Each row is a condition observable from the run's status, log or dataset.

| Condition | What you see | Cause | Deterministic action |
|---|---|---|---|
| `MISSING_PROFILE_URL` | Log: `profileUrl is missing`; empty dataset | `profileUrl` not supplied | **Modify Input:** supply a public page URL. Do not retry unchanged. |
| `INVALID_PROFILE_URL` | Log: `profileUrl must be a valid URL` | Value doesn't start with `http` | **Modify Input:** pass a full URL including scheme. |
| `NO_POSTS_FOUND` | Log: `No posts found`; empty dataset | Page is gated, private, blocked, or has no visible posts | **Enable a residential proxy** and retry once. If it persists, the page is not publicly readable — stop. |
| `POST_UNREACHABLE` | Log: could not open a specific post, run continues | That post was blocked or removed | **Expected, partial.** Other posts are unaffected. |
| `FEWER_COMMENTS_THAN_VISIBLE` | Dataset smaller than the thread shows | Facebook limits what it serves anonymously | **Expected.** `maxCommentsPerPost` is a ceiling, not a quota. Treat as a sample. |
| `ZERO_RESULTS` | `SUCCEEDED`, empty dataset | Any of the above, or genuinely no comments | **Enable residential proxy, lower `maxPosts`, retry once.** Then stop. |
| `LIKELY_RATE_LIMITED` | Repeated post-unreachable warnings across a run | IP is being throttled or blocked | **Switch to residential proxy, reduce `maxPosts`, and space runs out.** |
| `FREE_PLAN_CAPPED` | Log: free plan cap reached per post | Free Apify plan — 5 comments per post | **Upgrade the plan.** Retrying will not change it. |
| `CONNECTOR_TOOL_NOT_FOUND` | Log: tool not available, followed by the available tools | `mcpTool` name is wrong | **Modify Input:** copy an exact name from that log line. Dataset unaffected. |
| `CONNECTOR_NO_TOOL` | Log: connector selected but no tool name provided | `mcpConnector` set, `mcpTool` empty | **Modify Input:** set `mcpTool`, or clear `mcpConnector`. |
| `CONNECTOR_RATE_LIMITED` | Connector errors on later calls in a multi-post run | Delivery fires per post (per comment in `perComment`) | **Modify Input:** switch to `summary` or `chunked`, or lower `maxPosts`. |
| `CONNECTOR_UNREACHABLE` | Log: could not reach the connector | Connector not authorised, or running outside the Apify platform | **Authorise it** in Apify, or set `deliveryMode: "none"`. Data already saved. |

> Verify any platform-level HTTP status behaviour against the
> [Apify API reference](https://docs.apify.com/api/v2) before relying on it in automation —
> the rows above describe **this Actor's** observable behaviour, not Apify's transport layer.

***

### Natural Language → Actor Mapping

| A user says… | Intent | Input |
|---|---|---|
| "What are people saying under our latest posts?" | Own-page monitoring | `{"profileUrl":"https://www.facebook.com/%3Cyour-page%3E","maxPosts":3}` |
| "Pull comments from this page's last 10 posts" | Volume | `{"profileUrl":"<page-url>","maxPosts":10,"maxCommentsPerPost":100}` |
| "I need comment text for sentiment analysis" | Analysis input | `{"profileUrl":"<page-url>","maxPosts":5,"maxCommentsPerPost":200}` |
| "Check the comments on our newest post only" | Single post | `{"profileUrl":"<page-url>","maxPosts":1,"maxCommentsPerPost":500}` |
| "Anything abusive in our comments?" | Moderation triage | `{"profileUrl":"<your-page>","maxPosts":5,"maxCommentsPerPost":200}` |
| "It returned nothing — try harder" | Blocked | Add `{"proxyConfiguration":{"useApifyProxy":true,"apifyProxyGroups":["RESIDENTIAL"]}}` |
| "Just a quick sample" | Cheap probe | `{"profileUrl":"<page-url>","maxPosts":1,"maxCommentsPerPost":10}` |
| "Post our page's comments to Slack daily" | Scrape + deliver | Above, plus `mcpConnector`, `mcpTool`, `mcpArguments`, on a schedule |
| "File negative comments as Jira issues" | Scrape + deliver | `{"profileUrl":"<your-page>","mcpConnector":"jira","mcpTool":"create_issue","deliveryMode":"perComment"}` |
| "Track comment volume on our page weekly" | Scheduled monitor | Same input on a [schedule](https://docs.apify.com/platform/schedules) |

**Should NOT route here:** **private profiles, friends-only posts or groups** · **commenter
profile URLs, user IDs, emails or phone numbers** · **replies** to comments · **reactions,
likes, shares or timestamps** · **keyword or hashtag search** across Facebook · **several
pages** in one run · a **complete export** of a thread · **building a marketing or outreach
list** from commenters · scraping an individual private person's activity.

***

### Agent Execution & Routing Logic

```
Does the user want COMMENTS from a PUBLIC Facebook page?
├── NO → not this Actor.
│        private profile / group / friends-only → not reachable, ever
│        commenter contact details              → not collected, by design
│        reactions / likes / timestamps         → not returned
│        search by keyword or hashtag           → no search input
│        another platform                       → use that platform's Actor
│
└── YES
    │
    ├── Is the page PUBLIC?
    │     ├── unsure → try once; "No posts found" means it is not publicly readable
    │     └── no    → stop. Nothing here will reach it.
    │
    ├── ALWAYS set proxyConfiguration → Apify Proxy, RESIDENTIAL
    │     (without this, expect partial or zero results)
    │
    ├── How many posts?
    │     ├── newest only  → maxPosts: 1
    │     ├── recent       → maxPosts: 3-5      (default 3)
    │     └── deeper       → up to 50, but cost and block risk rise sharply
    │
    ├── How many comments per post?
    │     ├── a sample     → 10-50
    │     └── the thread   → up to 500 (a CEILING; Facebook may serve fewer)
    │
    ├── Is this THEIR OWN page?
    │     ├── yes → strongest footing: moderation and analytics on their own content
    │     └── no  → confirm they have a lawful basis before storing anything
    │
    └── Should results land in another app?
          ├── yes → mcpConnector + mcpTool + deliveryMode
          │           NOTE: fires once PER POST, not per run
          │           one digest per post → summary
          │           long thread         → chunked
          │           one call per comment→ perComment (watch rate limits)
          └── no  → leave mcpConnector empty; dataset only
```

***

### Cost Control & Pricing Transparency

This Actor bills **per comment saved** (pay-per-event). You pay for rows that reach your
dataset, so a blocked run that returns nothing costs nothing in event charges. Current
per-comment rates are on the
[Actor's Apify page](https://apify.com/techforce.global/facebook-public-comments); the Console
shows the live total while a run is in progress.

| Choice | Effect on cost |
|---|---|
| `maxPosts` | Each post is a separate page load — the main driver of run *time*. |
| `maxCommentsPerPost` | The main driver of *event* charges. It is a ceiling; you're only charged for comments actually found. |
| Residential proxy | Adds proxy cost, but without it you may pay for a run that returns nothing useful. Worth it. |
| Being blocked | Costs run time but few or no event charges — the failure mode is cheap, which is small consolation. |

**Keeping runs predictable:**

1. **First run: `maxPosts: 1`, `maxCommentsPerPost: 10`, residential proxy on.** Confirm the
   page is readable at all before scaling anything.
2. **Then scale `maxCommentsPerPost` before `maxPosts`.** More comments from fewer posts is
   cheaper and less block-prone than the reverse.
3. **Always set a spend cap on unattended and scheduled runs** — `maxTotalChargeUsd` on the API
   call, or the run limit in the Console.
4. **Free Apify plans stop at 5 comments per post**, which makes free runs a connectivity test
   rather than a data pull.

***

### Troubleshooting

| # | Symptom you see | Most likely cause | Fix |
|:--|---|---|---|
| 1 | Run ends immediately, empty dataset, log says `profileUrl is missing` | `profileUrl` was not supplied. It is the one **required** field | Pass a public page URL. Do not retry unchanged. |
| 2 | Log says `profileUrl must be a valid URL` | The value does not start with `http` | Include the scheme: `https://www.facebook.com/<page>`. |
| 3 | You forgot to set `profileUrl` and got comments about Mark Zuckerberg | The schema default and prefill are `https://www.facebook.com/zuck` | Always pass `profileUrl` explicitly from API, SDK and MCP calls. |
| 4 | `No posts found`, empty dataset | The page is gated, private, blocked from this IP, or has no visible posts | Enable a **residential** proxy and retry once. If it persists, the page is not publicly readable — stop. |
| 5 | Far fewer comments than the thread visibly shows | Facebook serves a fraction of a thread to anonymous visitors, and the Actor clicks "View more comments" a limited number of times | Expected. `maxCommentsPerPost` is a **ceiling, not a quota**. Treat every run as a sample. |
| 6 | One post is missing from an otherwise good run | That post was blocked or removed; the log names it and the run continues | Expected and partial. The other posts are unaffected. |
| 7 | Repeated post-unreachable warnings across the run | The IP is being throttled or blocked | Switch to a residential proxy, lower `maxPosts`, and space runs further apart. |
| 8 | Exactly 5 comments per post, every time | Free Apify plan cap | Upgrade the plan. Retrying will not change it — the log prints the cap notice. |
| 9 | A row's `comment_text` looks like the post body rather than a comment | Extraction reads comment blocks from the rendered page, and Facebook marks some non-comment blocks the same way | Filter obvious outliers on ingest. Comparing `comment_username` against the page's own name catches most of them. |
| 10 | The same comment appears twice | Comments are not de-duplicated across posts, and a shared or cross-posted item can appear under two permalinks | De-duplicate on `comment_username` + `comment_text` + `post_url` in your consumer. |
| 11 | No commenter profile link or user ID in the output | **By design.** The Actor collects three fields only and deliberately does not collect profile URLs, user IDs or contact details | Not a defect — it is a data-minimisation choice. See Compliance. |
| 12 | Run takes much longer than expected | `maxPosts` drives run time: each post is a separate page load with a fixed settle wait, and the profile scroll runs up to 15 passes | Lower `maxPosts`. Prefer more comments from fewer posts. |
| 13 | Connector configured but nothing delivered | `mcpTool` is empty — the log says a connector is selected but no tool name was provided | Set `mcpTool`, or clear `mcpConnector`. The dataset is saved either way. |
| 14 | Connector starts erroring partway through a multi-post run | Delivery fires **once per post** (once per comment in `perComment`), so a multi-post run makes many calls | Switch to `summary` or `chunked`, or lower `maxPosts`. |
| 15 | Delivered comments are fewer than the connector expected | Only comments that actually reached the dataset are delivered, so a free-plan cap applies to delivery too | Expected, and deliberate — the connector never receives rows the dataset was not allowed to keep. |

#### Diagnostic checklist before opening an issue

1. **Check the page in a logged-out browser first.** Open it in a private window. If you cannot see the posts and comments there, the Actor cannot either — that is the ceiling on what anonymous access reaches.
2. **Confirm the run's status.** `SUCCEEDED` with zero items is a valid outcome here, not a crash.
3. **Probe small:** `{"profileUrl":"<url>","maxPosts":1,"maxCommentsPerPost":10}` with a residential proxy on. If that returns comments, the pipeline works and the issue is scale or blocking.
4. **Try a residential proxy** before concluding a page is unreadable. The proxy defaults to **off**, and datacenter IPs are the most common cause of an empty run.
5. **Read the log for which failure it was.** "No posts found", "could not open <post>" and the free-plan cap notice are three different problems needing three different responses.

If it survives all five, open an **Issues** ticket with the **run ID**, the **exact input JSON**, and what you expected.

***

### FAQ

#### Setup & access

**Do I need a Facebook account, app, or API key?**

No. You need an **Apify** account and API token only. The Actor accepts no Facebook credentials and uses no account — it reads what a logged-out visitor sees. If any Actor asks you to hand over your Facebook login, treat that as a red flag, including this one.

**Is this the official Meta Graph API?**

No. This is an independent Actor, not affiliated with, endorsed by, or sponsored by Meta. The sanctioned route is the [Graph API](https://developers.facebook.com/), which is the better option if you administer the page.

**Do I need a proxy?**

The proxy input defaults to **off**, but a **residential** proxy is strongly recommended. Datacenter IPs are the single most common reason a run comes back empty.

**Can I plug it into Claude, Cursor, or a LangChain agent?**

Yes — it is a native MCP tool:

`claude mcp add --transport http apify "https://mcp.apify.com/?tools=techforce.global/facebook-public-comments"`

#### Scope & input

**Can I scrape a private profile, a group, or a friends-only post?**

No. Public pages and public profiles only, and only the posts and comments Facebook shows to an anonymous visitor.

**Can I give it a single post URL instead of a page?**

Not directly. The input is a page or profile URL, and the Actor discovers recent posts from it. To narrow the scope to effectively one post, set `maxPosts: 1`.

**Can I search comments by keyword?**

No. There is no search input. Scrape the page and filter `comment_text` yourself.

**How many posts and comments can one run cover?**

`maxPosts` accepts 1–50 (default 3) and `maxCommentsPerPost` accepts 1–500 (default 20). Both are ceilings — Facebook decides how much it actually serves.

**Do I get replies to comments?**

Only where Facebook renders them in the same thread view as the comments themselves. There is no separate reply field and no guaranteed nesting — the output is a flat list.

**Are comments returned in chronological order?**

No. Order follows however Facebook renders the thread, which is usually relevance-ranked rather than chronological, and there is no timestamp field to re-sort by.

#### Output & data

**What exactly do I get per comment?**

Three fields: `comment_username`, `comment_text` and `post_url`. That is the whole output, and it is a deliberate data-minimisation choice.

**Why is there no commenter profile URL, user ID, or timestamp?**

Because collecting them would materially increase the privacy exposure for people who are not the subject of your research. A display name plus text is enough for sentiment, volume and moderation triage; a resolvable identifier turns the dataset into a profile-building tool.

**Can I match comments to specific individuals?**

Not reliably, and by design. Display names are not unique and there is no identifier attached. If your use case requires identifying individuals, this Actor is the wrong tool and you should re-examine the lawful basis for it.

**Is the output ready for sentiment analysis?**

Yes — `comment_text` is the comment body as posted. Feed it straight into a model, and consider dropping `comment_username` on ingest, which removes most of the compliance obligations at no analytical cost.

#### Cost & runtime

**How is this billed?**

Pay-per-event: **one event per comment saved to the dataset**. You are charged for rows you actually receive, so a blocked run that returns nothing costs nothing in event charges. Current rates are on the Actor's Apify page.

**Does a blocked or empty run still cost money?**

No event charges, since nothing was saved. It still consumes platform run time, which is why the cheap probe run is worth doing first.

**What does the free plan give me?**

5 comments per post, and no event charges. That makes a free run a connectivity test rather than a data pull — enough to confirm a page is readable before you upgrade.

**How do I guarantee an agent never overspends?**

Pass `maxTotalChargeUsd` as a query parameter on the run endpoint — a hard per-execution ceiling. Always set one on unattended and scheduled runs.

**What makes a run slow?**

`maxPosts`, mostly. Each post is a separate page load with a fixed settle wait, and the initial profile scroll runs up to 15 passes before it gives up. More comments from fewer posts is both faster and less block-prone.

***

### Companion machine-readable files

| File | What it defines |
|---|---|
| [`.actor/input_schema.json`](.actor/input_schema.json) | Every input, its type, default and bounds |
| [`.actor/dataset_schema.json`](.actor/dataset_schema.json) | The three output fields and the two Console views |
| [`.actor/output_schema.json`](.actor/output_schema.json) | Where the run's output is exposed |
| [`.actor/actor.json`](.actor/actor.json) | Actor identity, memory bounds and storage wiring |

> **If this page and the schema files disagree, the schema files win.** They are what the
> platform validates against at run time; this page is documentation and can lag a release.

***

### Related Actors by Techforce Global

| Actor | Best for |
|---|---|
| **This Actor** | **Comment threads** under a public Facebook page's posts |
| [Facebook Company Page Scraper](https://apify.com/techforce.global/facebook-company-page) | A page's own **business details** — no personal data |
| [Website Contact Scraper](https://apify.com/techforce.global/website-contact-scraper) | Business contact details from a company's own site |
| [Smart Event Scraper](https://apify.com/techforce.global/smart-event-scraper) | Event listings across six platforms — no personal data |
| [EventsEye Scraper](https://apify.com/techforce.global/events-eye-scraper) | Trade shows with organizer business contacts |

If your goal is **business** information rather than what individuals said, prefer the Facebook
Company Page Scraper — it returns no personal data and carries none of the obligations above.

> Browse the full catalogue at **[scraper.techforce.global](https://scraper.techforce.global/)**.

***

### Compliance & Data Privacy

**Read this section before your first run.** For most Actors this is a formality. For this one
it is the operating manual.

- **The output is personal data. There is no reading of the law under which it isn't.**
  `comment_username` is an identifiable person's name and `comment_text` is content they
  authored. Under **GDPR / UK GDPR** you become a **data controller** the moment you store it,
  with the full obligation set: a lawful basis, a retention period, a response route for
  access and erasure requests, and — for any substantial or systematic collection — a
  **Legitimate Interests Assessment** or a **DPIA**. The **CCPA/CPRA**, Brazil's **LGPD** and
  India's **DPDP Act 2023** impose parallel duties.

- **Comments contain special-category data, and you cannot filter it in advance.** People
  volunteer political opinions, health conditions, religious belief and sexual orientation in
  comment threads. That is **Article 9** data, which normally requires explicit consent you do
  not have. You cannot know which rows contain it until after you've collected them — so the
  safe posture is a short retention period and tight access control on the whole dataset.

- **"Publicly accessible" is not a lawful basis.** This is the single most common mistake.
  A comment being visible to anyone does not make processing it lawful, and EU regulators have
  repeatedly rejected that argument. You still need a basis, and it must survive a balancing
  test against the commenter's reasonable expectations — someone replying to a brand post does
  not expect to enter a third-party database.

- **Meta's Terms of Service prohibit automated collection.** Facebook's terms and its
  `robots.txt` disallow scraping without written permission, and Meta enforces this — including
  civil action. **This Actor does not remove that risk; it is a risk you accept by running it.**
  No configuration makes the collection ToS-compliant.

- **Your own page is much stronger ground than someone else's.** Monitoring and moderating
  comments on a page **you control** has an obvious legitimate interest, sits within what
  commenters expect, and puts you on the right side of most of the above. Third-party pages,
  competitor monitoring, and anything resembling surveillance of individuals do not.

- **Never use this to build a contact or marketing list.** The Actor deliberately omits profile
  URLs, user IDs and contact details so it *can't* be used that way. Re-identifying commenters
  from their display names and then contacting them would breach **CAN-SPAM**, **CASL**,
  **ePrivacy/PECR** and the **DPDP Act** — and the GDPR purpose-limitation principle on top.

- **Do not scrape individual private people.** The Actor is built for pages. Pointing it at a
  private individual's profile to compile their activity is targeted surveillance, is unlawful
  in most jurisdictions, and is not a use this Actor supports.

- **Minimise, and set a retention clock.** Keep `maxPosts` and `maxCommentsPerPost` at what
  your actual question requires. Aggregate to sentiment scores or counts and **discard the raw
  names and text** as soon as you can — an aggregate is usually what you needed, and it takes
  you out of scope.

- **No credentials, no account, no private content.** The Actor accepts no Facebook login and
  accesses only what an anonymous visitor sees. If you are ever asked to supply Facebook
  credentials to an Actor, that is a red flag — including for this one.

***

### 🆘 Support & Custom Pipeline Engineering

Need automated multi-city scheduled feeds, webhook enrichment, or enterprise data warehouse syncs?

- **Email**: bhavin.shah@techforceglobal.com
- **Custom Enterprise Integrations**: [Book a 15-Minute Technical Consultation](https://calendly.com/techforce-global/intro-meeting)
- **Maintained by**: [Techforce Global](https://www.techforceglobal.com) — Specialists in High-Performance Web Scrapers and Agentic Workflows.

***

<sub>Built and maintained by **Techforce Global**. Accesses only content visible to an anonymous
visitor — no credentials, no private profiles, no groups. **Output contains personal data.**
You are the data controller for anything you store, and you are responsible for complying with
Meta's Terms of Service and with the data-protection law of your jurisdiction. Best-effort by
design: Facebook limits automated access, and partial or empty results are expected.</sub>

***

### 🏷️ Structured data for search & AI discovery

`SoftwareApplication` describes the Actor; `FAQPage` wraps the FAQ above so those answers are
eligible for rich results, matching it question-for-question.

```json
{
  "@context": "https://schema.org/",
  "@type": "SoftwareApplication",
  "name": "Facebook Public Comment Tracker",
  "alternateName": "Facebook Public Comment Tracker — Comment Extraction from Public Pages & Posts",
  "applicationCategory": "BusinessApplication",
  "applicationSubCategory": "Web Scraping / Social Listening",
  "operatingSystem": "Any (cloud-hosted on Apify)",
  "url": "https://apify.com/techforce.global/facebook-public-comments",
  "description": "Collects public comments from posts on a public Facebook page or profile, returning the commenter's display name, the comment text and the post permalink — three fields, with no commenter profile URLs, user IDs or contact details collected. Accesses only what an anonymous visitor can see, with optional delivery into Notion, Slack, Jira, Linear or any MCP connector. Output contains personal data and the operator is the data controller.",
  "author": {
    "@type": "Organization",
    "name": "Techforce Global",
    "url": "https://www.techforceglobal.com/"
  },
  "provider": {
    "@type": "Organization",
    "name": "Apify",
    "url": "https://apify.com/"
  },
  "offers": {
    "@type": "Offer",
    "category": "Pay per event",
    "description": "Billed per comment saved to the dataset. Current rates are shown on the Actor's Apify page.",
    "url": "https://apify.com/techforce.global/facebook-public-comments"
  },
  "featureList": [
    "Comment threads from a public page's recent posts",
    "Commenter display name, comment text and post permalink",
    "No credentials accepted and no account used - anonymous access only",
    "No commenter profile URLs, user IDs or contact details collected, by design",
    "Configurable post and per-post comment ceilings",
    "Residential proxy support",
    "Hidden comments expanded by clicking through the thread's View more control",
    "Charged per comment saved, so a blocked run costs nothing in event charges",
    "Free plan returns 5 comments per post as a connectivity check",
    "Delivery is capped to what the dataset kept, so a connector never receives withheld rows",
    "Optional MCP delivery to Notion, Slack, Jira, Linear and more",
    "Chunked delivery mode keeps long threads under connector size and timeout caps",
    "Two Console dataset views"
  ],
  "isAccessibleForFree": false,
  "softwareRequirements": "Apify account and API token",
  "softwareHelp": {
    "@type": "CreativeWork",
    "url": "https://apify.com/techforce.global/facebook-public-comments"
  },
  "keywords": "Facebook comment scraper, social listening, brand monitoring, sentiment analysis input, public page comments, comment extraction, moderation triage, MCP connector"
}
```

```json
{
    "@context": "https://schema.org/",
    "@type": "FAQPage",
    "mainEntity": [
        {
            "@type": "Question",
            "name": "Do I need a Facebook account, app, or API key?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "No. You need an Apify account and API token only. The Actor accepts no Facebook credentials and uses no account - it reads what a logged-out visitor sees. If any Actor asks you to hand over your Facebook login, treat that as a red flag, including this one."
            }
        },
        {
            "@type": "Question",
            "name": "Is this the official Meta Graph API?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "No. This is an independent Actor, not affiliated with, endorsed by, or sponsored by Meta. The sanctioned route is the Graph API at developers.facebook.com, which is the better option if you administer the page."
            }
        },
        {
            "@type": "Question",
            "name": "Do I need a proxy?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "The proxy input defaults to off, but a residential proxy is strongly recommended. Datacenter IPs are the single most common reason a run comes back empty."
            }
        },
        {
            "@type": "Question",
            "name": "Can I plug it into Claude, Cursor, or a LangChain agent?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "Yes - it is a native MCP tool. Add it with: claude mcp add --transport http apify \"https://mcp.apify.com/?tools=techforce.global/facebook-public-comments\""
            }
        },
        {
            "@type": "Question",
            "name": "Can I scrape a private profile, a group, or a friends-only post?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "No. Public pages and public profiles only, and only the posts and comments Facebook shows to an anonymous visitor."
            }
        },
        {
            "@type": "Question",
            "name": "Can I give it a single post URL instead of a page?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "Not directly. The input is a page or profile URL, and the Actor discovers recent posts from it. To narrow the scope to effectively one post, set maxPosts to 1."
            }
        },
        {
            "@type": "Question",
            "name": "Can I search comments by keyword?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "No. There is no search input. Scrape the page and filter comment_text yourself."
            }
        },
        {
            "@type": "Question",
            "name": "How many posts and comments can one run cover?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "maxPosts accepts 1-50 (default 3) and maxCommentsPerPost accepts 1-500 (default 20). Both are ceilings - Facebook decides how much it actually serves."
            }
        },
        {
            "@type": "Question",
            "name": "Do I get replies to comments?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "Only where Facebook renders them in the same thread view as the comments themselves. There is no separate reply field and no guaranteed nesting - the output is a flat list."
            }
        },
        {
            "@type": "Question",
            "name": "Are comments returned in chronological order?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "No. Order follows however Facebook renders the thread, which is usually relevance-ranked rather than chronological, and there is no timestamp field to re-sort by."
            }
        },
        {
            "@type": "Question",
            "name": "What exactly do I get per comment?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "Three fields: comment_username, comment_text and post_url. That is the whole output, and it is a deliberate data-minimisation choice."
            }
        },
        {
            "@type": "Question",
            "name": "Why is there no commenter profile URL, user ID, or timestamp?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "Because collecting them would materially increase the privacy exposure for people who are not the subject of your research. A display name plus text is enough for sentiment, volume and moderation triage; a resolvable identifier turns the dataset into a profile-building tool."
            }
        },
        {
            "@type": "Question",
            "name": "Can I match comments to specific individuals?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "Not reliably, and by design. Display names are not unique and there is no identifier attached. If your use case requires identifying individuals, this Actor is the wrong tool and you should re-examine the lawful basis for it."
            }
        },
        {
            "@type": "Question",
            "name": "Is the output ready for sentiment analysis?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "Yes - comment_text is the comment body as posted. Feed it straight into a model, and consider dropping comment_username on ingest, which removes most of the compliance obligations at no analytical cost."
            }
        },
        {
            "@type": "Question",
            "name": "How is this billed?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "Pay-per-event: one event per comment saved to the dataset. You are charged for rows you actually receive, so a blocked run that returns nothing costs nothing in event charges. Current rates are on the Actor's Apify page."
            }
        },
        {
            "@type": "Question",
            "name": "Does a blocked or empty run still cost money?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "No event charges, since nothing was saved. It still consumes platform run time, which is why the cheap probe run is worth doing first."
            }
        },
        {
            "@type": "Question",
            "name": "What does the free plan give me?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "5 comments per post, and no event charges. That makes a free run a connectivity test rather than a data pull - enough to confirm a page is readable before you upgrade."
            }
        },
        {
            "@type": "Question",
            "name": "How do I guarantee an agent never overspends?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "Pass maxTotalChargeUsd as a query parameter on the run endpoint - a hard per-execution ceiling. Always set one on unattended and scheduled runs."
            }
        },
        {
            "@type": "Question",
            "name": "What makes a run slow?",
            "acceptedAnswer": {
                "@type": "Answer",
                "text": "maxPosts, mostly. Each post is a separate page load with a fixed settle wait, and the initial profile scroll runs up to 15 passes before it gives up. More comments from fewer posts is both faster and less block-prone."
            }
        }
    ]
}
```

# Actor input Schema

## `profileUrl` (type: `string`):

Public Facebook profile or page URL (e.g. https://www.facebook.com/{username})

## `maxPosts` (type: `integer`):

Maximum number of posts to scan from the profile

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

Maximum number of comments to extract per post

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

Optional proxy settings.

## `mcpConnector` (type: `string`):

Optionally deliver each post's scraped comments into a connector you have authorized — Notion, Slack, Jira, GitHub, Linear, Airtable, or any MCP-compatible connector. Leave empty to only save results to the dataset.

## `deliveryMode` (type: `string`):

How to deliver each post's comments to the connector: 'summary' (one call with all of a post's comments joined together), 'chunked' (split a long comment thread across a few calls so services like Notion never time out), 'perComment' (one call per individual comment), or 'none' (save to dataset only).

## `mcpTool` (type: `string`):

Name of the tool to call on the connector (e.g. 'create\_page' for Notion, 'send\_message' for Slack, 'create\_issue' for Jira/GitHub). If unsure, run once with a connector selected — the log lists the connector's available tools.

## `mcpArguments` (type: `object`):

Arguments passed to the connector tool. String values support {placeholders}. In 'summary' mode: {postUrl}, {commentCount}, {comments} (all comments joined as "name: text" lines) and {message} (the rendered template below). In 'chunked' mode: same as summary but {comments} holds one part of the thread and {part}/{partCount} give the 1-based part number and total. In 'perComment' mode: {postUrl}, {username}, {text} and {message}. Example for Slack: {"channel": "#comments", "text": "{message}"}.

## `mcpMessageTemplate` (type: `string`):

Optional template rendered and exposed as the {message} placeholder in the tool arguments. Summary example: 'Comments on {postUrl} ({commentCount} total):\n\n{comments}'. Per-comment example: '{username}: {text}'.

## Actor input object example

```json
{
  "profileUrl": "https://www.facebook.com/zuck",
  "maxPosts": 3,
  "maxCommentsPerPost": 20,
  "proxyConfiguration": {
    "useApifyProxy": false
  },
  "deliveryMode": "summary",
  "mcpTool": "",
  "mcpArguments": {},
  "mcpMessageTemplate": ""
}
```

# Actor output Schema

## `overview` (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 = {
    "profileUrl": "https://www.facebook.com/zuck"
};

// Run the Actor and wait for it to finish
const run = await client.actor("techforce.global/facebook-public-comments").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 = { "profileUrl": "https://www.facebook.com/zuck" }

# Run the Actor and wait for it to finish
run = client.actor("techforce.global/facebook-public-comments").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 '{
  "profileUrl": "https://www.facebook.com/zuck"
}' |
apify call techforce.global/facebook-public-comments --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,techforce.global/facebook-public-comments"
        }
    }
}

```

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/fPDFmWk8Mp9mFxOC4/builds/w8iKBUmrHd2nIp8ul/openapi.json
