Facebook Groups Scraper - Public Group Posts
Pricing
from $0.67 / 1,000 posts
Facebook Groups Scraper - Public Group Posts
Scrape posts from public Facebook groups. Each post gives the author, text, exact time, permalink, photos and videos, plus reaction, comment and share counts. Up to 5,000 posts and 50 groups per run, with a keyword filter. $0.70 per 1,000 posts.
Pricing
from $0.67 / 1,000 posts
Rating
5.0
(1)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
157
Total users
75
Monthly active users
4.2 hours
Issues response
2 days ago
Last modified
Categories
Share
Paste public Facebook group URLs and get their posts as rows: the text, the author, the exact posting time, the permalink, the photos and videos, and the reaction, comment and share counts. No login, and no browser to wait on.
If a group shows no posts, it comes back as a free note in your dataset rather than a charge.
On the Apify Free plan, most runs return no posts. Paid plans get them.
| Input | Public Facebook group URLs |
| Output | One row per post: text, author, posting time, permalink, photos and videos, reactions, comments, shares |
| Ceiling | 5,000 posts and 50 groups per run |
| Account needed | None |
| Apify plan | A paid plan. On the Free plan most runs end with a free RATE_LIMITED note and no posts |
| Price | $0.70 per 1,000 posts on the free plan, down to $0.67 on Business |
🔍 What Facebook Groups Scraper does
Give it group URLs, pick how the feed should be ordered, say how many posts you want, and press Start. Each post becomes one row with everything the group page publishes about it.
Three orderings, and they are Facebook's own, not a sort applied afterwards: New posts walks the feed by posting time, Newest activity brings up threads that were commented on recently, and Most relevant is Facebook's own ranking. For monitoring, use New posts.
There is a date window too. Give onlyPostsNewerThan a date or something like 7 days, or 2 hours
when you check often, and older posts are dropped before they are written, so you are not charged for
them.
Two switches help with groups you check often. keywords keeps only posts holding one of your
words, and the rest are never charged. onlyNewPosts remembers the newest post each run handed
over, so the next run gives you only what came after it.
Both numeric group URLs and the handle form work.
📋 What data you get from each Facebook group post
| What you get | Field |
|---|---|
| The post's id and permalink | id, url, legacyId |
| The text | text |
| The original post's text, when the post is a share | sharedPostText |
| When it was posted | time, timestamp |
| Who posted it | user (name, id, picture, profile link) |
| Reactions, comments and shares | likesCount, topReactionsCount, commentsCount, sharesCount |
| Reactions by type: like, love, haha and the rest | reactionsByType |
| Photos, videos and a shared link | attachments, attachmentsCount, photoCount, isVideo, link |
| Each picture's size and Facebook's own description of it | width, height, accessibilityCaption inside attachments |
| The group | groupId, groupTitle, facebookUrl |
| The URL you gave | inputUrl |
| The comments shown under the post (optional, no extra charge) | topComments |
| Full comment threads (optional, paid add-on) | separate rows with recordType: "comment" |
▶️ How to scrape Facebook groups
- Open Facebook Groups Scraper and click Try for free.
- Paste group URLs into Facebook group URLs.
- Set Number of posts and pick a Sorting order.
- Add Posts newer than if you only want recent ones, then click Start.
- Download the dataset as JSON, CSV or Excel, or read it from the Apify API.
Run it with no usable group URL and you get one labelled sample row, which is not charged.
💰 How much does it cost to scrape Facebook groups?
$0.70 per 1,000 posts. That is the free plan's price; paid plans pay a little less: $0.69 on Starter, $0.68 on Scale and $0.67 on Business.
One charge per post row. Posts your date window or your words leave out are never charged, and neither are sample or diagnostic rows. An empty group or a run that finds nothing costs you nothing for results. Top comments with each post cost nothing extra.
Full comment threads are an add-on: each comment row is charged as one Comment event, at the price on the Pricing tab. While that price is not there yet, asking for them returns one free note and reads no comments.
📥 What you give it
{"startUrls": [{ "url": "https://www.facebook.com/groups/dogspotting/" }],"resultsLimit": 50,"viewOption": "CHRONOLOGICAL","onlyPostsNewerThan": "7 days"}
| Field | Default | What it is |
|---|---|---|
startUrls | none, the form starts with an example | Up to 50 public group URLs. Any past the fiftieth are left unread and listed in one free BAD_INPUT row. |
resultsLimit | empty, runs as 20 | Posts across the whole run, up to 5,000. Five groups at resultsLimit: 100 is a hundred posts in total, not five hundred. |
maxPostsPerGroup | none | The most posts from any one group. Set it and leave resultsLimit empty, and the run asks for that many from every group. |
viewOption | empty, runs as CHRONOLOGICAL | CHRONOLOGICAL for new posts, RECENT_ACTIVITY for recently commented threads, TOP_POSTS for Facebook's ranking. |
keywords | none | Words or phrases. Only posts holding at least one of them, in the text, the shared post's text or a link preview, are delivered and charged. Case does not matter. |
onlyNewPosts | false | Each run remembers the newest post it handed over per group, in a store called facebook-groups-scraper-new-posts on your own Apify account, and the next run skips everything up to it. Delete that store to start over. |
onlyPostsNewerThan | none | 2026-01-01, a full ISO timestamp, or a span such as 7 days, 2 hours or 30 minutes. Older posts are skipped and never charged. |
onlyPostsOlderThan | none | The same formats, the other way round. Use both for a window. |
allPhotos | false | Turn it on to get up to 24 photos of each post instead of the first 5. The price per post stays the same, but the run takes longer, a few seconds more for each post with more than 5 photos, so give big runs a longer timeout. |
includeTopComments | false | Adds topComments to each post: the one or two comments Facebook already shows under it. No extra charge. |
maxCommentsPerPost | none | Full comment threads: up to this many comments from each post that has some, as their own rows, charged per comment. |
includeCommentReplies | false | With maxCommentsPerPost set, the replies under each comment too. They count toward that number. |
proxyUrls | none | Leave it empty. It is here for callers who want the traffic to leave through servers they already pay for, as http://user:pass@host:port. There is no bandwidth surcharge on this actor either way. |
📤 What you get back
A real row from a run on 21 September 2026. The image links are signed and very long, so they are cut short here:
{"ok": true,"recordType": "post","charged": true,"facebookUrl": "https://www.facebook.com/groups/dogspotting/","url": "https://www.facebook.com/groups/dogspotting/permalink/10166203291439467/","id": "10166203291439467","legacyId": null,"time": "2026-09-20T23:30:52.000Z","timestamp": 1789947052,"text": "His name is Invader and he invaded my heart","user": {"id": "pfbid02UQC3terETmAmd24Hgg4ev1Pxye5Bh6SQ9HCYF58dVPrULg7E3tumNTv4Hs2Aoz4tl","profileUrl": null,"profilePic": "https://scontent-lga3-3.xx.fbcdn.net/v/t39.30808-1/560561781_10164128278012578_..."},"likesCount": 147,"commentsCount": 0,"sharesCount": 0,"topReactionsCount": [86, 60, 1],"attachments": [{"type": "photo","thumbnail": "https://scontent-lga3-3.xx.fbcdn.net/v/t39.30808-6/791453646_10165826125182578_...","url": "https://www.facebook.com/photo/?fbid=10165826125842578&set=gm.10166203291439467&idorvanity=10487409466","id": "10165826125842578"}],"attachmentsCount": 1,"isVideo": false,"link": null,"groupId": "10487409466","groupTitle": "Dogspotting","inputUrl": "https://www.facebook.com/groups/dogspotting/","scrapedAt": "2026-09-21T01:45:39.314Z"}
| Field | How to read it |
|---|---|
id, url | The post id and its permalink. id is your dedupe key across runs. |
time, timestamp | The real posting time, as ISO and as a unix number. Not "2 hours ago". |
likesCount | Every reaction added together, not only thumbs-up. In the row above, 147 is the 86, 60 and 1 in topReactionsCount summed. |
topReactionsCount | The counts behind the reaction types on the post, as numbers with no labels. reactionsByType gives the same counts by name, for example {"like": 86, "love": 60, "haha": 1}, and adds up to likesCount. null when the post has no reaction. |
width, height, accessibilityCaption | In an attachments entry: the size of the picture the thumbnail link opens, and Facebook's own description of it, such as "May be an image of a dog". The caption is null when Facebook has none. Photos added by allPhotos carry neither. |
topComments | With includeTopComments on: the comments Facebook shows under the post, each with text, profileName, date, likesCount, repliesCount and commentUrl. Usually one or two, and an empty list on most posts with few comments. |
user | Name and picture. profileUrl is often null and the id is the long pfbid form, which is what Facebook hands out for group authors now. |
attachments | One entry per photo or video, with a thumbnail and, on videos, the video link. Every media link is signed and stops working after a while, so download what you want to keep in the same session. |
photoCount | How many photos the post has in total, the number behind the "+N" on the last photo. attachments holds the first 5 of an album's photos, or up to 24 with allPhotos on, so a post with 31 photos gives 5 links (24 with allPhotos) and photoCount: 31. A video in the same set counts as one. null when the post has no photo. |
sharedPostText | On a share, text is only what the person sharing typed above it, and often empty. This is the shared post's own text, in full. null when the post is not a share or the shared post has no text. |
legacyId | Facebook's older numeric id when the page still carries one. Usually null. |
🧾 Reading the output
Four kinds of row, and only posts and comments cost anything.
| Row | How to spot it | Charged |
|---|---|---|
| A post | recordType: "post" | yes |
| A comment, with full threads on | recordType: "comment", with the post's link in facebookUrl and its id in postId | yes, as a Comment |
| The sample row | _sample: true, on a run with no usable input | no |
| A diagnostic | _uncharged: true, and it carries a code | no |
The charged field is a row marker, not a receipt. It is what separates a real post from a sample
or a diagnostic, and it is stamped as the row is built rather than after the money moves. Your Apify
run detail is the authority on what you were actually billed. Diagnostic rows carry code, not
errorCode:
| Code | What it means |
|---|---|
FREE_PLAN | The first row of a run on the Apify Free plan: Facebook serves only a few group reads, and this Actor keeps them for paid plans, so most Free-plan runs end with RATE_LIMITED and no posts. |
BAD_INPUT | Not a Facebook group URL, or more than 50 groups in one run: that row lists the ones left out. |
NO_PUBLIC_POSTS | The group showed no posts to the run. A handle that no longer exists lands here too. |
NO_RESULTS | The feed answered and had nothing matching your date window or your words, or nothing new since your last run. |
FILTER_TOO_RARE | Your words matched too few of the posts read to keep reading. What matched is delivered. |
TIME_LIMIT | The run stopped just before its time limit. What was delivered stays. The run ends as failed only when nothing came back before the limit. |
COMMENTS_SOON | You asked for full comment threads before they were switched on. No comments were read. |
MEMORY_ERROR | With onlyNewPosts on, the record of your last run could not be opened, so nothing was read. |
NOT_FOUND | That group is gone. |
RATE_LIMITED | Facebook throttled the reads. Any groups still queued are skipped. |
NOT_SERVED | This group was not served this run. Re-run it later. Until 12 October 2026 this code was called BLOCKED. |
STOPPED_EARLY | The run stopped before your limit: the feed stopped giving out posts, or further down it held very few posts that fit your settings. You keep everything collected up to that point. |
SCHEMA_DRIFT | The feed came back in a shape this could not read. Worth sending in, it usually means Facebook changed something. |
TARGET_ERROR, NETWORK | Facebook errored, or the request did not complete. Re-run it. |
💡 What people use it for
- Watching buy-and-sell and local groups for a word, with
onlyNewPostson, and acting on new posts the same day. - Collecting questions people ask in a niche group, to write content that answers them.
- Tracking how a community reacts to an announcement, by post text and reaction counts.
- Keeping an archive of a group you run, outside Facebook, with permalinks that still work.
From a group's feed to the threads people argued in, in three steps:
- Run this on a group with
viewOptionset toRECENT_ACTIVITY. - Sort on
commentsCountand copy theurlof the busiest posts. - Paste them into Facebook Comments Scraper, which reads group-post links, and read the comments themselves.
🚧 What it does not do
- Full comment threads are a paid add-on. Each comment is charged as a Comment event at the price on the Pricing tab, and while that price is not there the option returns a free note. Top comments with each post are free, but they are only the one or two Facebook shows.
- No member lists, no admin lists, no group rules.
- No search inside a group. The word filter checks the posts the run reads; it does not ask
Facebook to search. A word that turns up rarely stops the run early with a free
FILTER_TOO_RARErow. - No sale listing fields such as price or sold status. Sale posts come back as ordinary posts, with the price wherever the seller typed it in the text.
- No photo or video files, only links, and those links expire.
- 50 groups per run at most. Any beyond that are left unread and listed in one free
BAD_INPUTrow. - It won't read a whole group to find a handful of posts. Sorted by top posts or recent activity with a date
window, or skipping far back with
onlyPostsOlderThan, a run stops once the posts further down mostly fall outside your settings, and says so in a freeSTOPPED_EARLYrow. Newest first with Posts newer than still returns every post in the window. resultsLimitis the whole run, not per group. Sharing 50 posts across 10 groups is five each if the feeds cooperate.maxPostsPerGroupcaps each group.onlyNewPostsdoes not go back. Older posts a run did not hand over are not picked up later, so setresultsLimitto cover what a group posts between runs.- It is not an official Facebook tool. Dami's Studio is independent and is not affiliated with or endorsed by Facebook or Meta, or by any other company named on this page.
🧭 Which Facebook scraper do you need?
| If you want | Use |
|---|---|
| Posts from public groups | This one |
| Posts from a Facebook Page | Facebook Posts Scraper |
| Comments under a post or reel, group posts included | Facebook Comments Scraper |
| Reels from a Page | Facebook Reels Scraper |
| A Page's website, e-mail, phone and address | Facebook Page Contact Info Scraper |
❓ Questions people ask
Do I need a Facebook account to scrape groups?
No. Public groups are read without one.
Why did I get fewer posts than I asked for?
Either the group has fewer public posts, your date window excluded the rest, or the feed stopped
early. A STOPPED_EARLY or NO_RESULTS row tells you which. If you get NO_PUBLIC_POSTS, open the
group in a private browser window. If a signed-out visitor sees no posts there either, that is why.
Can I call it from code or connect it to an AI assistant?
Yes. The API tab has ready-made
code for Python, JavaScript and the command line. For Claude, ChatGPT or another MCP client, connect
https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/facebook-groups-scraper. Either way
the run happens on your Apify account at the same price.
Is scraping public Facebook groups legal?
These are pages anyone can read without an account. Posts contain personal data, which GDPR and similar laws cover, so have a lawful reason for collecting them. Apify's write-up on scraping and the law is a reasonable starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the run ID and the group URL. The code on the
diagnostic row usually says what happened on its own.