Facebook Post & Group Comment Thread Extractor
Get comments and nested reply threads from public Facebook posts, Watch videos, photos, and group posts, with per-reaction-type counts, author details, and date filtering. No login or cookies required.
Input schema
Input fields, types, required flags, descriptions, defaults, and prefills come from the published definition. Prefill examples are distinct from defaults.
| Field | Type | Required | Description |
|---|---|---|---|
startUrls | array | required | Facebook post, photo, reel, video, Watch, or public group post URLs (one or more). Comment permalinks (URLs containing ?comment_id=) are accepted and resolved to their post; legacy story.php, permalink.php and share links are normalized automatically. Most public reels and videos are supported; a minority restricted by Facebook return no thread and are reported. |
maxItems | integer | optional | Maximum number of comment rows (including replies) to collect per URL. The run also stops when Facebook has no more comments or replies to serve. |
onlyCommentsNewerThan | string | optional | Limit results to comments posted after this date. Accepts YYYY-MM-DD, a full ISO 8601 timestamp (e.g. 2024-06-15T12:00:00Z), or a relative value like '1 day', '2 weeks', '3 months', '1 year'. When set, comments are fetched newest-first so the filter can stop as soon as an older comment is reached. Leave blank to disable date filtering. |
Show all input fields
| Field | Type | Required | Description |
|---|---|---|---|
startUrls | array | required | Facebook post, photo, reel, video, Watch, or public group post URLs (one or more). Comment permalinks (URLs containing ?comment_id=) are accepted and resolved to their post; legacy story.php, permalink.php and share links are normalized automatically. Most public reels and videos are supported; a minority restricted by Facebook return no thread and are reported. |
maxItems | integer | optional | Maximum number of comment rows (including replies) to collect per URL. The run also stops when Facebook has no more comments or replies to serve. |
onlyCommentsNewerThan | string | optional | Limit results to comments posted after this date. Accepts YYYY-MM-DD, a full ISO 8601 timestamp (e.g. 2024-06-15T12:00:00Z), or a relative value like '1 day', '2 weeks', '3 months', '1 year'. When set, comments are fetched newest-first so the filter can stop as soon as an older comment is reached. Leave blank to disable date filtering. |
commentsMode | string | optional | Which comment view to scrape: MOST_RELEVANT (Facebook's ranked view), NEWEST (all comments, newest first), or ALL (Facebook's unfiltered ranked view, including comments its ranked view may hide). |
includeNestedComments | boolean | optional | If true, also scrape reply rows under top-level comments (with parent/reply metadata). If false, only top-level comments are collected (faster). |
maxReplyDepth | integer | optional | How deep into reply threads to collect: 1 = direct replies to top-level comments only, 2 or more = also include deeper nested replies. Facebook serves reply threads with up to two nesting levels to anonymous visitors. |
Download the published input schema
View complete JSON
{
"description": "Extract public comments and reply threads from Facebook posts, photos, reels, videos, and public group posts. Returns comment text, author details, per-reaction-type counts, timestamps, reply context, and the post's own comment totals. No login or cookies required.",
"properties": {
"commentsMode": {
"default": "ALL",
"description": "Which comment view to scrape: MOST_RELEVANT (Facebook's ranked view), NEWEST (all comments, newest first), or ALL (Facebook's unfiltered ranked view, including comments its ranked view may hide).",
"enum": [
"ALL",
"NEWEST",
"MOST_RELEVANT"
],
"enumTitles": [
"All comments (Facebook's unfiltered view)",
"Newest first",
"Most relevant (Facebook's ranked view)"
],
"prefill": "MOST_RELEVANT",
"title": "Comment ordering",
"type": "string"
},
"includeNestedComments": {
"default": true,
"description": "If true, also scrape reply rows under top-level comments (with parent/reply metadata). If false, only top-level comments are collected (faster).",
"prefill": true,
"title": "Include replies",
"type": "boolean"
},
"maxItems": {
"default": 100,
"description": "Maximum number of comment rows (including replies) to collect per URL. The run also stops when Facebook has no more comments or replies to serve.",
"maximum": 10000,
"minimum": 1,
"prefill": 5,
"sectionCaption": "Limits",
"title": "Max comments per URL",
"type": "integer"
},
"maxReplyDepth": {
"default": 1,
"description": "How deep into reply threads to collect: 1 = direct replies to top-level comments only, 2 or more = also include deeper nested replies. Facebook serves reply threads with up to two nesting levels to anonymous visitors.",
"maximum": 5,
"minimum": 1,
"prefill": 1,
"title": "Max reply nesting depth",
"type": "integer"
},
"onlyCommentsNewerThan": {
"description": "Limit results to comments posted after this date. Accepts YYYY-MM-DD, a full ISO 8601 timestamp (e.g. 2024-06-15T12:00:00Z), or a relative value like '1 day', '2 weeks', '3 months', '1 year'. When set, comments are fetched newest-first so the filter can stop as soon as an older comment is reached. Leave blank to disable date filtering.",
"editor": "textfield",
"title": "Only comments newer than",
"type": "string"
},
"startUrls": {
"description": "Facebook post, photo, reel, video, Watch, or public group post URLs (one or more). Comment permalinks (URLs containing ?comment_id=) are accepted and resolved to their post; legacy story.php, permalink.php and share links are normalized automatically. Most public reels and videos are supported; a minority restricted by Facebook return no thread and are reported.",
"editor": "requestListSources",
"prefill": [
{
"url": "https://www.facebook.com/NASA/posts/pfbid025kwyoBjhFGUC22fC4Sies56D5xvd65ZHR5PYjHhc7XSzqGsxuWq2uDVriZNxWbeol"
}
],
"sectionCaption": "Input",
"sectionDescription": "Provide one or more public Facebook URLs to scrape comments from.",
"title": "Facebook URLs",
"type": "array"
}
},
"required": [
"startUrls"
],
"schemaVersion": 1,
"title": "Facebook Comment Thread Extractor",
"type": "object"
}
Output schema
Published result links and storage locations. This schema is not an exhaustive contract for every field in a dataset record.
| Field | Type | Required | Description |
|---|---|---|---|
comments | string | optional | Dataset containing all scraped Facebook comments |
Download the published output schema
View complete JSON
{
"actorOutputSchemaVersion": 1,
"description": "One record per Facebook comment or reply: text, author details, timestamp, per-reaction-type counts, reply/thread context, attachment and mention data, plus the parent post's name, text and comment totals.",
"properties": {
"comments": {
"description": "Dataset containing all scraped Facebook comments",
"template": "{{links.apiDefaultDatasetUrl}}/items",
"title": "Comments Data",
"type": "string"
}
},
"title": "Facebook Post & Group Comment Thread Extractor Output"
}
Dataset schema
Published dataset views and any declared field definitions. A view can select only a subset of the returned record fields.
Download the published dataset schema
View complete JSON
{
"actorSpecification": 1,
"title": "Facebook Comments Data",
"views": {
"detailed": {
"display": {
"component": "table",
"properties": {
"commentId": {
"format": "text",
"label": "Comment ID"
},
"commentUrl": {
"format": "link",
"label": "Comment URL"
},
"commentsCount": {
"format": "number",
"label": "Replies"
},
"date": {
"format": "text",
"label": "Date"
},
"facebookUrl": {
"format": "link",
"label": "Story URL"
},
"id": {
"format": "text",
"label": "Relay ID"
},
"inputUrl": {
"format": "link",
"label": "Input URL"
},
"likesCount": {
"format": "text",
"label": "Likes"
},
"profileId": {
"format": "text",
"label": "Profile ID"
},
"profileName": {
"format": "text",
"label": "Author"
},
"text": {
"format": "text",
"label": "Comment"
},
"threadingDepth": {
"format": "number",
"label": "Depth"
}
}
},
"title": "Full Comment Details",
"transformation": {
"fields": [
"profileName",
"profileId",
"text",
"date",
"likesCount",
"commentsCount",
"threadingDepth",
"commentId",
"id",
"facebookUrl",
"commentUrl",
"inputUrl"
]
}
},
"overview": {
"display": {
"component": "table",
"properties": {
"commentUrl": {
"format": "link",
"label": "URL"
},
"commentsCount": {
"format": "number",
"label": "Replies"
},
"date": {
"format": "text",
"label": "Date"
},
"likesCount": {
"format": "text",
"label": "Likes"
},
"profileName": {
"format": "text",
"label": "Author"
},
"text": {
"format": "text",
"label": "Comment"
},
"threadingDepth": {
"format": "number",
"label": "Depth"
}
}
},
"title": "Comments Overview",
"transformation": {
"fields": [
"profileName",
"text",
"date",
"likesCount",
"commentsCount",
"threadingDepth",
"commentUrl"
]
}
}
}
}
Key-value schema
Published key-value store definitions, when provided by this build.
This definition is not present in the default published build. See the published README for available documentation.
Published README
Read the full published documentation
Facebook Post & Group Comment Thread Extractor
Get public comments and full reply threads from Facebook posts, photos, and public group posts. Returns comment text, author details, per-reaction-type counts, timestamps, attachment and mention data, plus the post's own comment totals — no login or cookies required.
What this actor does
- Scrapes comments from public Facebook posts, photos, reels, videos, and public group posts, with full pagination (thousands of comments per post when Facebook serves them)
- Reels and videos are followed through Facebook's canonical video permalink, with a strict check that the returned thread belongs to the requested video
- Follows reply threads and includes nested replies (direct replies plus deeper nesting when Facebook returns it)
- Three comment orderings: Facebook's ranked view, all comments, or newest first
- Captures author details (name, profile picture, profile URL, ID), reaction totals and a per-reaction-type breakdown
- Surfaces the parent post's context on every row: page name, post text, Facebook's total comment count, and the count visible to anonymous visitors
- Filters results to comments posted after a given date
reactionBreakdown,attachmentType,hashtags,mentions,groupCommentInfoand similar optional fields are only added when Facebook's data carries them
Input
| Field | Type | Default | Description |
|---|---|---|---|
startUrls |
array | – | Required. Facebook post, photo, or public group post URLs. Comment permalinks (?comment_id=) are resolved to their post; legacy story.php, permalink.php and share links are normalized automatically |
maxItems |
integer | 100 |
Maximum number of comment rows (including replies) per URL; 1–10,000 |
onlyCommentsNewerThan |
string | – | Date filter: YYYY-MM-DD, full ISO 8601, or relative (1 day, 2 weeks, 3 months, 1 year). Comments are fetched newest-first so pagination stops early |
commentsMode |
string | ALL |
Comment ordering: ALL (Facebook's unfiltered view), NEWEST (newest first), or MOST_RELEVANT (Facebook's ranked view) |
includeNestedComments |
boolean | true |
Also collect reply rows under top-level comments (with parent/reply metadata). Turn off for faster, top-level-only runs |
maxReplyDepth |
integer | 1 |
Reply nesting depth to collect: 1 = direct replies only, 2+ also includes deeper nested replies; 1–5 |
At least one URL in startUrls is required. Provide URLs as plain strings, { "url": "..." } objects, or several URLs separated by spaces/newlines in one string.
Supported URL formats
- Posts:
https://www.facebook.com/PageName/posts/1234567890 - Posts (pfbid):
https://www.facebook.com/PageName/posts/pfbid0... - Legacy permalinks:
story.php?story_fbid=...&id=...,permalink.php?...(normalized automatically) - Photos:
https://www.facebook.com/photo?fbid=1234567890,photo.php?fbid=...,PageName/photos/... - Reels:
https://www.facebook.com/reel/1234567890(resolved through Facebook's video permalink) - Videos:
https://www.facebook.com/PageName/videos/1234567890,https://www.facebook.com/watch?v=1234567890 - Public group posts:
https://www.facebook.com/groups/groupname/permalink/1234567890/,groups/<id>/posts/<id> - Comment permalinks: any post URL with
?comment_id=...— the parent post's thread is returned - Share links:
https://www.facebook.com/share/p/...(resolved through Facebook's redirect) - Mobile URLs:
m.facebook.com/...links are normalized towww
Some individual videos are restricted by Facebook and do not expose their comment thread to anonymous visitors; the actor reports that per video instead of guessing (see Limitations).
Example input
{
"startUrls": [
{ "url": "https://www.facebook.com/NASA/posts/1234567890" },
{ "url": "https://www.facebook.com/groups/pythondevelopers/posts/28449935087979081/" }
],
"maxItems": 500,
"commentsMode": "NEWEST",
"includeNestedComments": true,
"maxReplyDepth": 2,
"onlyCommentsNewerThan": "3 months"
}
Output
Each dataset row is one comment or reply.
| Field | Type | Description |
|---|---|---|
facebookUrl |
string | URL of the post the comment belongs to |
commentUrl |
string | Direct permalink to the comment |
commentId |
string | Numeric (legacy) comment ID |
id |
string | Internal relay ID |
feedbackId |
string | Feedback ID for the comment |
date |
string | Comment timestamp (ISO 8601, UTC) |
text |
string | Full comment text; [Attachment] for media-only comments |
profilePicture |
string | Author's profile picture URL |
profileId |
string | Author's numeric or pfbid profile ID |
profileName |
string | Author's display name |
profileUrl |
string | Author's profile URL (when Facebook exposes one) |
likesCount |
integer | Total reactions on the comment |
reactionBreakdown |
object | Per-reaction-type counts (like, love, care, haha, wow, sad, angry, other); only reaction types with a non-zero count are included |
threadingDepth |
integer | 0 = top-level comment, 1+ = reply depth |
commentsCount |
integer | Number of replies (0 for replies themselves) |
replyToCommentId |
string | Parent comment's ID; for deep replies where Facebook withholds the direct parent, the thread's top-level comment ID |
directParentCommentId |
string | Facebook's direct parent pointer, when the response includes it |
facebookId |
string | Numeric story/post ID |
inputUrl |
string | The URL exactly as provided in the input |
postTitle |
string | Page name that published the post (kept for integrations) |
pageName |
string | Page name that published the post |
postText |
string | The post's own text (when available) |
postCommentsCount |
integer | Facebook's total comment count for the post |
postVisibleCommentsCount |
integer | Comments Facebook serves to anonymous visitors for the selected ordering |
gender |
string | Author's gender, when Facebook exposes it |
spamDisplayMode |
string | Facebook's own spam classification for the comment |
isDisabled |
boolean | Whether the comment was hidden/removed by moderation |
isHiddenByViewer |
boolean | Whether Facebook hides the comment from anonymous viewers |
attachmentType |
string | gif, sticker, image, video or attachment for media comments |
attachmentUrl |
string | Media URL for attachment comments — rehosted into Apify's key-value store so it does not expire |
attachmentUrlOriginal |
string | Original signed Facebook CDN URL of the attachment (expires after a few days) |
attachmentUrlExpiresAt |
string | Expiry time of the original signed attachment URL (ISO 8601) |
hashtags |
array | Hashtags used in the comment (without #) |
mentions |
array | Profiles mentioned in the comment (without @) |
groupCommentInfo |
object | Group posts only: groupId, isAuthorAnonymous, isAuthorNickname, isAuthorWithMemberProfile |
groupId |
string | Group ID for group-post comments |
Example output
{
"facebookUrl": "https://www.facebook.com/NASA/posts/pfbid025kwyoB...",
"commentUrl": "https://www.facebook.com/NASA/posts/pfbid02BnSBZiZ...?comment_id=809453025548580",
"commentId": "809453025548580",
"id": "Y29tbWVudDoxNDg3MDE3OTEyNzkzNTgwXzgwOTQ1MzAyNTU0ODU4MA==",
"feedbackId": "ZmVlZGJhY2s6MTQ4NzAxNzkxMjc5MzU4MF84MDk0NTMwMjU1NDg1ODA=",
"date": "2026-03-26T23:31:17.000Z",
"text": "Ah I remember the moon landing of 1969 on the eve of my 9th birthday!",
"profileId": "pfbid0246xYyRVsKr1v7nDryWNgA4iynY2GKcEVzuVzx2knUikMNEzUNN5RtWsiX945JRt4l",
"profileName": "Gwen Weidell",
"profileUrl": "https://www.facebook.com/gwen.weidell.9",
"likesCount": 69,
"reactionBreakdown": { "like": 54, "haha": 9, "love": 4, "care": 1, "wow": 1 },
"threadingDepth": 0,
"commentsCount": 31,
"facebookId": "1487017912793580",
"inputUrl": "https://www.facebook.com/NASA/posts/pfbid025kwyoB...",
"postTitle": "NASA - National Aeronautics and Space Administration",
"pageName": "NASA - National Aeronautics and Space Administration",
"postText": "Our Artemis II crew's journey around the Moon is on the horizon...",
"postCommentsCount": 1083,
"postVisibleCommentsCount": 813,
"gender": "FEMALE",
"spamDisplayMode": "none",
"isDisabled": false,
"isHiddenByViewer": false
}
Use cases
- Brand monitoring — track what people say about your brand across public posts
- Market research — analyze audience sentiment and topics at scale (pipe
textinto your own NLP/LLM step) - Community insights — understand how audiences react to news, announcements, or campaigns
- Competitor analysis — monitor comment threads on competitor pages and public groups
- Lead generation — identify engaged users from comment activity
- Moderation triage — use Facebook's own spam/disabled/hidden signals plus reply structure to prioritize review
Tips for best results
- Set
maxItemsper URL — it caps runtime and dataset size; the actor also stops on its own when Facebook runs out of comments - Use
NEWESTfor fresh-comment monitoring — withonlyCommentsNewerThan, pagination stops as soon as an older comment appears, saving requests - Keep
includeNestedCommentson for full threads; turn it off for fast top-level-only exports - Test with 1–2 URLs first, then scale up
- Public content only — posts, photos and groups must be visible without login
Limitations
- Some videos are restricted per video: Facebook serves reel and video comment threads anonymously for most public videos, but a minority return no thread at all; those are reported as "not served to anonymous visitors" instead of returning unrelated content (every returned thread is verified against the requested video id).
- Anonymous visibility ceiling: Facebook serves only part of a post's comments to visitors without a session (for example, a post reporting 1,083 comments served 813 to anonymous viewers). The dataset reports what Facebook actually served;
postCommentsCountvspostVisibleCommentsCountshows the difference, and the run status message notes it. - Some photo pages are login-walled from cloud networks: photo URLs return the photo's own comment thread when it is a standalone photo. When the photo belongs to a post and Facebook blocks the anonymous photo viewer, the actor reports that a logged-in session would be required — paste the post URL that contains the photo to scrape its comments.
- Some authors have no public profile URL; those rows simply omit
profileUrl. - Attachment media (
attachmentUrl) is rehosted so it does not expire; original signed URLs stay inattachmentUrlOriginal. Profile pictures are Facebook CDN links that expire after a few days (per-row avatars are not rehosted — see FAQ). - Private, friends-only, and restricted content cannot be accessed.
- Occasionally Facebook changes its internal comment API; the actor discovers the current API identifiers at runtime and falls back to the last known ones, but comment ordering and reply visibility are always Facebook's decision.
FAQ
Q: Do I need a Facebook account or cookies? A: No. The actor reads public content without any login. Nothing in the input asks for credentials.
Q: Do I need to configure a proxy? A: No. The actor picks its route automatically, starting with a direct connection and escalating only when Facebook blocks it. There is no proxy input.
Q: Why are some comments missing? A: Facebook shows anonymous visitors a filtered view of large threads ("Most relevant" ordering may hide some comments) and withholds some replies. The actor reports what Facebook serves and never fabricates rows.
Q: Can I scrape comments from Reels or videos? A: Yes for most public reels and videos — they are followed through Facebook's own canonical video permalink and the returned thread is verified to match the requested video. A minority of videos are restricted by Facebook and return no thread to anonymous visitors; those are reported clearly instead of returning unrelated comments.
Q: I passed a photo URL and got 0 results. Why? A: Facebook serves some photo pages only to logged-in sessions (this depends on the network the actor runs from). When that happens the actor says so; paste the post URL that contains the photo instead — post URLs are always supported.
Q: How many comments can I scrape per post?
A: Up to maxItems (10,000 by default max), and often Facebook's own visibility limit comes first. Exploding threads of thousands of comments are paginated 10 at a time until maxItems or Facebook's last page.
Q: What does threadingDepth mean?
A: 0 is a top-level comment, 1 is a direct reply, 2+ is a deeper reply. Use maxReplyDepth to control how deep the actor collects.
Q: Why are profile picture URLs temporary? A: They are signed Facebook CDN links that expire after a few days. Rehosting every row's avatar would dominate run bandwidth, so the actor keeps the CDN link for profile pictures while attachment media (rarer) is rehosted permanently.
Q: Is this affiliated with Facebook or Meta? A: No. This is an independent, third-party actor that reads publicly accessible comments; it is not affiliated with, endorsed by, or operated by Meta Platforms, Inc.
Python quickstart
Use a schema-derived input and the Python standard library to start a run. An Apify account and token are required for execution.
Source build a6Lt5hJbeDo9CracC. Documentation is regenerated from the default published build; private drafts are not included.