Facebook Page Scraper – Posts, Photos & Details
Pricing
from $1.00 / 1,000 posts
Facebook Page Scraper – Posts, Photos & Details
Scrape any public Facebook page: its latest posts with full text, reactions, comments, shares and media (52 fields each), or the page itself — About block, follower count, photo albums and video library. No login and no cookies. Unofficial.
Pricing
from $1.00 / 1,000 posts
Rating
5.0
(1)
Developer
Simple Actors
Maintained by CommunityActor stats
0
Bookmarked
12
Total users
8
Monthly active users
17 days ago
Last modified
Categories
Share
Scrape any public Facebook page two ways from one input. mode: "posts"
(the default) returns the page's latest posts — full text, publish date,
reactions, comments, shares, photos and video, newest first, 52 fields per post.
mode: "details" returns the page itself: its About block with category,
email, phone, website and address, its follower count, profile and cover photo,
its photo albums and its video library. The two read different parts of Facebook
and neither substitutes for the other. Built for social media monitoring, brand
and competitor tracking, lead lists and CRM enrichment.
Built for the common case: the last handful of posts. One run is two requests and finishes in seconds.
No login, no cookies, no account of yours involved. It reads the same post data Facebook already server-renders for logged-out visitors, so the login box you see on the page is never in the way.
Unofficial. Not affiliated with, endorsed by, or sponsored by Facebook or Meta.
Features
- Two modes, one input — latest posts, or the page's own About block, photos and videos.
- 52 fields per post — text, SEO title, hashtags, links, publish time, reactions broken out per type, comments, shares, view counts and media.
- Reaction breakdown as columns —
reactionLikeCount,reactionLoveCount,reactionHahaCount,reactionWowCount,reactionSadCount,reactionAngryCount,reactionCareCount, ready for a spreadsheet. - Photos and video separated —
imageswith dimensions,videoswith separate SD and HD URLs, thumbnail, duration and a captions track when one exists, plus the combinedmedia. - Outbound links unwrapped — the real destination, not the
l.facebook.comredirect Facebook rewrites links into. - Drop-in field names —
time/timestamp,likes/comments/shares,media,textReferences, so existing code reads this Actor unchanged. - Page About block for lead data — category, email, phone, website, address
and hours, plus
aboutFieldscarrying every value the page states with its type. - Incremental polling —
onlyPostsNewerThantakes20 hours,last 3 days,90 minutesor an ISO date. - URL forms normalised — vanity,
profile.php?id=…andm.facebook.comlinks all work. - One bad page never costs you the good ones — an unreadable page comes back as its own row and the run still succeeds.
Input
{"startUrls": [{ "url": "https://www.facebook.com/CoJCTN" }], // public page URLs"mode": "posts", // "posts" for latest posts, "details" for the page itself"maxPosts": 5, // latest posts to return, newest first (1–8)"onlyPostsNewerThan": "20 hours", // optional window: "last 3 days", "90 minutes", "2026-08-01""includeRaw": false, // attach Facebook's untouched post object under `raw`"proxy": { "useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"] }}
startUrls is the only required field. Everything else has a working default.
| Field | Type | Default | What it does |
|---|---|---|---|
startUrls | array | — | Required. Public Facebook page URLs. Vanity, numeric and m.facebook.com forms all work. |
mode | string | posts | posts = one row per post. details = one row per page (About, photos, videos). |
maxPosts | integer | 5 | Latest posts to return. Maximum 8 — one request is all Facebook serves. Posts mode only. |
onlyPostsNewerThan | string | — | Keep only posts after a window or ISO date. Posts mode only. |
includeRaw | boolean | false | Attach Facebook's raw post object. Makes items much larger. Posts mode only. |
includePhotos | boolean | true | Read the Photos tab and album list. Details mode only. |
includeVideos | boolean | true | Read the Videos tab. Details mode only. |
proxy | object | residential | Residential is required — Facebook answers the posts request from a datacenter IP with a rate-limit error. |
Reading the page itself, not its posts
Set mode to details:
{"startUrls": [{ "url": "https://www.facebook.com/nasa" }],"mode": "details"}
That returns one row per page instead of one per post:
{"resultType": "page-details","pageName": "NASA - National Aeronautics and Space Administration","pageId": "100044561550831","isVerified": true,"category": "Government organisation","email": "public-inquiries@hq.nasa.gov","websites": ["http://www.nasa.gov/", "https://www.nasa.gov/nasa-app/"],"followersText": "28M followers","followers": 28000000,"followersAreExact": false,"coverPhoto": "https://scontent.../cover.jpg","aboutFields": [{ "section": "category", "sectionTitle": "Categories", "type": "category", "value": "Government organisation" },{ "section": "about_contact_info", "sectionTitle": "Contact info", "type": "profile_email", "value": "public-inquiries@hq.nasa.gov" }],"photos": [{ "id": "...", "url": "https://www.facebook.com/photo.php?fbid=...", "image": "https://scontent.../photo.jpg" }],"albums": [{ "title": "Cover photos", "url": "https://www.facebook.com/media/set/?set=a...", "coverImage": "..." }],"videos": [{"url": "https://www.facebook.com/NASA/videos/.../27340367028974495/","title": "NASA's Curious Universe - Roman Series - Episode 2","durationSeconds": 29,"time": "2026-08-19T...Z","playCount": 251617,"likes": 1606}],"photoCount": 8, "albumCount": 8, "videoCount": 18}
aboutFields is the field that will not let you down. Facebook states each
About value with a type — category, profile_email, website — and a page
publishes whichever ones apply to it, so a restaurant carries an address, a
phone and opening hours where a government page carries none of them. The named
keys (email, phone, website, address, category, hours) are a
convenience over aboutFields, and aboutFields carries everything the
page stated, including field types that postdate this Actor. If a named key is
empty, look there before concluding the page does not publish the value.
Follower counts are Facebook's rounded display figure, and the row says so.
The page header carries "28M followers" and no exact number anywhere, so
followersText is kept verbatim, followers is parsed from it, and
followersAreExact is false. Do not trend followers — a rounded figure does
not move for months, and then jumps.
One caveat on hours: measured on a real page it carries Facebook's rendered
status — "Closed now" — rather than a weekly schedule, so read it as a display
string, not as opening times.
includePhotos and includeVideos each default to true and each cost a page
load, so turn them off when you only want the About block — that is the
difference between $0.004 and $0.010 a page, and it is why the two are priced
separately rather than as one number. A real About-only
read of a city government page returned category, address, phone, email,
website and hours in six fields for one page load.
Why this is not just "read the latest posts"
The two modes read different parts of Facebook, and neither substitutes for the other:
- The About block is not in the post feed at all. No category, email, website, phone or follower count appears on a post.
- The media on a page's latest posts is not its library. A page whose recent posts are text or links returns no media at all, while its Videos tab still holds years of them — NASA's returned 18 videos reaching well past its latest 8 posts, and the Photos tab includes album and cover photos that were never in a post.
Output
One dataset item per post — the full text, when it was posted, how it performed, and every photo or video it carries:
{"facebookUrl": "https://www.facebook.com/CoJCTN","postId": "1369546808618058","storyId": "UzpfSTEwMDA2Njg4MjU1MDQ0ODoxMzY5NTQ2ODA4NjE4MD…","url": "https://www.facebook.com/reel/946342075161908/","postType": "video","title": "Assistant City Manager Nick Geis provides information about the City's Stormwater Division and recent rain events in this video","text": "Assistant City Manager Nick Geis provides information about the City's Stormwater Division and recent rain events in this video. T…","hashtags": [],"links": [],"time": "2026-08-12T20:58:11.000Z","timestamp": 1786568291,"timeCreated": "2026-08-12T20:58:11.000Z","timestampCreated": 1786568291,"likes": 101,"topReactions": [{"type": "Like","count": 93},{"type": "Love","count": 4},{"type": "Haha","count": 2},{"type": "Wow","count": 1},{"type": "Angry","count": 1}],"topReactionsCount": 5,"reactionLikeCount": 93,"reactionLoveCount": 4,"reactionHahaCount": 2,"reactionWowCount": 1,"reactionSadCount": 0,"reactionAngryCount": 1,"reactionCareCount": 0,"comments": 14,"shares": 10,"viewsCount": 4027,"videoPostViewCount": 4027,"liveViewerCount": null,"isVideo": true,"isShare": false,"sharedPost": null,"paidPartnership": false,"media": [{"url": "https://www.facebook.com/reel/946342075161908/","sdUrl": "https://video.fmad8-1.fna.fbcdn.net/o1/v/t2/f2/m412/AQPql-…","hdUrl": "https://video.fmad8-1.fna.fbcdn.net/o1/v/t2/f2/m366/AQMeSx…","thumbnailUrl": "https://scontent.fmad7-1.fna.fbcdn.net/v/t15.5256-10/77312…","durationMs": 83797,"isLive": false,"captionsUrl": "https://scontent.fmad7-1.fna.fbcdn.net/v/t39.2093-6/773744…","publishedAt": "2026-08-12T20:57:35.000Z","id": "946342075161908"}],"imageCount": 0,"videoCount": 1,"images": [],"videos": [{"url": "https://www.facebook.com/reel/946342075161908/","sdUrl": "https://video.fmad8-1.fna.fbcdn.net/o1/v/t2/f2/m412/AQPql-…","hdUrl": "https://video.fmad8-1.fna.fbcdn.net/o1/v/t2/f2/m366/AQMeSx…","thumbnailUrl": "https://scontent.fmad7-1.fna.fbcdn.net/v/t15.5256-10/77312…","durationMs": 83797,"isLive": false,"captionsUrl": "https://scontent.fmad7-1.fna.fbcdn.net/v/t39.2093-6/773744…","publishedAt": "2026-08-12T20:57:35.000Z","id": "946342075161908"}],"link": "http://johnsoncitytn.org/","textReferences": [{"type": "ExternalUrl","id": "NjQyMTgzOTU5MjA4MTA3Omh0dHBcYS8vam9obnNvbmNpdHl0bi5vcmcvOjpEZWZhdWx0Ojo6MTM2OTU0NjgwODYxODA1ODo=","url": "https://l.facebook.com/l.php?u=http%3A%2F%2Fjohnsoncitytn.org%2F&h=AUBHhU73r3VsNDED12CG04aEHyH2l9n-I8a-pvaVp_R-qUALOBrliucOL3dbyBm5_miUUKNE08QGK0Kietp3S-ngPvikwPVCBLV_wDmBrF_OlSEMBtANW9eg79D3_y4kOZU9dG8bG_wphctPgRp5asZVt2Ib2zVP&s=1","externalUrl": "http://johnsoncitytn.org/","mobileUrl": "https://lm.facebook.com/l.php?u=http%3A%2F%2Fjohnsoncitytn.org%2F&h=AUDb75f2i4MOL0iRZzTtSvA_Kk_mq4NvS2OXjLo1sRG-nFzZhQmis6_xkA1ZlNJ8RE0V1KYVBa5W13d9MDWyp3ykghtSdiYlGw3ThgZJfgLO6lKNZFQ2_ckD3JusbfKCQjRbwqIo-J-MYpq6qFvqCsabwNxN7KBn&s=1","offset": 167,"length": 17}],"collaborators": [],"actionLink": {"type": "MMEMessengerActionLink","url": null},"previewTitle": null,"previewDescription": null,"previewSource": null,"previewTarget": null,"topComments": [{"author": "Tom McCormack","authorId": "pfbid02vuXJVG7EBSwLbibmGki4uAxXWEoUksYp7HCXxDs…","text": "There are other parts of Johnson City that need to be protected from flooding. Are you looking at protecting those areas also?","createdAt": "2026-08-12T23:16:13.000Z"}],"feedbackId": "ZmVlZGJhY2s6MTM2OTU0NjgwODYxODA1OA==","pageName": "Johnson City, TN - City Government","pageId": "100066882550448","user": {"id": "100066882550448","name": "Johnson City, TN - City Government","profileUrl": "https://www.facebook.com/100066882550448","profilePic": "https://scontent.fmad8-1.fna.fbcdn.net/v/t39.30808-1/46072…"},"pageProfilePicture": "https://scontent.fmad8-1.fna.fbcdn.net/v/t39.30808-1/46072…","scrapedAt": "2026-08-19T08:38:43.421Z"}
Field names follow the vocabulary the established Facebook post scrapers use —
time/timestamp, likes/comments/shares, media, textReferences — so
you can point existing code at this actor without rewriting how you read the
results. The fields it adds on top (postType, hashtags, imageCount, and
the images/videos split alongside the combined media) keep their own
names.
postType is one of video, photo, link or text. A post that shares a
URL is a link post and carries the preview card in previewTitle,
previewSource and previewDescription, with the real destination in link —
unwrapped from the l.facebook.com redirect Facebook rewrites outbound links
into.
textReferences lists what Facebook marks up inside the text — hashtags,
mentions, events and external links — each with its type, ID, URL and character
offset, so you can find them in text without re-parsing it. Reactions come
both as topReactions and as one column per type (reactionLikeCount,
reactionLoveCount, reactionHahaCount, reactionWowCount, reactionSadCount,
reactionAngryCount, reactionCareCount) for loading straight into a
spreadsheet or a table. Photo posts carry
images with dimensions and the Facebook photo page; video posts carry videos
with separate SD and HD URLs, a thumbnail, duration and a captions track when
one exists.
The dataset ships four views: Posts (what it says and how it did), Engagement (reactions, comments, shares and views for ranking or trend work), Media (posts with photos or video and their URLs), and Posts with full text.
Set includeRaw to attach Facebook's untouched post object under raw when you
need a detail that has no named field.
Things worth knowing about the numbers
topCommentsis not the comment thread. Facebook ships a couple of comments alongside the feed and this actor passes those through, so a post withcommentCount: 14will still usually carry zero or one entry here. UsecommentCountfor the real total.- Every post has a posted time.
timeandtimestampare always present — a post without one fails the run rather than arriving with a null, so you can sort and bucket on it without guarding. A share also carries the original's own time intimeCreated, and a video carries its upload time invideos[].publishedAt; both can be earlier than the post itself. - A shared post reports zero engagement. When
isShareis true, the reactions, comments and shares belong to the original story, not to the share, and Facebook returns the sharer's own counters as empty.sharedPostnames the original and links to it — read the engagement there. - Video URLs expire.
sdUrlandhdUrlare signed and time-limited, good for hours rather than days. Download what you need soon after the run; the permalink inurlkeeps working.
About title
A Facebook post has no title of its own — it is just a body of text. title
here is Facebook's own SEO headline for the post, which is what search engines
and link previews show. For the occasional post Facebook generates no headline
for, title falls back to the post's opening line — and for a photo posted with
no caption at all, to Facebook's own description of the picture, so the field is
never blank. Either way it is capped at
120 characters, so its length does not depend on which source it came from.
text is always the complete, untruncated body.
When a page cannot be read
A URL that cannot be read does not fail the run and does not disappear — it comes back as its own row, so one bad page never costs you the pages that worked:
{"facebookUrl": "https://www.facebook.com/somepage","url": "https://www.facebook.com/somepage","error": "not_available","errorDescription": "… is not publicly visible — Facebook reports \"This content isn't available\". The page may be private, restricted, or removed; only public pages can be read without a login.","scrapedAt": "2026-08-19T16:02:11.004Z"}
error is one of not_available (private, restricted or deleted),
not_found, or read_failed (Facebook refused the read, worth retrying).
Rows carrying an error are not charged as posts.
How to use
From Apify Console
- Open the Actor and click Try for free / Start.
- Paste one or more public page URLs into Facebook page URLs — vanity
(
facebook.com/CoJCTN), numeric (facebook.com/profile.php?id=…) andm.facebook.comlinks all work. - Leave What to read on Latest posts, or switch it to Page details, photos and videos to read the About block and media library instead.
- Raise Number of posts to 8 for the full batch Facebook serves in one request, or set Only posts newer than to poll incrementally.
- Click Start, then open the Dataset tab. Four ready-made views ship with it — Posts, Engagement, Media and Posts with full text — and you can export as JSON, CSV or Excel.
From the API
curl -s "https://api.apify.com/v2/acts/simple.actors~facebook-page-posts/run-sync-get-dataset-items?token=$APIFY_TOKEN" \-H 'Content-Type: application/json' \-d '{"startUrls": [{"url": "https://www.facebook.com/CoJCTN"}]}'
Or with the JavaScript client:
import { ApifyClient } from 'apify-client';const client = new ApifyClient({ token: process.env.APIFY_TOKEN });const run = await client.actor('simple.actors/facebook-page-posts').call({startUrls: [{ url: 'https://www.facebook.com/CoJCTN' }],maxPosts: 8,onlyPostsNewerThan: '24 hours',});const { items } = await client.dataset(run.defaultDatasetId).listItems();
To follow a page over time, schedule the Actor and diff on postId.
Use cases
- Monitor a Facebook page for new posts — run on a schedule with
onlyPostsNewerThanset shorter than the gap between runs, and get exactly what is new. - Track emergency and service announcements — city governments, utilities, schools and clubs post outage notices, closures and alerts to Facebook first, often before anywhere else.
- Competitor and brand monitoring — pull reactions, comments, shares and view counts across rival pages to see which posts actually performed.
- Lead lists and CRM enrichment —
mode: "details"returns a page's category, email, phone, website and address straight from the About block. - Archive a page's output — keep a dated, linkable, searchable record of what an organisation published, with its media.
- Build a text dataset — full, untruncated post bodies for search, tagging, sentiment or topic analysis.
Usage notes
$1 per 1,000 posts, plus $0.003 per run — with Apify platform usage
included. A typical run reads a page's latest 5 posts for $0.008, and a run
that legitimately finds nothing costs only the run fee. Raise maxPosts to 8 for
the full batch Facebook serves, at $0.011.
Page details is priced separately, from 9 September 2026: $0.004 per page for the About block, plus $0.006 when photos and videos are read too — so $4 per 1,000 pages for contact details alone, or $10 per 1,000 for everything. The media charge only applies when a media tab was actually read, and a page that could not be read costs nothing either way.
Rows carrying an error are not charged as posts.
What an empty result means
An empty dataset means the page genuinely has no public posts — not that something went wrong.
That holds because a read that fails leaves a row rather than finishing
quietly: a page that does not exist, a private or restricted page, a challenge
or consent interstitial served instead of the page, a rate limit, or retries
running out each come back as a row carrying error and errorDescription. So
an empty dataset is a real answer, and the error rows — not the run status — are
where you look for failures.
The run itself succeeds even when every page in it failed. The one input
that still fails a run is an onlyPostsNewerThan value that cannot be parsed as
a window or a date, which is rejected before any page is fetched.
Settings
maxPosts— how many of the latest posts to return, newest first. Defaults to 5; raise it to 8 for the full batch Facebook serves in one request. 8 is the ceiling and anything above it is rejected rather than silently under-delivered. A smaller number also reaches less far back, so ifonlyPostsNewerThanstarts refusing a window it used to accept, raise this.proxy— defaults to Apify residential proxy, and needs to. Facebook serves the page itself to anyone, but answers the posts request from a datacenter IP with a rate-limit error rather than posts, so a datacenter run fails instead of returning a short result. A run moves under half a megabyte, which puts the residential bandwidth at roughly a third of a cent.onlyPostsNewerThan— keep only posts after a window like20 hours,last 3 daysor90 minutes, or an ISO date such as2026-08-01. Minutes, hours, days, weeks and months all work, with or without a leading "last". Ideal for incremental polling: ask for a window shorter than the gap between your runs and you get exactly what is new, or an error row on that page telling you the gap grew too large to answer honestly.includeRaw— attach Facebook's untouched post object underraw. Useful for a field with no named equivalent; it makes items much larger.- Runs are capped at 256 MB.
Limits
- Public pages only. A private page, or a personal profile that is not public, returns nothing — there is no session to log in with.
- The latest 8 posts at most, not the archive. One request to Facebook returns about
eight posts and asking again returns the same ones with a fresh cursor, so
eight is a ceiling rather than a default —
maxPostsabove 8 is rejected rather than quietly under-delivered. Run the actor on a schedule to follow a page over time instead of trying to reach further back in one run. - The newest post is always included. Every run loads the page fresh, and
Facebook serves it
no-store, so nothing is cached between runs. Results are sorted by date, so a pinned older post cannot displace a recent one. - Date filtering only within the window a run reads.
onlyPostsNewerThankeeps posts published after a window like20 hoursor an ISO date. Because a run reads only the latestmaxPostsposts, a cutoff reaching further back than those posts do returns an error row for that page rather than a partial answer — so an empty result always means "nothing new since then", never "we did not look that far". There is no filter for older posts: reaching back past the latest batch is not something one request can do. topCommentsis a sample, not the thread, and video URLs expire within hours. See the notes above.
FAQ
Is scraping Facebook legal? This Actor reads only pages that are publicly visible to any logged-out visitor, without logging in. Meta's Terms of Service restrict automated collection from its properties, so check the platform's ToS and your own obligations before using it, and run it at a volume and rate you are comfortable defending.
Do I need a Facebook login, cookies or an API key? No. There is no account, session or token involved — it reads the post data Facebook server-renders for logged-out visitors.
Does it support pagination or scraping a page's full history?
No, and that is a hard limit rather than a missing feature. One request to
Facebook returns about eight posts, and asking again returns the same eight with
a fresh cursor, so maxPosts is capped at 8. To follow a page over time, run
the Actor on a schedule with onlyPostsNewerThan instead of trying to reach
further back in a single run.
Can it scrape private pages or personal profiles?
No. A private page, or a personal profile that is not public, returns an
error row of not_available — there is no session to log in with.
Why does it need a residential proxy?
Facebook serves the page HTML to anyone, but answers the /api/graphql/ posts
request from a datacenter IP with a rate-limit error instead of posts. A
datacenter run therefore returns no posts. A run moves under half a megabyte, so
the residential bandwidth stays small.
Why does a post with 14 comments only return one in topComments?
Facebook ships a couple of comments alongside the feed and this Actor passes
those through — it is a sample, not the thread. Use comments for the real
total.
How do I get a page's email, phone and address?
Set mode to details. The About block is not present in the post feed at all,
so no post carries a category, email, website, phone or follower count.
Note
This actor is not affiliated with, endorsed by, or sponsored by Facebook or Meta. It reads publicly visible pages without logging in. Meta's Terms of Service restrict automated collection from its properties, so review them and your own obligations before using it, and run it at a volume and rate you are comfortable defending.