Instagram Post Scraper - Captions, Likes, Media avatar

Instagram Post Scraper - Captions, Likes, Media

Pricing

from $0.17 / 1,000 instagram posts

Go to Apify Store
Instagram Post Scraper - Captions, Likes, Media

Instagram Post Scraper - Captions, Likes, Media

Scrape Instagram posts and reels from links or shortcodes. One row per post: caption, likes, comments, publish time, every carousel image and video URL, owner, hashtags, mentions, tagged users, location and music. $0.18 per 1,000 posts, less on paid plans.

Pricing

from $0.17 / 1,000 instagram posts

Rating

5.0

(1)

Developer

Dami's Studio

Dami's Studio

Maintained by Community

Actor stats

0

Bookmarked

60

Total users

21

Monthly active users

5 days ago

Last modified

Categories

Share

Paste Instagram post, reel or IGTV links and get one row per post: the full caption, like and comment counts, the exact publish time, every image and video URL including all the frames of a carousel, the owner, the hashtags, the mentions and the tagged users. Bare shortcodes work too, so a messy list is fine.

Two things are missing on purpose, and it is better to know now: there is no comment text, and videoViewCount is usually null, because Instagram does not publish the play count to a logged-out reader. Likes and comments are there on both posts and reels.

InputPost, reel or IGTV links, or bare shortcodes
OutputOne row per post: caption, likes, comments, publish time, every image and video URL, owner, hashtags, mentions, tagged users, location, music
Ceiling5,000 links per run
Account neededNone
Price$0.18 per 1,000 posts on the free plan, down to $0.174 on Business. The free plan's $5 a month covers about 27,000. Optional Facebook counts, paid plans only: $1.38 per 1,000 posts checked on Starter, down to $1.34 on Business

🔍 What Instagram Post Scraper does

You give it links, it gives you rows. instagram.com/p/<code>/, /reel/<code>/, /tv/<code>/, a link copied from a profile grid, or just DbtErSrlB2J on its own. Mix them freely in one run.

Carousels come back whole. images and videos hold every frame in carousel order, childPosts holds one object per frame with its own shortcode and dimensions, and childPostsCount tells you how many there were. A reel fills in videoUrl and videoDuration and carries type: "Video" with productType: "clips".

Duplicate links are removed before anything is charged, including the same post supplied once as a URL and once as a bare code. A link that is dead, deleted or withheld comes back as a free labelled row rather than a charge.

📋 What data you get from each Instagram post

What you getField
Link, shortcode and numeric idurl, shortCode, id
What kind of post it istype, productType, isReel
Caption, and the hashtags and handles in itcaption, hashtags, mentions
Likes and commentslikesCount, commentsCount
Video views and lengthvideoViewCount, videoDuration
Publish timetimestamp
Cover, video file and every carousel framedisplayUrl, videoUrl, images, videos, childPosts, childPostsCount
Size and alt textdimensionsWidth, dimensionsHeight, alt
The account that posted itownerUsername, ownerFullName, ownerId, ownerIsVerified, ownerIsPrivate, ownerProfilePicUrl, ownerProfileUrl
Tagged people, co-authors and sponsorstaggedUsers, coauthorProfiles, coauthorProducers, sponsorProfiles
Paid partnership, hidden likes, comments offisSponsored, isPaidPartnership, likesAndViewCountsDisabled, isCommentsDisabled
Location and musiclocationName, locationId, musicArtist, musicTitle
Facebook plays, likes and comments, as a paid extrafacebookPlayCount, facebookLikesCount, facebookCommentsCount, totalPlayCount, totalLikesCount, totalCommentsCount, instagramPlayCount, facebookCountsFound

▶️ How to scrape Instagram posts

  1. Open Instagram Post Scraper and click Try for free.
  2. Paste your links into Post or reel links, one per line.
  3. Set Maximum posts while you are testing, since you pay per post.
  4. Click Start.
  5. Download the dataset as JSON, CSV or Excel, or pull it from the Apify API.

Hand it no links at all and it writes one labelled sample row, which is not charged, so you can see the shape before spending anything.

💰 How much does it cost to scrape Instagram posts?

$0.18 per 1,000 posts. That is the free plan's price; paid plans pay a little less: $0.178 on Starter, $0.176 on Scale and $0.174 on Business. On the free plan, the $5 Apify gives you each month covers about 27,000 posts.

You pay per post row delivered. Duplicate links are collapsed before the run starts, so the same post is never charged twice. The sample row, every diagnostic row, and links that were never valid Instagram links cost you nothing.

Facebook counts, if you tick them: $1.38 per 1,000 posts checked on Starter, $1.36 on Scale and $1.34 on Business, on top of the post price. Every post checked is charged, whether or not Facebook numbers come back for it, and the option needs a paid Apify plan.

📥 What you give it

{
"postUrls": [
"https://www.instagram.com/p/DbtErSrlB2J/",
"https://www.instagram.com/reel/DcCH2ZygIiP/",
"DbwWBxpDm_0"
],
"maxItems": 10
}
FieldDefaultWhat it is
postUrlsnoneThe links you want. Up to 5,000 per run, duplicates removed first.
maxItemsnoneStop after this many posts, counting from the top of your list. Leave it empty to read every link. The input form starts you at 10.
includeFacebookCountsoffAdds Facebook plays, likes and comments for posts that were also shared to Facebook, plus the Instagram-and-Facebook totals. $1.38 per 1,000 posts checked on Starter, down to $1.34 on Business, on top of the post price, and it needs a paid Apify plan.
sessionCookiesnoneOptional, and rarely needed. Your own Instagram cookie, tried on a post a logged-out run could not read.
proxyUrlsnoneLeave it empty unless you have your own servers you want the traffic to leave through.

📤 What you get back

A real row from a run on 21 September 2026. The caption is cut short in the middle, the media links are trimmed, and the eight carousel frames are shown as two:

{
"ok": true,
"charged": true,
"recordType": "post",
"inputUrl": "https://www.instagram.com/p/DbtErSrlB2J/",
"id": "3957840214710558089",
"shortCode": "DbtErSrlB2J",
"url": "https://www.instagram.com/p/DbtErSrlB2J/",
"type": "Sidecar",
"productType": "carousel_container",
"isReel": false,
"isSponsored": false,
"caption": "Where in the (Martian) world is Curiosity?\n \nOur Curiosity Mars rover has started its climb up a Martian valley called Valle Grande. ...\n \n#NASA #Mars #CuriosityRover",
"hashtags": ["NASA", "Mars", "CuriosityRover"],
"mentions": [],
"likesCount": 284607,
"commentsCount": 1759,
"videoViewCount": null,
"likesAndViewCountsDisabled": false,
"isCommentsDisabled": false,
"timestamp": "2026-08-06T15:49:01.000Z",
"displayUrl": "https://scontent-mia3-3.cdninstagram.com/v/t51.82787-15/766074877_...",
"videoUrl": null,
"videoDuration": null,
"images": [
"https://scontent-mia3-3.cdninstagram.com/v/t51.82787-15/766074877_...",
"https://scontent-mia5-1.cdninstagram.com/v/t51.82787-15/766287913_..."
],
"videos": [],
"childPosts": [
{ "id": "3957839638910891589", "shortCode": "DbtEi6bPnZF", "type": "Image", "displayUrl": "https://scontent-mia3-3.cdninstagram.com/..." }
],
"childPostsCount": 8,
"dimensionsWidth": 495,
"dimensionsHeight": 292,
"alt": null,
"ownerId": "528817151",
"ownerUsername": "nasa",
"ownerFullName": "NASA",
"ownerIsVerified": true,
"ownerIsPrivate": false,
"ownerProfilePicUrl": "https://scontent-mia5-1.cdninstagram.com/v/t51.2885-19/...",
"ownerProfileUrl": "https://www.instagram.com/nasa/",
"coauthorProducers": [],
"coauthorProfiles": [],
"taggedUsers": [],
"sponsorProfiles": [],
"locationName": null,
"locationId": null,
"musicArtist": null,
"musicTitle": null,
"scrapedAt": "2026-09-21T01:45:41.661Z"
}
FieldHow to read it
typeImage, Video or Sidecar. Sidecar is Instagram's name for a carousel.
productTypeThe finer kind: feed, clips for a reel, carousel_container, igtv.
shortCodeUnique per post. The right key for joining runs together.
timestampWhen it was published, in UTC. It never moves, so sort and filter on this one.
likesCount, commentsCountA snapshot at read time. Both come back null when the account has hidden its counts, and likesAndViewCountsDisabled says so.
taggedUsers, coauthorProfiles, sponsorProfilesProfile objects with id, username, full name, link and picture. Tagged users carry x and y coordinates when Instagram supplies them.
locationName, musicTitle, altFilled in when the post carries them, null when it does not. Nothing is guessed.
facebookCountsFoundOnly with includeFacebookCounts on. true when Facebook numbers came back, false when Instagram showed the whole post and it carries none, null when this check could not tell.
totalPlayCount, totalLikesCount, totalCommentsCountInstagram and Facebook added together, the way Instagram's app shows a shared post. null unless Facebook numbers came back.

🧾 Reading the output

Three kinds of row land in your dataset, and one flag separates them.

RowHow to spot itBilled
A real postok: true and charged: trueyes
The sample row_sample: true, charged: falseno
A diagnostic_diagnostic: true, charged: false, an errorCodeno

Filter on charged == true and you have your posts. Do not filter on recordType: the sample row carries recordType: "post" too. Read charged as the marker that separates a real row from a sample or a diagnostic, not as a receipt.

CodeWhat it means
NOT_FOUNDInstagram says the post is gone, or the link is wrong.
LOGIN_REQUIREDThe post is real, but Instagram shows it only to signed-in viewers, so a logged-out run cannot read it.
BAD_INPUTThat entry is not an Instagram post link or a shortcode.
RATE_LIMITEDInstagram refused that link this time. Re-running usually clears it.
NOT_SERVEDThis post was not served this run. Re-run it later. Until 12 October 2026 this code was called BLOCKED.
SERVER_ERROR, NETWORKInstagram was unreachable or answered badly. Re-run it.
TIME_BUDGETThe run ran out of time before reading every link. One row lists the unread ones in unreadShortCodes. The run ends as failed only when the time limit stopped it before any post came back.
NO_RESULTSNothing in the list parsed at all, so the run stopped rather than working through dead links.
ENGINE_SWITCHEDThe run switched to a slower way of reading posts part way through. Nothing was lost and nothing extra was charged.
FACEBOOK_COUNTS_OFFYou ticked Facebook counts but this run could not use them: on a free Apify plan, or unavailable on this run. Nothing was looked up or charged for them.
FACEBOOK_COUNTS_STOPPEDFacebook counts stopped part-way, at the maximum cost you set for the run. Later posts have the Facebook fields empty.
PROXY_INPUT_ADJUSTEDA connection setting in your input could not be used and was replaced. The run carried on.
CHARGE_ERROR, UNEXPECTED_ERRORSomething went wrong inside the run. Not charged, and the run still ends normally.

A diagnostic row never fails the run and is never billed.

💡 What people use it for

  • Turning a list of links from a brief into a table of captions, counts and media, in one run.
  • Comparing how a competitor's carousels are built, frame by frame, for a creative review.
  • Logging the like and comment counts of the same posts weekly to see how they age. Re-running the same links is safe and gives you a fresh snapshot.

A campaign report in three steps:

  1. Paste the post and reel links your creators sent you here.
  2. Keep the rows where isReel is true and copy their url.
  3. Watch those reels and note the hook each one opens with.

🚧 What it does not do

  • No comment text. The count is there, the comments are not. Those come from Instagram Comments Scraper.
  • It will not walk a profile grid. Give it links. If you want an account's posts, use Instagram Scraper.
  • Nothing private. A post on a private account comes back as a free NOT_FOUND or LOGIN_REQUIRED row instead of data.
  • videoViewCount is usually null. Instagram does not publish the play count to a logged-out reader. Likes and comments are there.
  • A long list of dead links stops early. After 40 consecutive failures with nothing parsed, the run writes a NO_RESULTS row and stops rather than burning the rest of your list.
  • If the run hits its deadline, it stops a few seconds early, writes the posts it has, and adds one TIME_BUDGET row listing every link it did not read.
  • Media links expire. They are signed, short-lived links.
  • Facebook numbers are not on every shared post. They exist only for posts the account also shared to Facebook, and Instagram does not show the Facebook side on every check. When it holds it back, the row says facebookCountsFound: null and the check is still charged.
  • It is not an official Instagram tool. Dami's Studio is independent and is not affiliated with or endorsed by Instagram or Meta, or by any other company named on this page.

🧭 Which Instagram scraper do you need?

If you wantUse
Posts and reels from links you already haveThis one
Posts from an account's gridInstagram Scraper
One row per account, with engagementInstagram Profile Scraper
Comments under a post or reelInstagram Comments Scraper
Play counts for the reels on a profileInstagram Reel Scraper
Posts under a hashtagInstagram Hashtag Scraper
Posts that tag or mention an accountInstagram Mentions Scraper

❓ Questions people ask

Do I need an Instagram account to scrape posts?

No. Public posts are read logged out, and that covers the vast majority of links. The cookie field is optional and takes your own Instagram cookie.

No. One row, one charge, however many frames are in it.

Why do the numbers differ from what I see in the app?

Likes and comments are a snapshot at read time, so they drift from what you see later. If a post comes back LOGIN_REQUIRED, open it in a private browser window to see whether Instagram asks you to log in there too.

Why is the view count empty on reels?

Instagram does not show play counts to a logged-out reader on a single post. For play counts across a profile's reels, use Instagram Reel Scraper from the table above.

Can I call it from code or connect it to an AI assistant?

Yes. The API tab has ready-made code for Python, JavaScript and the command line. For Claude, ChatGPT or another MCP client, connect https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/instagram-post-scraper. Either way the run happens on your Apify account at the same price.

This reads public posts only, never private accounts or messages. Results can still contain personal data, which GDPR and similar laws cover, so have a reason for collecting it. Apify's write-up on the legality of web scraping is a good starting point, and we are not lawyers.

🆘 If something breaks

Open the Issues tab on the actor page. Include one of the links that failed and the run ID, and the log is enough for us to see what happened.