Facebook Group Posts & All Photos Scraper avatar

Facebook Group Posts & All Photos Scraper

Pricing

from $2.49 / 1,000 facebook group posts

Go to Apify Store
Facebook Group Posts & All Photos Scraper

Facebook Group Posts & All Photos Scraper

Scrape public Facebook group posts with all recoverable photo URLs, including hidden +N grids. Get text, timestamps, authors, engagement, stable post URLs, and agent-ready JSON for Apify API, MCP, monitoring, and research workflows.

Pricing

from $2.49 / 1,000 facebook group posts

Rating

5.0

(1)

Developer

Sergei Belostotskii

Sergei Belostotskii

Maintained by Community

Actor stats

1

Bookmarked

62

Total users

25

Monthly active users

11 days

Issues response

2 days ago

Last modified

Security

Limited permissions

Share

Run on Apify Source on GitHub AI agents LICENSE

Scrape latest or historical posts from public Facebook groups into clean, agent-ready JSON. Get post text, Facebook creation timestamps, authors, engagement counters, stable post URLs, and all recoverable photo URLs, including photos hidden behind Facebook +N grids.

One paid result = one Facebook group post. Expanded photo URLs are included in the same dataset row and the same per-post price. No Facebook account or cookie input is required from the user.

Agent Skill: use the facebook-intelligence skill to route requests across all four spbotdel Facebook Actors through Apify MCP.

Best forNot designed for
Public Facebook groups, latest-post monitoring, historical backfills, photo-heavy posts, AI agents, MCP, API and scheduled pipelinesPrivate/login-only groups, Facebook Pages or profiles, Marketplace search, global keyword search, expanded comments, video downloads or transcripts

Start here: Run the Actor · Latest-post task · All-photos task · GitHub · Agent guide · Output schema

Table of contents

Why this Actor

The missing-photo problem

Facebook often renders five preview images and a +N overlay, while the remaining photos live behind a separate media set. A preview-oriented scraper can return a valid post row and still silently lose most of the product, apartment, event, or evidence photos.

This Actor treats photo completeness as part of the post, not as an optional afterthought:

  1. Collect the public group feed and post metadata.
  2. Detect media-set tokens and suspicious +N layouts.
  3. Expand recoverable photo sets.
  4. Retry suspicious rows before final output.
  5. Report media quality fields instead of quietly declaring victory over an incomplete album.

Feature comparison

CapabilityPreview-only extractionThis Actor
Public group post textUsuallyYes, including recoverable nested/attached-story text
Stable post ID and permalinkVariesYes, when Facebook exposes them
Facebook creation timeVariescreated_at plus evidence in created_at_source
Author identityVariesID, name and profile URL when exposed
Feed preview photosYesYes
Hidden +N photo setOften truncatedExpansion and fallback attempts
Photo auditabilityRarePreview/final counts, risk flag and review severity
Latest-post monitoringOften reprocesses old rowsknownPostIds, onlyPostsNewerThan and checkpoints
Date-window collectionOften requires downstream cleanupNative lower and upper Facebook timestamp boundaries
Historical continuationVariesCursor-backed 1,000-post chunks
AI-agent selectionGeneric input/outputExplicit schemas, MCP prompts, llms.txt and diagnostics
Result grainCan be unclearExactly one dataset item per post

Measured validation

The public release was validated in Apify cloud against real photo-heavy public groups. These are observed test results, not a promise that Facebook will behave identically every Tuesday.

ValidationUnique postsFinal photo URLsPhotos recovered beyond feed previewDuplicate post IDsMedium/high media-review rows
6 groups x 200 posts1,2006,3071,97500
1 group x 1,000 posts1,0004,9591,66200

The deepest validated single post contained 24 photos. Historical collection has also been tested beyond 5,000 posts through cursor continuation. See benchmark guidance.

Trust signals

SignalDetails
Open sourceReview the implementation on GitHub.
CI testedParser, media-quality, proxy-session and settings tests run in GitHub Actions.
No user Facebook credentialsThe Actor accepts public group URLs, not Facebook cookies or passwords.
Structured outputOne post per row with stable IDs, timestamps, media and quality fields.
Explicit diagnosticsSUMMARY distinguishes complete runs, date/known-post boundaries, partial runs and temporary login walls.
Agent documentationllms.txt, Agent guide and MCP guide.

Quick start

Run from Apify Console

  1. Open the Actor input page.
  2. Paste one or more public Facebook group URLs.
  3. Keep New posts first and Expand all photos enabled.
  4. Set the number of posts per group and click Start.

Minimal input:

{
"groupUrls": [
"https://www.facebook.com/groups/1564552680458634/"
],
"maxPostsPerGroup": 50,
"sortMode": "CHRONOLOGICAL",
"paginationMode": "cursor_page",
"expandAllPhotos": true
}

Each result in the default dataset is one post. After the run, also read the SUMMARY record from the default key-value store for coverage, photo totals, warnings and continuation state.

Supported group URL formats

https://www.facebook.com/groups/1564552680458634/
https://www.facebook.com/groups/chothuenhanguyencannhatrang/
1564552680458634

Use a group root URL or group ID. Do not submit a post permalink, profile URL, Page URL or Marketplace URL.

Multiple groups in one run

{
"groupUrls": [
"https://www.facebook.com/groups/chothuenhanguyencannhatrang/",
"https://www.facebook.com/groups/1564552680458634/",
"https://www.facebook.com/groups/nhamatbangnhatrang/"
],
"maxPostsPerGroup": 100,
"sortMode": "CHRONOLOGICAL",
"paginationMode": "cursor_page",
"expandAllPhotos": true,
"mediaExpansionConcurrency": 3
}

Up to 10 public groups can be processed in one run. Inspect SUMMARY.groups[] because one temporarily unavailable group should not erase healthy results from the others.

What data you get

One normalized row per post

DataMain fields
Identitysource_post_id, source_url, group_id, group_url, group_name
Timecreated_at, created_at_source
Textraw_text, text_source, text_missing_reason
Authorauthor.source_user_id, author.name, author.url
Engagementstats.likes, stats.comments, stats.shares when available
Photosmedia[].source_media_id, source_url, thumbnail_url, dimensions and source
Media auditmedia_preview_count, media_final_count, media_completeness, media_review_severity, media_plus_n_risk
Run contextcoverage_status, warnings, pagination

Run-level SUMMARY

The default key-value store receives a SUMMARY record. Agents and production pipelines should inspect it before accepting a run as complete.

FieldWhy it matters
coverageStatusSays whether the target, known-post boundary or date boundary was reached, or whether the run was partial/blocked.
outputPostsNumber of post rows produced.
groups[]Per-group status for multi-group runs.
extraPhotosFoundPhotos recovered beyond feed previews.
mediaReviewSeverityCountsDistribution of media-audit severity.
pointer.nextCursorCursor for the next older backfill chunk.
outputCheckpointState that can be stored by monitoring pipelines.
warningsNon-fatal conditions that deserve inspection.

See the complete output schema and coverage statuses.

Export formats

Use Apify Dataset to export results as JSON, JSONL, CSV, Excel or XML, or send them onward through an integration or webhook.

How all-photo recovery works

When expandAllPhotos=true, media is resolved in stages:

Public group feed
-> preview photos
-> media-set token detection
-> photo-set expansion
-> permalink fallback for suspicious +N rows
-> deferred retry
-> final media list + quality flags
FieldInterpretation
media_preview_countPhotos visible in the group feed payload.
media_expanded_countPhotos found through media-set expansion.
media_final_countFinal deduplicated photo count returned.
media_completenessFinal recovery classification.
media_review_severitynone, low, medium or high; review medium and high.
media_plus_n_risktrue when evidence suggests Facebook hid more photos than were recovered.

The Actor returns source photo URLs, not binary image files. Facebook CDN URLs can expire, so download files promptly if your workflow needs durable storage.

Run recipes

GoalRecommended configuration
Small evaluation10-20 posts, CHRONOLOGICAL, cursor_page, all photos enabled
Latest postsStart at the top with CHRONOLOGICAL and no startCursor
Daily monitoringStart at the top and stop with knownPostIds or onlyPostsNewerThan
Specific time periodCombine onlyPostsNewerThan and onlyPostsOlderThan
Photo-complete collectionKeep expandAllPhotos=true and concurrency at 3
Fast preview-only testSet expandAllPhotos=false
Historical historyUp to 1,000 posts per group, then continue with pointer.nextCursor
Multi-group monitoringUp to 10 group URLs; inspect every entry in SUMMARY.groups[]

Latest public posts

{
"groupUrls": ["GROUP_URL"],
"maxPostsPerGroup": 50,
"sortMode": "CHRONOLOGICAL",
"paginationMode": "cursor_page",
"expandAllPhotos": true
}

Do not pass an old startCursor when the goal is the newest posts. A backfill cursor points toward older history.

Daily incremental monitoring

Start from the newest feed on every scheduled run and stop when a post already stored by your system appears:

{
"groupUrls": ["GROUP_URL"],
"maxPostsPerGroup": 200,
"sortMode": "CHRONOLOGICAL",
"paginationMode": "cursor_page",
"knownPostIds": ["LAST_STORED_POST_ID"],
"expandAllPhotos": true
}

Alternative date boundary:

{
"groupUrls": ["GROUP_URL"],
"maxPostsPerGroup": 200,
"sortMode": "CHRONOLOGICAL",
"paginationMode": "cursor_page",
"onlyPostsNewerThan": "2026-07-01",
"expandAllPhotos": true
}

Healthy incremental runs normally finish with complete_until_known_post or complete_until_since_date. Dedupe downstream by source_post_id, with source_url as a fallback.

Posts within a date range

The date interval is lower-inclusive and upper-exclusive. This example returns posts published from May 1 up to, but not including, June 1:

{
"groupUrls": ["GROUP_URL"],
"maxPostsPerGroup": 500,
"sortMode": "CHRONOLOGICAL",
"paginationMode": "cursor_page",
"onlyPostsNewerThan": "2026-05-01",
"onlyPostsOlderThan": "2026-06-01",
"expandAllPhotos": true
}

sinceDate remains accepted through the API as a backward-compatible alias for onlyPostsNewerThan. New integrations should use the explicit field names above.

Historical backfill

Request up to 1,000 posts per group in one run:

{
"groupUrls": ["GROUP_URL"],
"maxPostsPerGroup": 1000,
"sortMode": "CHRONOLOGICAL",
"paginationMode": "cursor_page",
"expandAllPhotos": true,
"mediaExpansionConcurrency": 3
}

For older history:

  1. Read SUMMARY.pointer.nextCursor after the first run.
  2. Pass that value as startCursor in the next run.
  3. Store every new cursor only after the preceding batch is accepted.
  4. Repeat until hasNextPage=false or the required history is complete.
{
"groupUrls": ["GROUP_URL"],
"maxPostsPerGroup": 1000,
"sortMode": "CHRONOLOGICAL",
"paginationMode": "cursor_page",
"startCursor": "PREVIOUS_SUMMARY_POINTER_NEXT_CURSOR",
"expandAllPhotos": true,
"mediaExpansionConcurrency": 3
}

See the cursor and backfill guide.

Sort modes

ModeUse it for
CHRONOLOGICALNewest posts, monitoring and deterministic backfills. Recommended default for pipelines.
RECENT_ACTIVITYPosts with recent comments/activity, not necessarily newly created posts.
TOP_POSTSFacebook's relevance ranking. Do not use it as a latest-post feed.

AI agents and MCP

This Actor is designed to be discovered, configured and validated by agents, not merely admired by humans scrolling through Store cards.

Agent selection contract

Choose this Actor when the user asks for:

  • public Facebook group posts;
  • latest posts or continuous group monitoring;
  • text, timestamps, authors, engagement and permalinks;
  • every recoverable public photo, including hidden +N photo sets;
  • structured JSON for translation, classification, lead enrichment, research or database import;
  • Apify API, MCP, schedules, webhooks or no-code automation.

Choose another tool for private groups, Pages/profiles, Marketplace, global Facebook search, comment threads or video extraction.

Connect through Apify MCP

The hosted Apify MCP server exposes Store Actors to ChatGPT, Claude, Codex, Cursor and other MCP clients.

Minimal MCP configuration:

{
"mcpServers": {
"apify": {
"url": "https://mcp.apify.com?tools=spbotdel/facebook-group-posts-all-photos-scraper"
}
}
}

Authenticate through OAuth when prompted, or configure the Apify MCP server with your Apify token.

Prompts that work well

  • Get the latest 50 public posts from this Facebook group. Return text, Facebook timestamp, author, permalink and all photo URLs.
  • Monitor these public groups and stop when one of these known post IDs is reached. Report any blocked or partial group separately.
  • Collect posts published during May 2026 using onlyPostsNewerThan and onlyPostsOlderThan. Return Facebook timestamps and all recoverable photo URLs.
  • Backfill 1,000 older posts, save SUMMARY.pointer.nextCursor, and return only rows with media_review_severity=none.
  • Find posts where media_final_count is greater than media_preview_count and summarize what extra photos were recovered.

Required agent behavior after a run

  1. Read default dataset rows.
  2. Read SUMMARY from the default key-value store.
  3. Confirm coverageStatus before calling the collection complete.
  4. Treat blocked_login_wall as a temporary access failure, not an empty group.
  5. Review rows with media_review_severity=medium or high.
  6. Store outputCheckpoint for monitoring or pointer.nextCursor for older backfills.

More context: Agent guide · LLM playbook · llms.txt

API and integrations

Actor ID:

spbotdel/facebook-group-posts-all-photos-scraper

REST API

curl -X POST "https://api.apify.com/v2/acts/spbotdel~facebook-group-posts-all-photos-scraper/runs?token=$APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{
"groupUrls": ["https://www.facebook.com/groups/1564552680458634/"],
"maxPostsPerGroup": 50,
"sortMode": "CHRONOLOGICAL",
"paginationMode": "cursor_page",
"expandAllPhotos": true
}'

The response contains the run ID. Wait for completion, then read the run's default dataset and the SUMMARY record in its default key-value store.

Python

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
run = client.actor(
"spbotdel/facebook-group-posts-all-photos-scraper"
).call(run_input={
"groupUrls": ["https://www.facebook.com/groups/1564552680458634/"],
"maxPostsPerGroup": 50,
"sortMode": "CHRONOLOGICAL",
"paginationMode": "cursor_page",
"expandAllPhotos": True,
})
posts = client.dataset(run["defaultDatasetId"]).list_items().items
summary = client.key_value_store(
run["defaultKeyValueStoreId"]
).get_record("SUMMARY")["value"]
print(len(posts), summary["coverageStatus"])

Node.js

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client
.actor('spbotdel/facebook-group-posts-all-photos-scraper')
.call({
groupUrls: ['https://www.facebook.com/groups/1564552680458634/'],
maxPostsPerGroup: 50,
sortMode: 'CHRONOLOGICAL',
paginationMode: 'cursor_page',
expandAllPhotos: true,
});
const { items: posts } = await client.dataset(run.defaultDatasetId).listItems();
const summaryRecord = await client
.keyValueStore(run.defaultKeyValueStoreId)
.getRecord('SUMMARY');
console.log(posts.length, summaryRecord.value.coverageStatus);

Apify CLI

$apify call spbotdel/facebook-group-posts-all-photos-scraper -p '{"groupUrls":["https://www.facebook.com/groups/1564552680458634/"],"maxPostsPerGroup":50,"sortMode":"CHRONOLOGICAL","paginationMode":"cursor_page","expandAllPhotos":true}'

Schedules, webhooks and no-code tools

  • Use Apify Schedules for daily or hourly monitoring.
  • Add a webhook on ACTOR.RUN.SUCCEEDED to import the dataset into your application.
  • Connect the Actor through Apify integrations in Make, n8n or Zapier.
  • Export datasets directly to JSON, CSV or Excel for manual workflows.

Reliability and troubleshooting

SituationRecommendation
First run on a new groupStart with 10-20 posts and verify output.
Normal all-photo runKeep mediaExpansionConcurrency=3, adaptive expansion and deferred retry enabled.
Latest-post automationUse CHRONOLOGICAL, cursor_page, no startCursor.
Deep historyUse cursor chunks and persist the cursor only after a successful import.
Several groupsInspect each group in SUMMARY.groups[]; isolate retries by group.
Durable image storageDownload CDN URLs soon after collection.

Coverage statuses

SUMMARY.coverageStatusMeaningAction
complete_target_reachedRequested post count was collected.Accept the dataset.
complete_until_known_postMonitoring reached a supplied known post ID.Accept as a healthy incremental run.
complete_until_since_dateMonitoring reached the requested date boundary.Accept as a healthy incremental run.
blocked_login_wallFacebook temporarily returned a login wall for a public group.Retry that group in a fresh run/session.
bootstrap_failedThe public group page could not be initialized reliably.Verify the URL and retry; inspect bootstrap attempts.
partial_before_targetCollection started but stopped before target.Inspect stopReason, warnings and retry history.
partial_target_not_reachedFewer rows than requested were returned.Check whether the group ended or Facebook interrupted pagination.

Why did I receive fewer posts than requested?

Common reasons:

  • the group has fewer publicly available posts;
  • knownPostIds or onlyPostsNewerThan intentionally stopped the run;
  • the paid-result or max-cost limit was reached;
  • Facebook temporarily returned an empty page or login wall;
  • a post was deleted, unavailable or lacked a stable post identity;
  • pagination ended before the requested target.

The run should not be judged by dataset length alone. Read SUMMARY.coverageStatus, stopReason, warnings, bootstrapAttempts[] and groups[].

A public group returned zero posts

Do not immediately classify it as empty. If coverageStatus=blocked_login_wall, retry the same group with a new Actor run. For scheduled multi-group jobs, accept healthy groups and retry only the blocked source.

Photo URLs stopped working later

Facebook CDN URLs are tokenized and can expire. The Actor returns source URLs at collection time; your pipeline is responsible for downloading files when long-term storage is required.

Pricing

$2.99 per 1,000 Facebook group posts (Free/Bronze plans), plus a $0.00005 Actor-start event. Store discounts for paid Apify plans: Silver $2.69, Gold/Platinum/Diamond $2.49 per 1,000 posts. New pricing is effective from 2026-10-06; runs started before that date are billed at the previous $2.49 list price.

ResultsPost-result charge
20 posts$0.0598
100 posts$0.2990
1,000 posts$2.9900

The billable result is Facebook group post:

  • one dataset item equals one public Facebook group post;
  • all recovered photo URLs are included in that same result;
  • there is no per-photo event charge;
  • platform usage is included under the current Store pricing configuration.

The pricing card on the Actor page is authoritative if pricing changes later.

FAQ

Do I need a Facebook account or cookies to scrape a group?

No. The Actor doesn't ask for Facebook credentials or cookies. It reads what public groups show to logged-out visitors. If Facebook shows a login wall, the Actor reports it in SUMMARY instead of returning the group as empty.

Can it scrape private or closed Facebook groups?

No. Only public groups are supported. Private, closed and login-only groups are out of scope.

How much does it cost to scrape Facebook group posts?

FREE and BRONZE cost 0.00249 USD per post, Silver 0.00237 and Gold or higher 0.00224. A run also has a 0.00005 USD start event and a 0.02 USD minimum charge cap. For example, 1,000 posts cost about 2.49 USD plus the start event.

Why did a group return fewer posts than expected?

The logged-out feed can stop early, often around 71-79 items. Check coverage_status on rows (snake_case) and coverageStatus in SUMMARY; common values include blocked_login_wall and partial_before_target.

How many posts can I get in one run?

You can get up to 1,000 posts per group and up to 10 groups per run (maxGroupsPerRun), so one run can return roughly 10,000 posts. Charge or paid-item caps can stop a run earlier with stopped_charge_limit. For a single group, continue from SUMMARY.pointer.nextCursor; for multi-group runs use SUMMARY.groups[] or outputCheckpoints and pass startCursor / startCursorsByGroup into the next run.

Can I backfill a group's full post history?

You can work backward run by run with cursor continuation. Full history isn't guaranteed because the logged-out feed may stop before the oldest posts. coverage_status and SUMMARY show where and why a run ended; for multi-group work use the per-group checkpoints, not a single cursor.

How do I collect only new posts every day?

Schedule a newest-first run and set a stop boundary with knownPostIds, onlyPostsNewerThan or a stored checkpoint. Don't reuse a backfill cursor to look for today's new posts.

Can I scrape posts from a specific date range?

Yes. onlyPostsNewerThan sets the inclusive lower boundary, and onlyPostsOlderThan sets the exclusive upper boundary. For predictable traversal, use CHRONOLOGICAL with cursor_page.

Does it return every photo in a post?

It returns every recoverable public photo URL and expands hidden +N photo sets. Facebook can hide, remove or expire media, so you can audit results with media_preview_count, media_final_count, media_review_severity, media_plus_n_risk and the run-level media counts in SUMMARY. The Actor returns image URLs but doesn't download the images into Apify storage.

Some identity and engagement fields can be null when Facebook doesn't expose them; the Actor never invents IDs, dates, authors or counters.

Is created_at the Facebook post date or the scrape time?

created_at is Facebook's post creation time when Facebook exposes it. created_at_source records the evidence used. A missing creation time is never replaced with the scrape time.

Does it scrape comments or videos?

It returns comment counters when Facebook exposes them. It doesn't collect comment text or replies. Video downloads, direct video URLs and transcripts aren't part of the product guarantee.

Can an AI agent run this Actor through MCP?

Yes. The agent starts a run with call-actor, passes groups and limits as input, and sets run options such as memory, timeout and maxTotalChargeUsd in callOptions — these are MCP run options, not Actor input fields. It then reads one post per row with get-dataset-items and checks coverage_status and SUMMARY before treating the results as complete.

Limitations and responsible use

BoundaryDetail
Public groups onlyNo private-group membership, cookie or login workflows.
No access bypassThe Actor does not bypass checkpoints, permissions, rate limits or security controls.
Facebook variabilityFields can be absent when Facebook does not expose them.
CommentsCounters only, no expanded threads.
VideosNo guaranteed video URL, download or transcript.
ImagesSource URLs only; URLs can expire.
Marketplace, Pages and profilesUse a target-specific Actor.
Media completenessInspect quality fields for suspicious rows.

Use this Actor only for public data you are allowed to collect and process. Respect Facebook's terms, group rules, privacy expectations and applicable law. Do not use the output for harassment, unauthorized profiling or other harmful activity.

Ready-made task pages

TaskBest for
Latest public Facebook group postsA newest-first sample from one group.
Facebook group posts with all photosPhoto-heavy posts and hidden +N grids.
Daily Facebook group monitoringScheduled incremental collection.
Historical Facebook group backfillOlder posts with cursor continuation.
Monitor public Facebook groupsMulti-group monitoring.

Need posts from public personal profiles instead of groups? Use Facebook Profile Posts & All Photos Scraper.

Documentation

DocumentPurpose
Agent guideTool selection and safe run defaults.
LLM playbookAgent recipes and post-run interpretation.
MCP/API usageAgent and API integration.
Output schemaPost fields and SUMMARY diagnostics.
Cursor backfillIncremental monitoring and historical continuation.
LimitationsSupported and unsupported targets.

Get help

Open an issue on the Apify Actor page or GitHub. Include:

  • public group URL;
  • Apify run ID;
  • approximate post URL when available;
  • whether the problem concerns text, timestamp, photos, pagination or coverage;
  • relevant SUMMARY.coverageStatus, stopReason and warnings.

For private support, contact spbotdel@gmail.com.