Vexaloom Labs

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.

FieldTypeRequiredDescription
startUrlsarrayrequiredFacebook 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.
maxItemsintegeroptionalMaximum number of comment rows (including replies) to collect per URL. The run also stops when Facebook has no more comments or replies to serve.
onlyCommentsNewerThanstringoptionalLimit 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
FieldTypeRequiredDescription
startUrlsarrayrequiredFacebook 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.
maxItemsintegeroptionalMaximum number of comment rows (including replies) to collect per URL. The run also stops when Facebook has no more comments or replies to serve.
onlyCommentsNewerThanstringoptionalLimit 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.
commentsModestringoptionalWhich 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).
includeNestedCommentsbooleanoptionalIf true, also scrape reply rows under top-level comments (with parent/reply metadata). If false, only top-level comments are collected (faster).
maxReplyDepthintegeroptionalHow 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.

FieldTypeRequiredDescription
commentsstringoptionalDataset 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, groupCommentInfo and 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 to www

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 text into 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

  1. Set maxItems per URL — it caps runtime and dataset size; the actor also stops on its own when Facebook runs out of comments
  2. Use NEWEST for fresh-comment monitoring — with onlyCommentsNewerThan, pagination stops as soon as an older comment appears, saving requests
  3. Keep includeNestedComments on for full threads; turn it off for fast top-level-only exports
  4. Test with 1–2 URLs first, then scale up
  5. 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; postCommentsCount vs postVisibleCommentsCount shows 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 in attachmentUrlOriginal. 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.

Open the step-by-step Python guide →

Source build a6Lt5hJbeDo9CracC. Documentation is regenerated from the default published build; private drafts are not included.