Instagram Comments Scraper
Pricing
from $4.56 / 1,000 comment returneds
Instagram Comments Scraper
Instagram comment scraper for public posts and reels, no login. Paste post links, get one row per comment: author, user ID, text, likes, exact timestamp and whether the post's own account wrote it. Reads the newest comments Instagram shows a signed-out visitor. A post that returns nothing is free.
Pricing
from $4.56 / 1,000 comment returneds
Rating
0.0
(0)
Developer
Adrian Voss
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
2 days ago
Last modified
Categories
Share
One row per Instagram comment, without a login. Paste post or reel links and get a flat row per comment: the author's username and numeric user ID, the comment text, its like count, the exact time it was written, whether the post's own account wrote it, and the untouched source object. Field names are frozen and drop straight into a Sheet, a Clay table, an n8n workflow or an AI agent with no post-processing.
Read this before you buy: a signed-out visitor sees only the newest 10 to 14 comments on a post. That is Instagram's limit, not this actor's, and no amount of paying changes it — see "What you can and cannot get without logging in". If you need every comment on a 9,000-comment post, this is the wrong tool and you should say so to yourself now rather than after a run.
Who it's for
A brand watching its own posts wants to know what was said in the last hour, on a schedule, without a person refreshing a phone — and wants owner replies flagged so it can see which complaints have already been answered. A giveaway operator needs the entrants from the current window as a table, with usernames and user IDs, not a screenshot. A social listening or sentiment pipeline needs comment text with a real timestamp attached, in a shape it can feed to a model. And an agent that already knows which posts matter needs one HTTP call that answers "what are people saying on this post right now".
All four want the same thing: the recent comment stream, cheap, in a fixed shape, on a schedule. That is what this actor is. It is a monitor, not an archive.
Why this one
- Newest first, always. Instagram hands a signed-out visitor its most recent comments, in strict reverse-chronological order — verified on every fixture and asserted by the test suite, so a change in that ordering fails a test rather than quietly reordering your data. Run it every hour and you have a live comment feed for the posts you care about.
- No login, no cookies, no account risk. Nothing here logs in, stores a session, or asks you for credentials. There is no account of yours to get restricted.
- The row shape is the product.
shortcode,comment_id,parent_id,author,author_id,text,like_count,posted_at,is_owner_reply,reply_count,raw. Frozen names, so a scheduled workflow or an agent can be pointed at this safely. Everything this actor does not surface as its own column is still there, untouched, inraw. author_id, not justauthor. Usernames change; numeric user IDs do not. If you are deduplicating entrants or matching commenters across posts over time, the ID is the join key and the username is a label.- One request per post. The entire payload arrives in the post page itself, so there are no follow-up hops to pay for. That is why this is cheap.
- Never charged for a miss. A deleted post, a post with comments turned off, an age-gated post, a blocked request — each returns a row explaining what happened and costs nothing.
- It tells you when it came up short. Every run writes an
OUTPUTrecord listing each post where your limit could not be filled and exactly how many comments were available. You are never left guessing whether 11 rows means "11 comments exist" or "something broke".
What you get
One row per comment by default (turn off "Expand rows" in Advanced to get one row per post
instead, with everything nested under comments).
| Field | What it is |
|---|---|
shortcode | The post the comment is on, e.g. DdcI4o0Prsz |
comment_id | Instagram's own comment ID, as a string — these exceed what a spreadsheet stores as a number |
parent_id | The comment this one replies to. Always empty here — see below |
author | The commenter's username |
author_id | The commenter's numeric user ID, as a string. Stable across username changes |
text | The comment itself, emoji and all |
like_count | Likes on the comment. Real, but usually 0 — see below |
posted_at | When the comment was written, ISO-8601 UTC, to the second |
is_owner_reply | true when the account that posted the post wrote this comment. Matched on user ID, never on username |
reply_count | Instagram's count of replies under this comment. Always empty here — see below |
raw | The untouched source object, including is_covered, restricted_status, has_translation and giphy_media_info |
In grouped mode each post also carries commentCount (what you were billed for), totalComments
(how many the post has in total, which is usually far more), and truncated.
What you can and cannot get without logging in
This section exists because the honest answer is the most important thing on this page.
You get: the newest 10 to 14 top-level comments on any public post or reel, with every field in the table above that is marked as filled. Measured on three real posts across two accounts: 10, 11, 13 and 14 comments per page load.
You do not get, at any price, without a login:
| Why | |
|---|---|
| Comment 15 and beyond | Instagram embeds the newest comments directly in the post page and offers a "next page" cursor alongside them. That cursor is a decoy: every signed-out request that could consume it is refused. This was tested against the real pagination query and against the page's own content query with the page's own variables — both come back empty for a signed-out caller, which proves the channel is closed rather than the cursor being wrong. |
| Replies to comments | Instagram's signed-out post page carries no reply threads at all. parent_id and reply_count are therefore always empty, and the "Include replies" switch cannot do anything. It is kept only so saved inputs and API calls stay valid, and turning it on writes a note into the run's OUTPUT record instead of pretending. |
| Realistic like counts | like_count is read correctly, but the comments you get are the newest ones, and a comment posted four minutes ago has no likes yet. Across 25 live rows, one had a like. Do not sort or filter on this field. |
| A representative sample | The newest dozen comments on a viral post are not a sample of its 9,000 comments. They are the last dozen minutes. Treat this as a live feed, not a survey. |
If that list rules out your use case, use a logged-in comment scraper instead. It will cost more and carry account risk, and it will do the job this one cannot.
How to use
- In the Apify Console. Open the actor page and click Start — the
urlsfield is already pre-filled with a working example. Results land in the run's dataset as soon as each item is found. - Via the API. Call it directly with a POST request — no Console needed once you have an API token:
curl "https://api.apify.com/v2/acts/accountable_eel~ig-comments-scraper/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"urls":["DdcI4o0Prsz","DdcjXAeFyr8"]}'
- On a schedule. Save this actor as an Apify Task with the input you want, then add a Schedule (hourly, daily, weekly) so it runs on its own — no server of your own required.
Because the reach per run is the newest comments only, scheduling is how you get depth. An hourly run over the same post accumulates the full comment stream in your dataset over time, a dozen at a time, which one-off runs cannot do.
Input
{"urls": ["DdcI4o0Prsz","DdcjXAeFyr8"]}
One Instagram post or reel per line. A full link or just the shortcode from it both work. No login and no cookies: this reads only the comments a signed-out visitor can see, which is the newest dozen or so per post. Accepted formats: https://www.instagram.com/p/DdcI4o0Prsz/, https://www.instagram.com/reel/DdcI4o0Prsz/, DdcjXAeFyr8.
Post links, reel links, IGTV links, the instagram.com/<name>/p/<code>/ form from a profile grid,
links with a ?img_index= on the end, and bare shortcodes are all accepted and all normalise to
the same thing. A profile link is rejected with a message saying so, rather than being
quietly treated as a post.
Most comments to return per post is also your budget control, since you pay per comment
returned. Setting it above about 14 has no effect other than telling you, in the run's OUTPUT
record, that it could not be filled.
Sample output
| query | found | status | shortcode | commentCount | totalComments | truncated | comments | comment_id | parent_id | author | author_id | text | like_count | posted_at | is_owner_reply | reply_count | raw | scrapedAt |
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| DdcI4o0Prsz | true | OK | <all comments found (full list)> | <parent comment id (empty for top-level)> | <written by the post's author> | 1970-01-01T00:00:00.000Z |
A real expanded row from a live run:
{"query": "DdcjXAeFyr8","found": true,"status": "OK","shortcode": "DdcjXAeFyr8","comment_id": "18073828469713536","parent_id": null,"author": "allisonlinda511","author_id": "26531589248","text": "🥰","like_count": 0,"posted_at": "2026-09-20T13:07:36.000Z","is_owner_reply": false,"reply_count": null,"raw": { "…": "the untouched source object" }}
And the run's OUTPUT record from that same run:
{"requested": 2,"returned": 25,"errors": [],"caps": [{"shortcode": "DdcjXAeFyr8","available": 14,"reason": "Instagram preloads only the newest 12 or so comments into a logged-out post page… This post has 990 comments in total; 14 were readable, so a limit of 30 cannot be filled."}]}
A miss comes back as a row with "found": false and is never charged.
Pricing
- Comment returned: $6 per 1,000 comments
Plus a $0.00005 start fee per run. Each event above is billed independently, only when it actually returns data — misses (found:false) are never charged.
You are billed per comment returned, not per post looked up. A post that comes back empty — deleted, comments off, age-gated, blocked — costs nothing beyond the flat start fee. A post that returns 11 comments bills 11.
That also means the practical cost of a post is roughly a dozen comments' worth, whatever your limit says.
Use it from Clay, n8n, Make, or an AI agent
This actor runs synchronously over plain HTTP — call it directly from a script, a workflow tool, or an AI agent, no Apify Console needed once you have an API token.
curl "https://api.apify.com/v2/acts/accountable_eel~ig-comments-scraper/run-sync-get-dataset-items?token=<YOUR_TOKEN>" \-X POST \-H "Content-Type: application/json" \-d '{"urls":["DdcI4o0Prsz","DdcjXAeFyr8"]}'
n8n. Add an HTTP Request node: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~ig-comments-scraper/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body Content Type JSON, JSON Body {"urls":["DdcI4o0Prsz","DdcjXAeFyr8"]} (swap in an expression from an earlier node for a real value).
Clay. Add an "HTTP API" column: Method POST, URL https://api.apify.com/v2/acts/accountable_eel~ig-comments-scraper/run-sync-get-dataset-items?token=<YOUR_TOKEN>, Body {"urls":["{{post}}"]}, mapping the row's post into the urls array.
MCP. In Claude, Cursor, or any MCP client with the Apify MCP server, ask for "Instagram Scraper API: Comments by Post URL" — the agent will find and run this actor.
Tips
- Schedule it hourly against a small set of posts. That is the design point. Each run adds the newest dozen comments, and over a day you accumulate the stream. A single run never will.
- Deduplicate on
comment_id. Consecutive scheduled runs will overlap, because the newest dozen changes slowly on a quiet post.comment_idis stable and unique. - Join on
author_id, label withauthor. Usernames change between runs; IDs do not. - Do not filter on
like_countorreply_count. Both are honest fields and both carry almost no information on this route, for the reasons in "What you can and cannot get".posted_at,text,author_idandis_owner_replyare the fields worth building on. - Use
is_owner_replyto find answered threads. For a brand monitoring its own posts, it is the cheapest available signal for "we already responded to this". - Watch the
OUTPUTrecord, not the row count.caps[]distinguishes "this post only has 11 comments" from "your limit of 500 was never reachable", anderrors[]names every post that missed and why. - Keep concurrency low. Instagram rate-limits aggressively. The default of 2 with a Residential proxy returned every row on the first attempt in testing; pushing it higher invites HTTP 429.
vs. alternatives
| This actor | A logged-in comment scraper | |
|---|---|---|
| Comments per post | the newest 10–14 | potentially all of them |
| Replies | no | usually yes |
| Needs an Instagram account | no | yes |
| Account restriction risk | none | yours |
| Billing | per comment returned, misses free | usually per comment too |
| Best at | monitoring recent comments on known posts, on a schedule | one-off deep exports of a whole post |
apify/instagram-comment-scraper, the category leader, sells at roughly $2.30 per 1,000
comments and does go deeper, because it does not work signed out. If you need depth, buy depth.
This actor is the cheaper, lower-risk half of the market: recent comments, no login, a frozen row
shape, and an honest statement of its ceiling.
Data & privacy
This actor reads only pages that Instagram serves to an ordinary signed-out visitor. It never logs in, never stores or transmits credentials, never sets or reuses a session cookie, and never touches private accounts or content behind a follow request.
Comments are written by identifiable people. The usernames, user IDs, profile pictures and text this actor returns are personal data under the GDPR and comparable laws, and you are the controller of whatever you collect. Have a lawful basis, keep only what you need, honour deletion requests, and do not use it to build profiles of individuals or to contact people who have not asked to hear from you. Instagram's own Terms of Use apply to you as well as to us.
FAQ
Why did I only get 11 comments when the post has 9,000?
Because Instagram shows a signed-out visitor the newest dozen and refuses every route past them.
The run's OUTPUT record says so explicitly, per post, with the count that was available. Nothing
is wrong with the actor and you were billed only for the 11.
Can I get older comments by running it again with a different setting? No. There is no setting that reaches them. Running it repeatedly over time accumulates new comments as they are written, which is the intended way to build depth.
Why is reply_count empty on every row?
Instagram's signed-out post page carries no reply data at all. The field is reported as empty
rather than as 0, because "unknown" and "none" are different answers and collapsing them would
mislead you.
Why is like_count zero almost everywhere?
The comments returned are the newest ones. A comment written minutes ago genuinely has no likes.
The field is read correctly; there is just nothing to read yet.
Does the "Include replies" switch do anything?
No, and it says so in its own help text. It exists so that saved inputs and API calls that set it
stay valid. Turning it on adds a note to the run's OUTPUT record.
Can I pass a profile link instead of a post link?
No — you will get a BAD_FORMAT row telling you to paste the post link. This actor works per post.
To go from a username to its posts, run Instagram Profile Scraper first and feed its
shortcode column in here.
What happens on a post with comments turned off?
A found: false row saying "comments disabled or none yet", and no charge. Instagram does not
distinguish "the author turned comments off" from "nobody has commented" to a signed-out visitor,
so the message names both possibilities instead of guessing.
Do I need a proxy? Yes, Residential. Apify's datacenter addresses are answered with HTTP 429 on this target; the Residential group returned every row on the first attempt. It is the default here.
Related actors
- Instagram Profile Scraper: Posts and Reels — usernames in, one row per post or reel out,
with captions, hashtags, engagement and media links. Its
shortcodecolumn is this actor's input.