Instagram Hashtag Scraper - Posts, Reels, Likes & Captions
Pricing
from $0.38 / 1,000 posts
Instagram Hashtag Scraper - Posts, Reels, Likes & Captions
Instagram hashtag scraper: the posts and reels under a hashtag, one row per post with caption, likes, comments, video views, image and video URLs, owner, mentions and timestamp. A tag feed is the slice Instagram chooses to show, not every post ever tagged. $0.40 per 1,000 posts.
Pricing
from $0.38 / 1,000 posts
Rating
5.0
(2)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
199
Total users
75
Monthly active users
3 hours ago
Last modified
Categories
Security
Limited permissionsShare
Instagram hashtag scraper for the posts and reels under a tag: caption, like and
comment counts, image and video URLs, owner, place, sound and timestamp, one row per post. If you
already have /explore/tags/ links, paste those instead, or search by words.
One thing to know before you start, because it changes what you should expect: a hashtag feed is a sample, not an archive. On the free Apify plan a run returns one page, up to 24 posts.
| Input | Hashtags, /explore/tags/ URLs, or search words |
| Output | One row per post or reel: caption, likes, comments, video views, image and video URLs, owner, place, sound, tagged accounts, hashtags, timestamp |
| Ceiling | 5,000 posts per run |
| Account needed | None |
| Price | $0.40 per 1,000 posts on the free plan, down to $0.385 on Business. The free plan's $5 a month covers about 12,500 |
| Using an AI agent? | |
|---|---|
| Actor | dami_studio/instagram-hashtag-scraper |
| Set one field | hashtags, labelled "Hashtags" in the Console |
| Cap the bill | maxTotalChargeUsd on the run, for example 0.10: it never charges past that |
| MCP, one link | https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/instagram-hashtag-scraper |
| How often | Daily, for new top posts under a hashtag |
🔍 What Instagram Hashtag Scraper does
You type tags, it returns the posts sitting under them, photos, videos and carousels in one row shape.
You don't need an Instagram account or any API approval.
Which posts picks the feed: a tag's top posts (the default), only its reels, or its newest posts first. Search words find posts and reels by a phrase instead of a tag. Max posts per tag stops the first tag from taking the whole run, and Only posts newer than skips older posts without charging for them.
Optional add-ons, off unless you tick them: photos and carousels only, each tag's post count, the poster's Facebook page and Threads link, comments, Instagram and Facebook plays, and share counts. When one can't be used on a run, a free row says so.
A cookie in sessionCookies is optional. Most people never need it.
📋 What data you get from each Instagram hashtag post
| What you get | Field |
|---|---|
| What the post is: a photo, a reel, a video or a carousel | type, isVideo, postType |
| Link, shortcode and the full post id | url, shortCode, id |
| Caption, and the hashtags and handles in it | caption, hashtags, mentions |
| Likes, comments and video views | likesCount, commentsCount, videoViewCount |
| Whether the likes are hidden or comments are off | likesHidden, commentsDisabled |
| Cover image, video file, carousel frames and size | displayUrl, videoUrl, images, dimensions |
| Video length, and a carousel's slides | videoDuration, slideCount, slideTypes |
| Who posted it and when | ownerUsername, ownerId, timestamp |
| The poster's name, ticks and links | ownerFullName, ownerIsVerified, ownerIsPrivate, ownerProfileUrl, ownerProfilePicUrl |
| The place, when the post names one | locationName, locationId, locationCity, latitude, longitude |
| The sound on a reel, and a link to it | audioTitle, audioArtist, isOriginalAudio, audioUrl |
| Paid partnership, sponsors, tagged accounts, co-authors | isPaidPartnership, sponsors, taggedUsers, coauthors |
| Instagram's alt text | accessibilityCaption |
| Which of your tags or search words found it | hashtag, searchTerm |
| Add-on: the tag's id and post count | hashtagId, hashtagPostsCount |
| Add-on: the poster's Facebook page and Threads profile | ownerFacebookPageName, ownerFacebookPageUrl, ownerThreadsUrl |
| Add-on: comments, in the order Instagram shows them | topComments (text, author, likes, replies, time) |
| Add-on: Instagram plays, Facebook plays and likes | instagramPlayCount, facebookPlayCount, facebookLikesCount, facebookCountsFound |
| Add-on: shares | sharesCount |
| The tag's id and post count, when you supply a cookie | hashtagId, hashtagPostsCount |
▶️ How to scrape Instagram hashtags
- Open Instagram Hashtag Scraper and click Try for free.
- Type one or more tags into Hashtags (the
#is optional), or a phrase into Search words. - Set Max posts, and Max posts per tag if you give several. Start at 50 to see the output shape.
- Click Start.
- Download the dataset as JSON, CSV or Excel, or pull it from the Apify API.
Give it at least one tag. With nothing in either field you get one uncharged BAD_INPUT row, not a failed run.
💰 How much does it cost to scrape Instagram hashtags?
$0.40 per 1,000 posts. That is the free plan's price; paid plans pay a little less: $0.395 on Starter, $0.39 on Scale and $0.385 on Business. On the free plan, the $5 Apify gives you each month covers about 12,500 posts. On the free plan a run stops after one page and says so in a free row; a paid plan gets the full run.
You pay per post delivered. The same post found under two of your tags is billed once. Diagnostic rows, posts your date filter leaves out and a tag that returns nothing cost you nothing.
The add-ons are billed from 9 November 2026. Before that day the photos-only filter is free, and asking for one of the other five, which need a paid Apify plan, gets a free row saying it hasn't started.
| Add-on, from 9 November 2026 | Price |
|---|---|
photosOnly | $0.25 per 1,000 posts it leaves out on the Free plan, a little less on paid plans |
includeHashtagStats | $4.94 per 1,000 tags on Starter |
includePosterLinks | $4.94 per 1,000 posters on Starter |
includeFacebookCounts | $4.94 per 1,000 posts on Starter |
includeShareCount | $4.94 per 1,000 posts on Starter |
commentsPerPost | $0.395 per 1,000 comments on Starter |
Scale and Business pay a little less than Starter.
📥 What you give it
{"hashtags": ["coffee", "latteart"],"resultsLimit": 50,"maxPostsPerHashtag": 25}
| Field | Default | What it is |
|---|---|---|
hashtags | none | Tags with or without the #. A space inside a tag is joined up (new york is read as newyork) and the log says so. |
startUrls | none | Or paste /explore/tags/… URLs. Either works, and you can mix them. |
searchTerms | none | Words or phrases to find posts and reels by. Up to 10, read after your tags. |
feed | top | top for what a tag shows first, reels for its reels only, recent for its newest posts (mostly photos and carousels). Tags only. |
newerThan | none | A day like 2026-10-01 or a window like 7 days. Older posts are skipped and not charged. |
resultsLimit | 50 | Posts for the whole run, not per tag. 1 to 5,000. This is also your spend cap. |
maxPostsPerHashtag | none | The most posts from each tag or search word, 13 to 5,000. |
photosOnly | false | Optional add-on: photos and carousels only, reels and other videos left out. Not with feed: reels. |
includeHashtagStats | false | Optional add-on: each tag's id and post count on its rows. |
includePosterLinks | false | Optional add-on: the poster's linked Facebook page and Threads profile. |
commentsPerPost | none | Optional add-on: up to this many comments a post, 1 to 15, on posts with enough comments. |
includeFacebookCounts | false | Optional add-on: Instagram plays, and Facebook plays and likes for posts shared there. |
includeShareCount | false | Optional add-on: how many times each post was shared. |
sessionCookies | none | Optional. Your own Instagram cookie, used only for your run. |
proxyConfiguration | none | Leave it alone unless you have your own servers to use. |
notionConnector, notionParentId | none | Optional. Write each post into a Notion database as well as the dataset. |
📤 What you get back

A real row from a run on 24 October 2026, with the caption and links cut short and the people replaced by stand-ins:
{"ok": true,"type": "video","shortCode": "De4fY_-MMdh","url": "https://www.instagram.com/p/De4fY_-MMdh/","caption": "🐺 Happy Wolf Awareness Week! 🐺 ... #wolfawarenessweek #wolvesofgrandteton #nature #wolfconservation #wildlife","hashtags": ["wolfawarenessweek", "wolvesofgrandteton", "nature", "wolfconservation", "wildlife"],"mentions": [],"likesCount": 1293,"commentsCount": 29,"videoViewCount": 10527,"displayUrl": "https://scontent-lax3-2.cdninstagram.com/v/t51.82787-15/...","videoUrl": "https://scontent-lax3-1.cdninstagram.com/o1/v/t2/...","images": ["https://scontent-lax3-2.cdninstagram.com/v/t51.82787-15/..."],"isVideo": true,"dimensions": {"height": 1333, "width": 750},"ownerUsername": "example_account","ownerId": "1234567890","timestamp": "2026-10-24T15:50:11.000Z","accessibilityCaption": null,"hashtag": "nature","searchTerm": null,"id": "4015097125199202145","postType": "reel","ownerFullName": "Example Name","ownerIsVerified": true,"ownerIsPrivate": false,"ownerProfileUrl": "https://www.instagram.com/example_account/","ownerProfilePicUrl": "https://scontent-lax3-2.cdninstagram.com/v/t51.82787-19/...","locationName": "Grand Teton National Park","locationId": "213877293","locationCity": null,"latitude": 43.653450402378,"longitude": -110.71791887283,"likesHidden": false,"commentsDisabled": false,"videoDuration": 45.37,"slideCount": null,"slideTypes": null,"audioTitle": "Original audio","audioArtist": "example_account","isOriginalAudio": true,"audioUrl": "https://scontent-lax3-2.cdninstagram.com/o1/v/t2/...","isPaidPartnership": false,"sponsors": [],"taggedUsers": [],"coauthors": [{"username": "example_coauthor", "id": "3456789012", "isVerified": false}]}
| Field | How to read it |
|---|---|
hashtag, searchTerm | Which of your tags or search words produced this row. The other one is null. |
shortCode, id | Unique per post. id is 19 digits: keep it as text, a spreadsheet number cuts it. |
likesCount | Empty when the poster hid the likes (likesHidden: true). |
videoViewCount | 0 on stills. |
displayUrl, videoUrl, images, audioUrl, ownerProfilePicUrl | Direct links, signed and time limited. The run never downloads or keeps the files; save what you need. |
locationName, audioTitle, taggedUsers and the rest | null or [] when the post does not carry them. Nothing is guessed or padded. |
🧾 Reading the output
Three kinds of row can land in your dataset, and only the first kind costs anything.
| Row | How to spot it | Charged |
|---|---|---|
| A real post | ok: true and a shortCode | yes |
| A sample post | _sample: true, charged: false | no |
| A diagnostic | ok: false and an errorCode | no |
Filter on ok == true and drop any row carrying _sample: true, and you have your posts. The
errorCode on a diagnostic row tells you what happened:
| Code | What it means |
|---|---|
BAD_INPUT | An option has a value it cannot use, such as a date it cannot read. Nothing was read. |
NO_RESULTS | The tag came back empty, or none of its posts passed your date filter. It may be new, misspelled or restricted. |
FREE_PLAN_LIMIT | You are on the free Apify plan, so the run read only part of your input. hashtagsNotRead lists what it skipped. A paid plan gets the full run. |
OPTION_STARTS_SOON | An add-on you ticked was asked for before the add-ons started on 9 November 2026. The posts came as usual without it. |
OPTION_OFF | An add-on you ticked could not be used on this run (some need a paid Apify plan). The posts came as usual. |
OPTION_PARTIAL | An add-on stopped part-way, for example at your spending limit. Posts after that point came without it. |
PARTIAL | The run stopped early on that tag, either because it reached the most posts one run can collect or because posts stopped coming, or your spending limit had no room for a single post. What arrived is complete and charged. A new run starts again from the top. |
NOT_FOUND | No tag by that name answered on this run. Check the spelling, then try that tag again later. |
RATE_LIMITED | Too much traffic on that tag just now. Try again shortly. |
AUTHENTICATION_FAILED | The tag could not be read this time. If you supplied a cookie, check it is still valid. |
NOT_SERVED | This post was not served this run. Re-run it later. Runs before 13 October 2026 wrote BLOCKED here. |
SERVER_ERROR, NETWORK | Instagram was unreachable or answered badly. Re-run it. |
TIME_LIMIT | The run reached its time limit and stopped on its own. The posts delivered before that are complete and charged. Give the run more time, or ask for fewer posts, to get the rest. |
UNEXPECTED_ERROR | The run stopped early on an unexpected error. The results before this row are kept. |
A diagnostic row never bills you. It doesn't fail the run either, TIME_LIMIT included: a run the time limit
stopped before any post came back still ends as succeeded, with an amber status message.
The run's key-value store also holds one free record, TAGS_SEEN_WITH: for each of your tags and search
words, the other tags in the captions of the posts delivered, with how many posts carried each. It
describes this run's posts, not the whole tag, and it is not Instagram's own related-tag list.
💡 What people use it for
- Watching a niche tag for a week to see which accounts keep showing up in it.
- Pulling a few thousand captions to find out what wording actually gets engagement in a category.
- Building a shortlist of creators posting under a branded or event tag, then checking them by hand.
From a tag to a shortlist of creators, in three steps:
- Run this on a tag in your niche and copy the
ownerUsernamecolumn. - Paste those handles into
Instagram Profile Scraper and sort on
followersCount. - For the accounts worth a closer look, run Instagram Scraper on their usernames to see everything on their grid.
🚧 What it does not do
- No comments. This returns posts. Comments are a separate actor, linked below.
- A tag feed is a sample. You get a slice rather than the full history of a tag, however high you set the limit.
- A big ask can stop early. A run that asks for thousands can reach the most posts one run can
collect and stop there with a
PARTIALrow. The posts delivered are complete and charged, and a new run starts again from the top. - Media URLs expire. They are signed links, not permanent addresses.
- No private accounts. Public posts on public tags, nothing else.
- Newest first is mostly photos and carousels. For a tag's reels, pick Reels only.
- A date filter skips, it does not dig.
- An empty input reads nothing. You get one uncharged
BAD_INPUTrow; give it at least one tag. - 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 want | Use |
|---|---|
| Posts under a hashtag | This one |
| Everything one profile has posted | Instagram Scraper |
| Bio and counts for the accounts behind those posts | Instagram Profile Scraper |
| One post or reel you already have the link for | Instagram Post Scraper |
| Comments under a post or reel | Instagram Comments Scraper |
| Reels found by keyword or hashtag | Instagram Reels Search |
| Posts tagged at a place | Instagram Location Scraper |
| Videos under a TikTok hashtag | TikTok Hashtag Scraper |
❓ Questions people ask
Do I need an Instagram account to scrape hashtags?
No. Nothing to paste. The cookie field is optional and most people leave it empty.
Will I get every post ever tagged?
No. You get a slice of a tag feed.
Is resultsLimit per tag or per run?
Per run. Ask for 100 across three tags and you get 100 posts in total, not 300. To share them out,
set maxPostsPerHashtag too, say to 34.
Why do the numbers differ from what I see in the app?
Open the tag in a private browser window. Likes and comments are a snapshot at read time.
Can I call it from code or connect it to an AI assistant?
The API tab has code for Python, JavaScript and
the CLI. MCP clients like Claude and ChatGPT use
https://mcp.apify.com/?tools=fetch-actor-details,dami_studio/instagram-hashtag-scraper; coding assistants can load
our skill file. All
three bill your Apify account at the same price.
# pip install apify-clientfrom apify_client import ApifyClientclient = ApifyClient("YOUR_APIFY_TOKEN")run = client.actor("dami_studio/instagram-hashtag-scraper").call(run_input={"hashtags": ["nature"],"resultsLimit": 20,},max_total_charge_usd=0.10, # the most this run may spend)for row in client.dataset(run["defaultDatasetId"]).iterate_items():if row.get("ok") is False: # free note rows, not resultscontinueprint(row.get("likesCount"), row.get("url"))
Is scraping Instagram legal?
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 the hashtag you used and the run ID, and the log is enough for us to see what happened.