How to download all the comments from a Facebook post
Selecting and copying works until about the fortieth comment. After that Facebook is loading them in chunks, replies stay folded away, and your browser's find function cannot see any of it. Here is what actually gets you the whole thread, and why the total you end up with never quite matches the number printed on the post.
Why the manual route fails
A Facebook post does not contain its comments. It contains the first handful and a button that fetches more, and each click fetches another chunk. Replies are a second layer with their own buttons. So the page you can select with a mouse holds a fraction of the conversation, and the fraction changes depending on how long you sat there clicking.
That matters beyond convenience. If you are counting entries, measuring sentiment or quoting people, a partial export is worse than none, because it looks complete.
The number on the post is not the number you can get
This is the single most common surprise, so it is worth settling before you start. A post showing 1,200 comments will not give you 1,200 rows, and nothing is broken when it does not. The headline figure counts several things a public export cannot include:
- Replies are counted in it. A thread of one comment and nine replies contributes ten to the total.
- Spam-filtered comments are counted but not shown to visitors.
- Comments the page owner hid stay in the count and disappear from public view.
- Comments from since-deactivated or deleted accounts often persist in the tally.
A realistic expectation: you get every comment and reply that a person browsing without an account would see if they clicked every button, and that is the correct definition of "all" for anything you plan to publish or act on.
The three ways people do this
| Method | Reality |
|---|---|
| By hand | Fine to about forty comments. Beyond that you are clicking "view more replies" for an hour and still missing some. |
| Browser extension | Runs inside your logged-in session. That is the risk: automating actions from your own account is what gets accounts restricted, and the export dies whenever Facebook changes its markup. |
| Signed-out scraper | Reads the same public thread with no account attached. Nothing of yours is exposed, and it scales from one post to a thousand. |
Doing it
Paste the post URL into the Facebook Comments Scraper, set how many comments you want, and switch on replies if you need the full threads. You get one row per comment:
{
"commentId": "3000854580150022",
"date": "2021-08-15T19:58:31.000Z",
"text": "I'm struck by the goal you \"announced\" to the principal…",
"profileName": "Aimee J Bednar",
"profileId": "pfbid0LiAr9wu1KXhDrSfp77CyuFXFVuwgNCsFn7Su…",
"likesCount": "60",
"commentsCount": 1,
"threadingDepth": 0,
"replyToCommentId": null,
"commentUrl": "https://www.facebook.com/…?comment_id=3000854580150022"
}
Two fields do the work when you process this. threadingDepth is 0 for a top-level comment and 1 or more for a reply, and replyToCommentId points at the parent, so you can rebuild the thread structure exactly rather than guessing from indentation. One gotcha worth knowing before it bites you: likesCount arrives as a string, because Facebook abbreviates large values. Cast it before you sort on it.
Getting it into Excel
Every run stores its results as a dataset you can download as CSV or Excel from the run's Storage tab. Through the API, append the format you want to the dataset items URL:
curl "https://api.apify.com/v2/datasets/$DATASET_ID/items?format=csv&token=$APIFY_TOKEN" -o comments.csv
Nested fields flatten into columns like author.name. If you only want a few columns, add &fields=date,profileName,text,likesCount and the export comes back narrow enough to read.
Drawing a giveaway winner you can defend
Comment giveaways are the most common reason people need a full export, and they are also where a partial export causes an argument. Three rules make a draw defensible: replies are not entries, one person gets one entry however many times they commented, and the draw must be reproducible by anyone holding the same export.
This does all three. It seeds the random draw from the entry list itself, so re-running it produces the same winner, and anyone you give the export to can verify the result rather than trust you.
import json, random, sys, hashlib
data = json.load(open(sys.argv[1]))
keyword = sys.argv[2].lower() if len(sys.argv) > 2 else None
entries, seen = [], set()
for c in data:
if c.get("threadingDepth"): # 0 = top-level, replies are 1 and deeper
continue
if keyword and keyword not in (c.get("text") or "").lower():
continue
who = c.get("profileId") or c.get("profileName")
if not who or who in seen: # one entry per person, first comment wins
continue
seen.add(who)
entries.append(c)
entries.sort(key=lambda c: c["commentId"]) # stable order, independent of run
seed = hashlib.sha256("".join(c["commentId"] for c in entries).encode()).hexdigest()
random.seed(seed)
winner = random.choice(entries)
print(f"eligible entries : {len(entries)}")
print(f"draw seed : {seed[:16]}")
print(f"winner : {winner['profileName']}")
print(f"link : {winner['commentUrl']}")
Save your export as comments.json and run python3 pick.py comments.json, or add a required hashtag as a second argument: python3 pick.py comments.json "#giveaway". Publish the seed alongside the winner and the draw is auditable.
Other things the export is good for
- Sentiment and themes. A few thousand comments on a product announcement is a free focus group, and the text field feeds straight into whatever model you use.
- Support triage. Complaints arrive as comments on public posts far more often than through the form nobody can find.
- Competitor research. What people ask under a rival's launch post is the objection list for your own.
- Community moderation records. Keeping your own copy of a thread before it is edited or deleted.
Before you publish anything from it
Comments are written by identifiable people, which makes them personal data under the GDPR even though anyone can read them. Aggregate analysis is a very different thing from republishing someone's name next to their words, and the second needs more care than the first. Quote sparingly, do not build a profile of an individual out of their comment history, and do not use the author names as a marketing list. None of this is exotic; it is the same standard you would want applied to your own comments.
Questions people ask
Do I need a Facebook account?
No. Comments on a public post are visible to anyone, signed in or not.
Can I get comments from a private group or a personal profile?
No. Anything that requires a login to view is out of scope, deliberately.
Can I run this every day and get only the new comments?
Yes. Schedule the run and de-duplicate on commentId, which is stable.
What does it cost?
$1 per 1,000 comments, no start fee, no surcharge for filtering, with platform usage and residential proxies included. Apify's own comments scraper charges $2.50 per 1,000 on the free plan, plus a fee to start each run, plus an extra fee per comment when a date filter is on.
Try the Facebook Comments Scraper Or scrape the posts themselves