Instagram Scraper - Profiles, Posts, Hashtags & Comments
Pricing
from $1.99 / 1,000 results
Instagram Scraper - Profiles, Posts, Hashtags & Comments
Pricing
from $1.99 / 1,000 results
Rating
0.0
(0)
Developer
Lantern Lab
Maintained by CommunityActor stats
0
Bookmarked
2
Total users
1
Monthly active users
7 days ago
Last modified
Categories
Security
Limited permissionsShare
Give it Instagram usernames, post or Reel URLs, or hashtags and get the public data back: profile details, and for every post its caption, hashtags, publish time, likes, comment count, views, image and video URLs and author - plus the post's comments, page after page, not just the first 15. No Instagram login, no cookies, no account of your own. $1.99 per 1,000 results plus $0.005 per run. See Pricing.
What makes it different
- Comments past the first page. Instagram shows about 14 comments per page; this Actor keeps paging until it has the number you asked for. When Instagram stops early, the post says so (
commentsComplete: falseandcommentsPartialReason) instead of passing a short list off as all there is. - Your limits are hard limits.
maxPostsPerProfile,maxPostsPerHashtagand the comment limits are never exceeded, and you are never charged for more than you asked for. - The date filter works.
newerThankeeps only posts published since that date. On a profile it stops at the first older post below the pinned ones, so an old pinned post never cuts the list short. - Pinned posts once. Pinned posts carry
isPinned: true, are written at most once per run, and can be left out withskipPinnedPosts. - Hashtag results really carry the hashtag. A post is returned for
#moononly if its own caption contains#moon. Posts that merely mention the word are read, dropped and not charged. - No duplicates. Profiles, posts and comments are deduplicated across the whole run by Instagram's own IDs; a repeat is written and charged once. A post URL whose post an earlier profile or hashtag input already wrote still gets the comments it asks for.
- Empty, blocked and failed is free - and labelled. Every input gets a free
input_statusrow. An input Instagram refused, or one cut short by a limit, is markedpartial: truewith a reason - never reported as "zero posts".
Input
{"usernames": ["nasa"],"postUrls": ["https://www.instagram.com/p/DX7RFLbk8B6/"],"hashtags": ["artemis"],"maxPostsPerProfile": 24,"maxPostsPerHashtag": 20,"maxCommentsPerPost": 100,"newerThan": "30 days","skipPinnedPosts": true}
| Field | What it does |
|---|---|
usernames | nasa, @nasa or a profile URL. Returns a profile row plus its newest posts. |
postUrls | /p/<code>/ or /reel/<code>/ URLs. Returns the post plus its comments. |
hashtags | tag or #tag. Returns public posts whose caption carries the hashtag. |
maxPostsPerProfile | Posts per profile, newest first. Default 12, up to 500. |
maxPostsPerHashtag | Posts per hashtag. Default 20, up to 100. |
maxCommentsPerPost | Comments per post URL. Default 50, up to 5,000; 0 turns them off. |
maxCommentsPerListedPost | Comments per profile or hashtag post. Default 0 (off). |
newerThan | 2026-10-01, an ISO time, or 7 days / 2 weeks / 3 months. Applies to profile and hashtag posts. |
skipPinnedPosts | Leave pinned posts out of profile results. Default off. |
maxUpstreamRequests | Optional hard ceiling on requests. By default the Actor works one out from your inputs, so a run is never unbounded. |
proxyConfiguration | Default: Apify Proxy (datacenter). A refused request is retried once on a residential IP. |
Output
Every row has a recordType. Dataset views: Posts, Comments, Profiles, Input status.
post
{"recordType": "post","postId": "3889777825826455674","shortcode": "DX7RFLbk8B6","url": "https://www.instagram.com/p/DX7RFLbk8B6/","type": "Sidecar","productType": "carousel_container","caption": "Start your week with some new photos from Artemis II! ...","hashtags": ["nasa", "artemis", "photodump"],"mentions": [],"publishedAt": "2026-05-04T18:01:15.000Z","publishedAtEpoch": 1777917675,"likeCount": 397148,"commentCount": 1326,"viewCount": null,"displayUrl": "https://scontent-....cdninstagram.com/...","videoUrl": null,"mediaUrls": ["https://scontent-...", "https://scontent-...", "https://scontent-...", "https://scontent-..."],"ownerId": "528817151","ownerUsername": "nasa","ownerFullName": "NASA","ownerIsVerified": true,"coauthors": ["nasaartemis"],"locationName": null,"isPinned": null,"commentsRequested": 100,"commentsCollected": 100,"commentsComplete": true,"commentsPartialReason": null,"inputKind": "post","inputValue": "https://www.instagram.com/p/DX7RFLbk8B6/","rank": 1,"partial": false,"partialReason": null,"collectedAt": "2026-10-30T12:54:08.945Z"}
type is Image, Video or Sidecar (a carousel); productType: "clips" is a Reel. publishedAt is Instagram's publish time; collectedAt is when this run read it. isPinned is true/false on profile posts and null where Instagram does not say. viewCount is filled where Instagram shows it to logged-out visitors (profile Reels and videos) and is null elsewhere - it is never estimated.
comment - commentId, postId (the parent post), postShortcode, postUrl, parentCommentId (the comment it replies to; null on a top-level comment), text, publishedAt, likeCount, ownerUsername (the commenter's public username only), ownerIsVerified, rank, collectedAt.
profile - userId, username, fullName, biography, externalUrl, followersCount, followsCount, postsCount, isVerified, isPrivate, isBusinessAccount, category, profilePicUrl, profileUrl, collectedAt. No e-mail addresses or phone numbers are collected.
input_status (free) - one per input: postsReturned, commentsReturned, rowsCharged, duplicatesSkipped, pinnedSkipped, olderSkipped, unrelatedSkipped, partial, partialReason and a plain-English statusText.
RUN_SUMMARY (free) - the last row, and the same object in the key-value store: totals, partial inputs by reason, requests sent, and why the run stopped if it stopped early.
Partial reasons
partialReason | Meaning |
|---|---|
comments_not_public | Instagram stopped paging comments before its own count. The count includes replies and comments it does not show to logged-out visitors. |
search_results_exhausted | A hashtag's public search results ran out before maxPostsPerHashtag. |
candidate_limit | A hashtag read 3 search results per post asked for without filling the limit (most did not carry the hashtag or were filtered out). |
private_account | The profile is private; its profile row is returned, its posts are not public. |
not_found | No public profile or post by that name (deleted, renamed, restricted or never existed). |
gated | Instagram withholds the post from logged-out visitors (age or region restriction). |
blocked | Instagram refused the requests, also on a fresh residential IP. Not an empty result. |
upstream_error / unexpected_shape | A request failed, or the answer was not in a shape the Actor knows. Not an empty result. |
upstream_request_cap | The run reached maxUpstreamRequests. |
charge_limit_reached | The maximum charge you set for the run was reached. |
not_collected | The run stopped before reaching this input. |
Limits, stated up front
- Public content only, no login. Private accounts, Stories, highlights, and anything that needs an Instagram account are out of scope.
- Hashtags come from public web search. Instagram's own hashtag feed requires a login. This Actor finds hashtag posts through public search results, then checks each post's caption. You get real, matching posts - but not Instagram's complete or newest-first hashtag feed, and popular accounts are over-represented. When the search results run out the hashtag is marked
search_results_exhausted. - Replies are not shown to logged-out visitors. Comments are top-level comments;
parentCommentIdis filled only when Instagram provides it. Instagram'scommentCountincludes replies, which is why a post can have fewer collectable comments than its count. - Views. Instagram shows a view count logged-out only for some videos; elsewhere
viewCountisnull. - Transcripts of Reels are not part of this Actor.
Pricing
Pay per result: $1.99 per 1,000 results, plus $0.005 per run (start fee). A result is one profile, post or comment row. input_status rows, the run summary, duplicates, filtered posts and anything an input could not return are free, so a blocked or empty input costs nothing beyond the start fee. Example: one profile with 50 posts and 20 comments each = 1 + 50 + 1,000 = 1,051 results ≈ $2.10.
How it works
Plain HTTP requests to the same public endpoints Instagram's own logged-out web page uses, through Apify Proxy (datacenter by default, residential only as a fallback). Profiles come from Instagram's public profile endpoint (newest 12 posts in one request, then the profile grid's own pages); posts and comments from the logged-out post page and its comment pages. No browser, no login, no cookies of your own.