Facebook Groups Scraper avatar

Facebook Groups Scraper

Pricing

from $0.67 / 1,000 posts

Go to Apify Store
Facebook Groups Scraper

Facebook Groups Scraper

Facebook groups scraper: export the 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

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

236

Total users

94

Monthly active users

3.9 hours

Issues response

14 hours ago

Last modified

Categories

Features

Limited permissions

Share

Facebook groups scraper for public group URLs, one row per post: 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.

InputPublic Facebook group URLs
OutputOne row per post: text, author, posting time, permalink, photos and videos, reactions, comments, shares
Ceiling5,000 posts and 50 groups per run
Account neededNone
Apify planAny, the Free plan included
Price$0.70 per 1,000 posts on the free plan, down to $0.67 on Business. Full comment threads, if you ask for them, add $0.25 per 1,000 comments, down to $0.239 on Business
Using an AI agent?
Actordami_studio/facebook-groups-scraper
Set one fieldstartUrls, labelled "Facebook group URLs" in the Console
Cap the billmaxTotalChargeUsd on the run, for example 0.10: it never charges past that
MCP, one linkhttps://mcp.apify.com/?tools=fetch-actor-details,dami_studio/facebook-groups-scraper
How oftenDaily, with onlyNewPosts on so each run brings only new posts

🔍 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 getField
The post's id and permalinkid, url, legacyId
The texttext
The original post's text, when the post is a sharesharedPostText
When it was postedtime, timestamp
Who posted ituser (name, id, picture, profile link)
Reactions, comments and shareslikesCount, topReactionsCount, commentsCount, sharesCount
Reactions by type: like, love, haha and the restreactionsByType
Photos, videos and a shared linkattachments, attachmentsCount, photoCount, isVideo, link
Each picture's size and Facebook's own description of itwidth, height, accessibilityCaption inside attachments
The groupgroupId, groupTitle, facebookUrl
The URL you gaveinputUrl
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

  1. Open Facebook Groups Scraper and click Try for free.
  2. Paste group URLs into Facebook group URLs.
  3. Set Number of posts and pick a Sorting order.
  4. Add Posts newer than if you only want recent ones, then click Start.
  5. 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: $0.25 per 1,000 comments on the free plan, $0.246 on Starter, $0.243 on Scale and $0.239 on Business. You pay for each comment row, replies included when you ask for them, on top of the post. A post with no comments adds nothing.

📥 What you give it

{
"startUrls": [{ "url": "https://www.facebook.com/groups/dogspotting/" }],
"resultsLimit": 50,
"viewOption": "CHRONOLOGICAL",
"onlyPostsNewerThan": "7 days"
}
FieldDefaultWhat it is
startUrlsnone, the form starts with an exampleUp to 50 public group URLs. Any past the fiftieth are left unread and listed in one free BAD_INPUT row.
resultsLimitempty, runs as 20Posts across the whole run, up to 5,000. Five groups at resultsLimit: 100 is a hundred posts in total, not five hundred.
maxPostsPerGroupnoneThe most posts from any one group. Set it and leave resultsLimit empty, and the run asks for that many from every group.
viewOptionempty, runs as CHRONOLOGICALCHRONOLOGICAL for new posts, RECENT_ACTIVITY for recently commented threads, TOP_POSTS for Facebook's ranking.
keywordsnoneWords 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.
onlyNewPostsfalseEach 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.
onlyPostsNewerThannone2026-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.
onlyPostsOlderThannoneThe same formats, the other way round. Use both for a window.
allPhotosfalseTurn 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.
includeTopCommentsfalseAdds topComments to each post: the one or two comments Facebook already shows under it. No extra charge.
maxCommentsPerPostnoneFull comment threads: up to this many comments from each post that has some, as their own rows, charged per comment.
includeCommentRepliesfalseWith maxCommentsPerPost set, the replies under each comment too. They count toward that number.
proxyUrlsnoneLeave 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

Real run output

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"
}
FieldHow to read it
id, urlThe post id and its permalink. id is your dedupe key across runs.
time, timestampThe real posting time, as ISO and as a unix number. Not "2 hours ago".
likesCountEvery reaction added together, not only thumbs-up. In the row above, 147 is the 86, 60 and 1 in topReactionsCount summed.
topReactionsCountThe 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, accessibilityCaptionIn 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, and photos added by allPhotos have no caption.
topCommentsWith includeTopComments on: the comments Facebook shows under the post, each with text, profileName, date, likesCount, repliesCount and commentUrl.
userName and picture. profileUrl is often null and the id is the long pfbid form.
attachmentsOne 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.
photoCountHow 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.
sharedPostTextOn 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.
legacyIdFacebook's older numeric id when the page carries one, null otherwise.

🧾 Reading the output

Four kinds of row, and only posts and comments cost anything.

RowHow to spot itCharged
A postrecordType: "post"yes
A comment, with full threads onrecordType: "comment", with the post's link in facebookUrl and its id in postIdyes, as a Comment
The sample row_sample: true, on a run with no usable inputno
A diagnostic_uncharged: true, and it carries a codeno

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:

CodeWhat it means
FREE_PLANRare. The first row of a run on the Apify Free plan that may end with RATE_LIMITED and no posts. Try again later.
BAD_INPUTNot a Facebook group URL, or more than 50 groups in one run: that row lists the ones left out.
NO_PUBLIC_POSTSThe group showed no posts to the run. A handle that no longer exists lands here too.
NO_RESULTSThe feed answered and had nothing matching your date window or your words, or nothing new since your last run.
FILTER_TOO_RAREYour words matched too few of the posts read to keep reading. What matched is delivered.
TIME_LIMITThe run stopped just before its time limit. What was delivered stays, and the run still ends as succeeded, with an amber status message.
COMMENTS_OFFRare. Full comment threads were not available on this run, so no comments were read or charged. Your posts are not affected. Try again later.
MEMORY_ERRORWith onlyNewPosts on, the record of your last run could not be opened, so nothing was read.
NOT_FOUNDThat group is gone.
RATE_LIMITEDFacebook throttled the reads. Any groups still queued are skipped.
NOT_SERVEDThis group was not served this run. Re-run it later. Runs before 13 October 2026 wrote BLOCKED here.
STOPPED_EARLYThe 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_DRIFTThe feed came back in a shape this could not read. Worth sending in.
TARGET_ERROR, NETWORKFacebook 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: schedule it daily with onlyNewPosts on and send new posts to Slack, Make, Zapier or n8n.
  • 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:

  1. Run this on a group with viewOption set to RECENT_ACTIVITY.
  2. Sort on commentsCount and copy the url of the busiest posts.
  3. 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 on top of the post, at the price above. Top comments with each post are free, but they are only the ones shown under it.
  • 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_RARE row.
  • 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_INPUT row.
  • 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 free STOPPED_EARLY row. Newest first with Posts newer than still returns every post in the window.
  • resultsLimit is the whole run, not per group. Sharing 50 posts across 10 groups is five each if the feeds cooperate. maxPostsPerGroup caps each group.
  • onlyNewPosts does not go back. Older posts a run did not hand over are not picked up later, so set resultsLimit to 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 wantUse
Posts from public groupsThis one
Posts from a Facebook PageFacebook Posts Scraper
Comments under a post or reel, group posts includedFacebook Comments Scraper
Reels from a PageFacebook Reels Scraper
A Page's website, e-mail, phone and addressFacebook 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 or your date window excluded the rest. A STOPPED_EARLY or NO_RESULTS row tells you which. If you get NO_PUBLIC_POSTS, open the group in a private browser window.

Can I call it from code or connect it to an AI assistant?

The API tab has code for Python, JavaScript and the CLI. MCP clients like Claude and ChatGPT use https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/facebook-groups-scraper; coding assistants can load our skill file. All three bill your Apify account at the same price.

# pip install apify-client
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("dami_studio/facebook-groups-scraper").call(
run_input={
"startUrls": [{"url": "https://www.facebook.com/groups/dogspotting/"}],
"resultsLimit": 50,
},
max_total_charge_usd=0.10, # the most this run may spend
)
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
if row.get("ok") is False: # free note rows, not results
continue
print(row.get("time"), (row.get("text") or "")[:80])

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.