Facebook Comment Scraper - Public Page Comments, No Login
Pricing
from $2.50 / 1,000 results
Facebook Comment Scraper - Public Page Comments, No Login
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.
Pricing
from $2.50 / 1,000 results
Rating
0.0
(0)
Developer
Techforce Global
Maintained by CommunityActor stats
0
Bookmarked
4
Total users
1
Monthly active users
3 days ago
Last modified
Categories
Share
Facebook Comment Scraper - Comment Threads from Public Pages and Posts, Logged-Out and Without Commenter Identifiers
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 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
maxPostslow, and treat every run as a sample rather than a complete export.
Browse all Actors by Techforce Global at scraper.techforce.global.
Meta Graph API vs. this Actor
| Meta Graph API (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 |
| 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 for current terms before choosing.
AI Discovery & MCP Metadata
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 thecommenter's display name, the comment text and the post permalink. Optional delivery intoNotion, 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. Commenttext can contain Article 9 special-category data (political opinion, health, religion,sexual orientation) written by the commenter. Anyone storing this output is a controllerand 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 Facebookcredentials and no account is required or supplied. Consequently it can only reach contentFacebook 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 contactdetails. 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 runper 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 meansthree 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 capapplies to delivery too.never_blocks_the_dataset: >Delivery runs after the dataset is saved. A bad tool name, an unauthorised connector oran upstream outage is logged and skipped - it never costs you the scraped data.
{"@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
-
Use a residential proxy.
proxyConfigurationis 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. -
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.
-
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. -
profileUrlmust be a public page or profile. Private profiles, friends-only posts and groups are invisible to an anonymous visitor and will simply return nothing. -
One page per run. There is no multi-page input, and no keyword search. Schedule or fan out one run per page.
-
Keep
maxPostslow. 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. -
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.
-
The output has three fields. No timestamps, no like counts, no reaction data, no commenter identifiers. Don't build a pipeline expecting more.
-
Delivery fires once per post, not once per run.
maxPosts: 3insummarymode means three connector calls. Size your connector expectations accordingly. -
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.
-
Treat every output row as personal data from the moment you receive it. See 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
perCommentmode, a run with 3 posts × 20 comments is up to 60 connector calls — check your connector's rate limits first.
Recommended proxy setting
{"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
{"post_url": "https://www.facebook.com/<page>/posts/<post-id>","comment_username": "Jordan Blake","comment_text": "Been using this for two years and the support team is genuinely excellent."}
Values above are illustrative.
comment_usernameis 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, paste a
public page URL, enable Apify Proxy with the RESIDENTIAL group, and click Start.
MCP — add as an agent tool
$claude mcp add apify --transport http https://mcp.apify.com/?actors=techforce.global/facebook-public-comments
Python
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("techforce.global/facebook-public-comments").call(run_input={"profileUrl": "https://www.facebook.com/<your-page>","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
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/<your-page>',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)
curl -X POST "https://api.apify.com/v2/acts/techforce.global~facebook-public-comments/run-sync-get-dataset-items?token=<YOUR_APIFY_TOKEN>" \-H 'Content-Type: application/json' \-d '{"profileUrl": "https://www.facebook.com/<your-page>","maxPosts": 3,"maxCommentsPerPost": 50,"proxyConfiguration": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }}'
cURL — asynchronous with a spend cap
curl -X POST "https://api.apify.com/v2/acts/techforce.global~facebook-public-comments/runs?token=<YOUR_APIFY_TOKEN>&maxTotalChargeUsd=2" \-H 'Content-Type: application/json' \-d '{ "profileUrl": "https://www.facebook.com/<your-page>", "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
{"profileUrl": "https://www.facebook.com/<your-page>","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 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/<your-page>","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 |
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; 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:
- First run:
maxPosts: 1,maxCommentsPerPost: 10, residential proxy on. Confirm the page is readable at all before scaling anything. - Then scale
maxCommentsPerPostbeforemaxPosts. More comments from fewer posts is cheaper and less block-prone than the reverse. - Always set a spend cap on unattended and scheduled runs —
maxTotalChargeUsdon the API call, or the run limit in the Console. - 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
- 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.
- Confirm the run's status.
SUCCEEDEDwith zero items is a valid outcome here, not a crash. - 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. - 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.
- Read the log for which failure it was. "No posts found", "could not open
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, 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 | Every input, its type, default and bounds |
| .actor/dataset_schema.json | The three output fields and the two Console views |
| .actor/output_schema.json | Where the run's output is exposed |
| .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 | A page's own business details — no personal data |
| Website Contact Scraper | Business contact details from a company's own site |
| Smart Event Scraper | Event listings across six platforms — no personal data |
| EventsEye 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.
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_usernameis an identifiable person's name andcomment_textis 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.txtdisallow 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
maxPostsandmaxCommentsPerPostat 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
- Maintained by: Techforce Global — Specialists in High-Performance Web Scrapers and Agentic Workflows.
🏷️ 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.
{"@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"}
{"@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."}}]}

