Facebook Comments Scraper - $0.25 per 1,000
Pricing
from $0.25 / 1,000 comment scrapeds
Facebook Comments Scraper - $0.25 per 1,000
Turn public Facebook post and reel URLs into comment rows: author, text, timestamp, like count, reply count, and the nested replies if you want them. No login needed from you, and no browser. $0.25 per 1,000 comments, the same rate on every plan.
Pricing
from $0.25 / 1,000 comment scrapeds
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
4
Total users
2
Monthly active users
2 days ago
Last modified
Categories
Share
Facebook Comments Scraper
Paste public Facebook post URLs, get the comments back as rows: who wrote it, what they wrote, when, how many likes it got, how many replies it has, and the replies themselves if you want them.
Nothing to set up. You don't supply a login, a cookie or a token, and no browser is started.
Price
$0.25 per 1,000 comments, plus a $0.001 start fee per run (one tenth of a cent, billed per gigabyte of run memory, so exactly $0.001 on the default 1 GB).
That $0.25 is the rate on every plan, free or paid. No volume tiers, no minimum spend, no add-on fees. What you read here is what you pay on day one.
| Comments | Total cost |
|---|---|
| 100 | $0.026 |
| 1,000 | $0.251 |
| 10,000 | $2.501 |
| 100,000 | $25.001 |
What is actually charged
- One
comment-scrapedevent per comment row written to the dataset. Nothing else is metered per row. - Replies count as comments. Each reply is its own row, so each one is one charge.
- Free: the sample row an empty run returns, every diagnostic row (blocked post, private post,
post with comments turned off, bad URL), and every comment dropped by the
onlyCommentsNewerThanfilter. They all carry"charged": false. - A run that finds nothing costs the start fee and nothing more.
- Rows never leave the dataset without a charge, and are never charged without a row. The primary
event is a named one, so there's no price quietly attached to
apify-default-dataset-item.
Input
{"startUrls": [{ "url": "https://www.facebook.com/natgeo/posts/pfbid02rAK2eMyfVYDZbESKoNVuwWjcFr5BgRBfjp27nhgQToSiQD9NF3ypNdXpQuwSp7qnl" },{ "url": "https://www.facebook.com/NASAJSC/posts/1011509817757722" }],"resultsLimit": 50,"includeNestedComments": true,"viewOption": "RANKED_UNFILTERED"}
| Field | What it does |
|---|---|
startUrls | Public Facebook post, video, reel, photo or group-post permalinks. Up to 100 per run. |
resultsLimit | Maximum comments per post URL. Default 50, hard ceiling 5,000. |
includeNestedComments | Also pull the replies under each comment. Each reply is its own row and counts towards the limit. |
viewOption | RANKED_UNFILTERED (all comments, the default), RANKED_THREADED (most relevant), RECENT_ACTIVITY (newest first). |
onlyCommentsNewerThan | Optional cut-off. 2026-01-31, a full ISO timestamp, or relative like 3 days / 2 months. Dropped comments aren't charged. |
sessionCookies | Optional, and most runs never touch it. See About logins below. |
proxyUrls | Leave empty. Fill it in only if you want traffic to leave through proxy servers you already pay for. |
Run it with empty input and you get one labelled sample row, free, so you can see the output shape before you spend anything.
URL shapes that work
https://www.facebook.com/<page>/posts/<pfbid...>https://www.facebook.com/<page>/posts/<numeric id>https://www.facebook.com/<page>/videos/<numeric id>https://www.facebook.com/reel/<numeric id>https://www.facebook.com/groups/<group id>/posts/<numeric id>https://www.facebook.com/permalink.php?story_fbid=<id>&id=<page id>https://www.facebook.com/photo.php?fbid=<id>
A bare Page URL like https://www.facebook.com/natgeo is rejected with an explanation rather than
scraped. A Page isn't a post and has no single comment thread.
Output
One row per comment. Real row from a National Geographic post:
{"ok": true,"charged": true,"recordType": "comment","inputUrl": "https://www.facebook.com/natgeo/posts/pfbid02rAK2eMyfVYDZbESKoNVuwWjcFr5BgRBfjp27nhgQToSiQD9NF3ypNdXpQuwSp7qnl","postId": "1634927484671342","postTitle": "National Geographic","postDescription": "A punishing heat wave has left much of Europe in drought, causing rivers to run at record-low levels.","pageName": "National Geographic","commentUrl": "https://www.facebook.com/natgeo/posts/pfbid02r7oYKajerb...?comment_id=27860828630277533","id": "Y29tbWVudDoxNjM0OTI3NDg0NjcxMzQyXzI3ODYwODI4NjMwMjc3NTMz","commentId": "27860828630277533","feedbackId": "ZmVlZGJhY2s6MTYzNDkyNzQ4NDY3MTM0Ml8yNzg2MDgyODYzMDI3NzUzMw==","date": "2026-08-15T06:07:03.000Z","timestamp": 1786774023,"text": "Perfect opportunity to clean our waters!!! Bring this history to the musuem for our kids.","likesCount": 106,"likesCountText": "106","commentsCount": 4,"threadingDepth": 0,"replyToCommentId": null,"profileName": "Maggie Dalkowska","profileId": "pfbid0gZTGg4botETTKbXHiLzt72U5Wig8Gg3mJgF18vBVbiKRWof4nKXS26GVDFy9siuyl","profileUrl": "https://www.facebook.com/maggie.dalkowska","profilePicture": "https://scontent-fra3-2.xx.fbcdn.net/v/t39.30808-1/465583957_...jpg","author": { "id": "pfbid0gZTGg4botETTKbXHiLzt72U5Wig...", "name": "Maggie Dalkowska", "url": "https://www.facebook.com/maggie.dalkowska" },"attachments": [],"scrapedAt": "2026-08-20T19:52:23.770Z"}
A reply row looks the same but with "threadingDepth": 1, a replyToCommentId pointing at its
parent, and a commentUrl carrying both comment_id and reply_comment_id.
Field notes
likesCountis a number. Facebook only publishes a display string for reaction counts ("28","1.2K","3.4M"), so it's parsed back into an integer here.likesCountTextkeeps the original string. Above about a thousand reactions Facebook rounds the display string, so the number is rounded too:1.2Kbecomes1200, not the exact count. Nobody can give you the exact count from the public page, because the public page doesn't contain it.commentsCountis the reply count on that comment, not the post's comment count.profileIdis sometimes a numeric id and sometimes an opaquepfbid…string, depending on the account. Thepfbidform rotates over time, socommentIdis the safer key.attachmentsis an array of{type, url}for photo, video and sticker comments, empty for the usual text-only ones.profileUrlis null for commenters whose profile Facebook renders without a public link.postDescriptionis the post's text, not the comment's. It's read from the post's own content section, which matters more than it sounds: taking the longest text block on the page instead returns whichever reader wrote the longest comment.
Speed
Measured on the platform at the default 1 GB. One post, 60 comments: 13 seconds from a cold container. Two posts, 8 comments each: 7 seconds, since up to three posts are worked on at once.
Facebook hands out comments in pages of ten and silently ignores any request for a larger page, so a hundred comments is ten round trips no matter how it's asked for. That's the floor for this target, not a limitation of this Actor.
About logins
Worth spelling out, because "no login" gets used loosely.
Runs start logged out, and for a public post that is usually all it takes. When Facebook hands a logged-out reader nothing back, the run falls back to an account session that ships with the Actor so you don't have to supply one. There is a session involved. It just isn't yours and you never see it.
That session is shared across everyone using the Actor, and Facebook meters per account. If you're
running heavily and start seeing BLOCKED diagnostics, sessionCookies lets you paste your own
c_user=…; xs=… pair and get a rate limit nobody else is using. Treat those values like a password.
Anyone holding them can act as that account, and Facebook may sign the session out or restrict the
account for automated use.
What this does not do
An honest list, because you'll hit these otherwise.
- Public posts only. Anything Facebook shows only to a specific audience, meaning private groups, friends-only posts, or a Page restricted by age or country, returns an uncharged diagnostic row saying so.
- No reactions breakdown. You get the total reaction count, not how many were love, haha or angry. The public page doesn't carry it.
- No commenter email or phone. Not published, not inferable, not returned.
- One level of replies.
includeNestedCommentspulls the replies under a top-level comment. Replies to replies are collapsed by Facebook into the same level, so that's as deep as the public thread goes. - Reply counts can exceed the rows you get. A comment may report six replies and return four if some were made by accounts that later deactivated or were removed.
- Very large threads. The ceiling is 5,000 comments per post URL. Threads deeper than that get paginated by Facebook in a way that starts repeating rather than continuing, and repeated rows are dropped rather than charged.
- A post with comments turned off returns one uncharged diagnostic row, not an error.
- Rate limiting. Facebook meters reads per address. The Actor rotates through a large pool of
datacenter addresses and retries, but a very large run may still see a few posts come back as
BLOCKEDdiagnostics. They aren't charged. Re-running usually clears them.
Diagnostics
Nothing here fails silently, and a failed run never bills you for the failure. Every problem becomes
a row with "charged": false and a code:
code | Meaning |
|---|---|
BAD_INPUT | That URL isn't a Facebook post URL. The row says why. |
NOT_FOUND | The post is private, deleted, or the URL points at something with no comment thread. |
NO_COMMENTS | The post exists and is readable but has no comments, or none newer than your date filter. |
BLOCKED | Every exit address tried was throttled on this post. Re-run. |
RATE_LIMITED | Facebook asked for a slower pace. Re-run. |
DEAD_BATCH | Fifteen URLs in a row returned nothing, so the run stopped early rather than working through a list of dead links. The rest weren't touched and weren't charged. |
PROXY_INPUT_ADJUSTED | You asked for a proxy setting this Actor doesn't use; it ran on its own rotating addresses instead. |
CHARGE_ERROR | A billing event couldn't be recorded. Told to you rather than hidden. |
The run still ends SUCCEEDED in all of these cases, because a failed run would bill you the start fee for the privilege of being told you pasted the wrong link.
FAQ
Do I need a Facebook account, cookies or an access token?
Not from you. Paste URLs, get comments. There's an optional sessionCookies field if you'd rather
the run used your own account's rate limit than the shared one.
Does it work on reels and videos? Yes. Reels, videos, photos and group posts all have the same comment thread underneath them and are read the same way.
How do I get the replies under a comment?
Set includeNestedComments to true. Each reply arrives as its own row with threadingDepth: 1
and replyToCommentId set, and each is charged as a comment because each is a row.
How do I only get recent comments?
Set onlyCommentsNewerThan to 7 days, or to a date like 2026-06-01. Anything older is dropped
before it reaches the dataset and never charged. Combine it with viewOption: "RECENT_ACTIVITY" and
the run also stops paging as soon as it goes past your cut-off, which is faster and cheaper than
filtering afterwards.
How much does 10,000 comments cost? $2.50 plus the $0.001 start fee. There's no tier that makes it cheaper or more expensive.
Why do I get exactly ten comments per request in the logs?
Because that's what Facebook returns. Asking for 25, 50 or 100 returns ten. The Actor pages until it
reaches your resultsLimit.
Can I use my own proxies?
Yes, put them in proxyUrls as http://user:pass@host:port. Leave it empty and the run uses a
rotating pool of datacenter addresses, which costs you nothing extra. This Actor deliberately
doesn't offer residential proxy: on a target this data-heavy the bandwidth would cost more than the
data is worth, and you'd be paying for it.
Is the comment ID stable?
commentId is Facebook's own numeric comment id and is stable. id is the base64 node id, also
stable. Either works as a deduplication key across runs.
What happens if I run it with no input?
One sample row, marked "_sample": true and "charged": false, showing every field. Only the start
fee applies.
Can it scrape all comments from a whole Page? Not directly. This takes post URLs. Collect the post URLs first, then feed them in here, up to 100 per run.
Integration
Standard Apify Actor. Start it from the API, the JS or Python client, a schedule, or an MCP client, and read the default dataset:
curl -X POST "https://api.apify.com/v2/acts/dami_studio~facebook-comments-scraper/runs?token=<YOUR_TOKEN>" \-H 'content-type: application/json' \-d '{"startUrls":[{"url":"https://www.facebook.com/natgeo/posts/pfbid02rAK2eMyfVYDZbESKoNVuwWjcFr5BgRBfjp27nhgQToSiQD9NF3ypNdXpQuwSp7qnl"}],"resultsLimit":50}'
Output exports as JSON, CSV, Excel and XML from the dataset endpoint.
Legal
This Actor reads public Facebook content: posts and comments that anyone can open. It doesn't bypass a privacy setting and it doesn't touch private groups or restricted posts. Comment text and profile names are personal data in most jurisdictions, so you are the controller of whatever you collect, and GDPR, the CCPA and Facebook's own terms are yours to satisfy. If someone asks you to delete their comment out of your dataset, that request lands on you, not on us.

