Instagram Hashtag Scraper & Instagram Reels Search, No Login avatar

Instagram Hashtag Scraper & Instagram Reels Search, No Login

Pricing

from $1.35 / 1,000 reels

Go to Apify Store
Instagram Hashtag Scraper & Instagram Reels Search, No Login

Instagram Hashtag Scraper & Instagram Reels Search, No Login

Scrape Instagram hashtags and keywords: an Instagram keyword search and hashtag scraper for the top reels of any hashtag or keyword. Per reel the caption, exact time, plays, likes, comments, owner and full name, music, location, tags and video URLs; per hashtag its post count. Misses free.

Pricing

from $1.35 / 1,000 reels

Rating

0.0

(0)

Developer

Hyperbach

Hyperbach

Maintained by Community

Actor stats

0

Bookmarked

15

Total users

8

Monthly active users

9 hours ago

Last modified

Features

Limited permissions

Share

Instagram's top reels for any hashtag or keyword, as data, logged out. Give hashtags (natgeo, #natgeo, a hashtag link) or search keywords (skincare routine) and get Instagram's own ranked list of reels for each, in its order, to the list's end — each reel with its whole caption and its hashtags and mentions, the exact publish time, the plays, the likes (null when the owner hides them, never a fake number), the comment count, the duration, the owner with their full name, the music title and artist, the location, the tagged accounts, the coauthors, the latest comments, Instagram's topic tags and alt text, and the video, cover and audio URLs with the time they expire. Every hashtag or keyword also gets a free search row: the hashtag's post count, Instagram's related keywords and its description of the term, how many reels the list held and a verdict (COMPLETE: the list ended; CAPPED: your limit came first). No login, no Instagram account, no cookie, proxies handled for you.

$2.70 per 1,000 reel rows on the Free plan, $2.295 on Starter. A run start is $0.0018. The default input returns about 20 rows for about $0.0558. A value that names nothing is a free row that says why.

An Instagram reel page in a browser: an invented reel of a tide pool by the verified account saltmarsh.field at Kelder Point, with its caption and hashtags, its plays, likes and comments. Beside it, a part of the row this Actor returns for that reel: owner_followers, the owner's follower count, and rank, the reel's place in Instagram's ranked list for the hashtag, are highlighted; then the keyword, the plays, the likes, the comment count, the owner's username and verified badge, the location and the hashtags.

Tested head-to-head on 2026-11-01

The job: the posts of one hashtag (natgeo), 20 posts. Every Actor ran on it the same day from the same harness; a rival's cost is what a buyer account paid, this Actor's is its list price on the Free plan. Fields counts the filled fields of a typical row. Re-measured monthly.

ActorRowsFirst rowRun timeCostFieldsFailures
this Actor2011 s15 s$0.04849none
apify/instagram-hashtag-scraper2030 s36 s$0.04622none
apify/instagram-scraper201.4 s1.5 s$0.04622none

Why this Instagram hashtag scraper

  • Instagram's own top list, to its end. Instagram ranks about 50 to 70 reels for a hashtag or keyword (natgeo 59, nature 53, six ordinary keywords 58 to 70 on our runs). This Actor reads the list to Instagram's own end flag and says so on the search row (COMPLETE, with the list's length); a shorter dataset is never silent. Each row has its rank, 1 = the top.
  • The fields other hashtag scrapers leave out. The owner's full name and the music title and artist come from each reel's own record, read for every reel by default: on natgeo's 59 reels, 59 owner names, the music on all 54 that carry a sound asset, 38 locations, the latest comments on all 59. Turn includeDetails off for a faster run with the lists' fields only.
  • Counts that do not lie. A reel whose owner hides its likes gets likes null and likes_hidden true; Instagram serves a placeholder number for those, and some scrapers deliver it or -1 as the count. The plays are Instagram's own counter from the ranked list, not Facebook's and not the smaller embed counter (that one is views, on request).
  • The hashtag's figures for free. Each input's search row carries the hashtag's post count as Instagram shows it (natgeo 27,862,149; a phrase's joined hashtag, e.g. skincareroutine 38.8 M), Instagram's related keywords (up to 48), its own description of the term, and the averages and top creators over the reels delivered.
  • Hashtags typed any way. #NatGeo, natgeo, a hashtag link and a popular-page link are one term: Instagram's list is case-sensitive, so the term is lower-cased; accents and other scripts are kept (ラーメン works; café and cafe are two terms). A term Instagram does not know is a free row that says so, after a second connection agrees.
  • One row per reel, free rows for the rest. A reel listed under two of your hashtags is one row and one charge. A reel a filter leaves out, an input with no list: free. maxReelsPerInput gives exactly that many when the list holds them.
  • Plain HTTP, no browser. Instagram's own logged-out answers: no login, no cookie, no account of yours, nothing to configure. On our test from a laptop the first row came 3.6 seconds after the start and two hashtags' 112 reels with every detail in 26 seconds.

Who it's for

  • Marketers and brand teams — the reels that rank for a campaign hashtag or a product keyword right now, with their plays, likes, comments, music and creators, and the hashtag's size.
  • Influencer and creator scouts — the creators who rank for a niche's hashtags and keywords, with their full names, verified flags and, on request, their follower counts and engagement per follower.
  • Trend and music researchers — which sounds, topics and captions rank for a term, across related keywords in one run, with the exact publish times.
  • Developers and data teams — typed rows keyed by the media id with Instagram's rank, one free search row per input, a run summary to check a pipeline against.

Quick start

A hashtag's top 20 reels

{
"hashtags": [
"natgeo"
],
"maxReelsPerInput": 20
}

Several keywords to the end of their lists

{
"keywords": [
"skincare routine",
"street food bangkok"
],
"maxReelsPerInput": 100
}

A hashtag and its related keywords, the last 30 days only

{
"hashtags": [
"sourdough"
],
"maxReelsPerInput": 50,
"relatedKeywordsDepth": 3,
"newerThan": "30 days"
}

A fast light run: the lists' fields only

{
"hashtags": [
"natgeo",
"nature"
],
"maxReelsPerInput": 100,
"includeDetails": false
}

Switching from apify/instagram-hashtag-scraper?

Your input works as it is. Each name in the left column is read as this Actor's own field and the run log says so (read <theirs> as <ours>); a name marked not read is ignored with a note. A value in the other Actor's shape, an object list or its own date form, is read too.

apify/instagram-hashtag-scraperthis Actorwhat to know
hashtagshashtagsThe same name: hashtags with or without #, or hashtag links.
keywordSearchnot readRead as a switch: with it on, the hashtags list is read as keywords (the run log says so).
resultsTypenot readNot read: this Actor reads reels. For a profile's posts use the Instagram Posts Scraper.
resultsLimitmaxReelsPerInputReels per hashtag or keyword, in Instagram's order.

What differs:

  • This Actor reads the ranked reels of a hashtag or keyword, with each reel's exact plays, likes and comments; resultsType: posts or stories is not a list it reads.
  • A keyword is its own list here (keywords); the leader's keywordSearch: true switch is read and moves the hashtags list into it.
  • The cap is maxReelsPerInput (20 by default, 100 = the whole ranked list); resultsLimit fills it.

Output

One row per reel (and one free search row per hashtag or keyword):

fieldmeaning
record_typereel (a reel of a ranked list: charged when status is ok) or search (a free row per hashtag or keyword: the hashtag's figures and what the walk read, or why the input gave no reel).
statusA reel: ok. A search row: ok (see verdict), no_ranked_list (Instagram knows the term — its description is in description — and shows no ranked reels list for it; two exits agree), unknown_term (Instagram does not know the term as typed; two exits agree: try another spelling), invalid_input (the value names no hashtag or keyword), failed, not_read (maxItems, the charge limit or the time limit came first).
inputThe value you gave that led to this row (a related keyword's own text on its rows).
input_typehashtag, keyword, related (a related keyword walked with relatedKeywordsDepth) or invalid.
keywordThe term Instagram's ranked list was read for: your value lower-cased, without # or the link's path.
related_toOn a related keyword's rows: the input whose related keyword it is.
rankThe reel's place in Instagram's ranked list for the keyword, 1 = the top.
idInstagram's media id (pk) of the reel. One row per id in a run.
shortcodeThe reel's shortcode (instagram.com/reel/<shortcode>/).
urlThe reel's link.
typereel for a reel (product_type clips), video for a feed video Instagram puts on a ranked list now and then (product_type feed; it has no plays), carousel for a carousel. Without includeDetails it is read from the list: a reel carries a sound kind, a feed video none.
product_typeInstagram's own type of the media (clips for a reel), from the reel's record (includeDetails).
timestampThe exact publish time (UTC, ISO 8601).
taken_atThe exact publish time as a Unix timestamp (seconds).
captionThe caption in full.
hashtagsThe hashtags of the caption, in order, without #.
mentionsThe accounts the caption mentions, without @.
caption_is_editedTrue when the caption was edited after publishing (includeDetails).
caption_created_atWhen the caption's current text was written (UTC; includeDetails).
altInstagram's alt text of the reel (includeDetails).
likesThe like count; null when the owner hides the likes (likes_hidden true) — never Instagram's placeholder value.
likes_hiddenTrue when the owner hid the like and view counts.
comments_countThe comment count.
playsThe play count Instagram's ranked list shows; null on the list's last 1–11 reels, which Instagram serves without plays (plays_status).
plays_statusserved, not_in_ranked_head (one of the list's last reels, which Instagram serves without a play count) or not_served.
viewsThe view counter of the reel's embed page (includeViews; a quarter to a half of the plays): null when Instagram hides the counts or the reel's embed page carries no record (2 of 16 reels with visible counts on our test).
video_durationThe video's length in seconds.
has_audioFalse for a reel with no sound track.
engagement_per_play(likes + comments) ÷ plays, four significant digits; null when the likes are hidden or there are no plays.
engagement_rate(likes + comments) ÷ the owner's followers (includeOwnerFollowers); null without the followers or with hidden likes.
owner_usernameThe reel's owner's username.
owner_idThe owner's account id (pk).
owner_full_nameThe owner's full name as their profile shows it (includeDetails; null when the profile has none).
owner_is_verifiedTrue when the owner's account is verified.
owner_profile_pic_urlThe owner's profile picture (a signed URL).
owner_followersThe owner's follower count (includeOwnerFollowers).
coauthorsThe coauthors of a collab reel: {username, id, is_verified, full_name, profile_pic_url} (includeDetails).
tagged_usersThe accounts tagged in the reel: {username, full_name, id, is_verified, profile_pic_url} (includeDetails).
location_nameThe reel's location name (includeDetails; null when it has none).
location_idInstagram's id of the location.
location_latThe location's latitude.
location_lngThe location's longitude.
display_urlThe reel's cover image (a signed URL, see media_urls_expire_at).
video_urlThe reel's video file (a signed URL).
audio_urlThe reel's audio-only track (HE-AAC; a signed URL); null when the reel has no sound.
media_urls_expire_atWhen the row's signed media URLs stop working (UTC; 1 to 4 days after the read).
widthThe video's width in pixels.
heightThe video's height in pixels.
sound_typeoriginal (the creator's own audio), licensed (a track from Instagram's music library) or none.
audio_mutedInstagram's own mute flag of the reel's sound: true when it serves the reel without its music track, with the reason in audio_muted_reason ("This song is currently unavailable."; the reason comes with includeDetails, the list gives the flag only); false when the sound is not muted or the reel has no sound asset. Every reel is read from an exit whose sound is checked first: a few exits serve every licensed track muted or as the creator's original audio, and the actor moves off them before it reads a reel there.
audio_muted_reasonInstagram's reason for a muted sound, as it gives it; null when the sound is not muted.
musicThe sound: {title, artist, audio_id, uses_original_audio} (includeDetails); a licensed track Instagram marks unavailable has its title and artist null.
music_trendingTrue when Instagram marks the sound as trending in reels (includeDetails).
ai_labelInstagram's own AI label of the reel; null when it shows none (includeDetails).
topicsInstagram's own topic tags of the reel (includeDetails).
latest_commentsThe reel's latest comments as Instagram shows them logged out, up to 15: {id, text, timestamp, likes, owner_username, owner_id, owner_is_verified, gif_url} (includeDetails); a comment with no text (a sticker) has text "" and is kept.
first_commentThe text of the first comment Instagram serves with the reel (includeDetails).
details_statusserved (the reel's own record was read), not_asked (includeDetails off), failed (the record did not answer: the list's fields are there) or not_found.
post_countOn a search row: the hashtag's post count as Instagram shows it (the hashtag spelled as the keyword without spaces); null when Instagram lists no such hashtag.
hashtag_idOn a search row: Instagram's id of that hashtag.
hashtag_nameOn a search row: the hashtag the post count belongs to.
related_keywordsOn a search row: Instagram's related keywords for the term (up to relatedKeywordsCount).
descriptionOn a search row: Instagram's own description of the term, when it shows one.
verdictOn a search row: COMPLETE (Instagram's ranked list ended: every reel read), CAPPED (maxReelsPerInput), RUN_CAP (maxItems or the charge limit), PARTIAL (an error or the time limit stopped it; the note says which).
reels_listedOn a search row: the reels of the ranked list the walk read (with COMPLETE, the list's whole length).
reels_deliveredOn a search row: the reels delivered from this input.
avg_playsOn a search row: the average plays over the reels delivered from this input.
median_playsOn a search row: the median plays over those reels.
avg_likesOn a search row: the average likes over those reels (hidden likes left out).
median_likesOn a search row: the median likes over those reels.
avg_commentsOn a search row: the average comment count over those reels.
median_commentsOn a search row: the median comment count over those reels.
top_creatorsOn a search row: the owners with the most reels among those delivered: {username, reels, plays}, up to 5.
noteWhy, in words: the reason of a free row, what a walk did not read and why.
scraped_atWhen the row was read (UTC).

Example record:

{
"record_type": "reel",
"status": "ok",
"input": "natgeo",
"input_type": "hashtag",
"keyword": "natgeo",
"related_to": null,
"rank": 4,
"id": "3992952281495587802",
"shortcode": "Ddp0PHHoUva",
"url": "https://www.instagram.com/reel/Ddp0PHHoUva/",
"type": "reel",
"product_type": "clips",
"timestamp": "2026-09-24T02:44:20Z",
"taken_at": 1790217860,
"caption": "राणा — शान भी, सल्तनत भी।🐆👑\n\n@natgeoindia @natgeo @nikonindiaofficial \n\n#reels #trendingreels #reelsinstagram #trending #viralvideos \n.\n.\n.\n.\nRana Leopard | Indian Leopard | Jawai Wildlife | Leopard Photography | Rajasthan Wildlife | Wildlife India | Majestic Leopard | Big Cat | Wildlife Reel",
"hashtags": [
"reels",
"trendingreels",
"reelsinstagram",
"trending",
"viralvideos"
],
"mentions": [
"natgeoindia",
"natgeo",
"nikonindiaofficial"
],
"caption_is_edited": false,
"caption_created_at": "2026-09-24T02:44:09Z",
"alt": "Video by Dushyant Malhotra| Wildlife Creator on September 23, 2026. May be an image of cheetah, big cat and text.",
"likes": 37269,
"likes_hidden": false,
"comments_count": 85,
"plays": 876523,
"plays_status": "served",
"views": null,
"video_duration": 16.136,
"has_audio": true,
"engagement_per_play": 0.04262,
"engagement_rate": null,
"owner_username": "dushyant_wildtrails",
"owner_id": "3911404912",
"owner_full_name": "Dushyant Malhotra| Wildlife Creator",
"owner_is_verified": true,
"owner_profile_pic_url": "https://scontent-xxc1-1.cdninstagram.com/v/t51.82787-19/567468550_18393098221132913_4935748518260328495_n.jpg?stp=dst-jpg_s150x150_tt6&_nc_cat=102&ccb=7-5&_nc_sid=f7ccc5&efg=eyJ2ZW5jb2RlX3RhZyI6InByb2ZpbGVfcGljLnd3dy4xMDgwLkMzIn0%3D&_nc_ohc=REDACTED&_nc_oc=REDACTED&_nc_zt=24&_nc_ht=scontent-xxc1-1.cdninstagram.com&_nc_gid=REDACTED&_nc_ss=7ea8c&oh=REDACTED&oe=6ADF4B5D",
"owner_followers": null,
"coauthors": [],
"tagged_users": [
{
"username": "nikonindiaofficial",
"full_name": "Nikon India Pvt Ltd.",
"id": null
},
{
"username": "rajasthan_tourism",
"full_name": "Rajasthan Tourism",
"id": null
},
{
"username": "rajasthanforestdepartment",
"full_name": "Rajasthan Forest Department",
"id": null
}
],
"location_name": "Jhalana Reserve Forest",
"location_id": "1262395790532175",
"location_lat": 26.855243742451,
"location_lng": 75.833497796402,
"display_url": "https://scontent-xxc1-1.cdninstagram.com/v/t51.82787-15/818854974_18445259269132913_8361329682113486626_n.jpg?stp=dst-jpg_e15_tt6&_nc_cat=102&ig_cache_key=Mzk5Mjk1MjI4MTQ5NTU4NzgwMjE4NDQ1MjU5MjYzMTMyOTEz.3-ccb7-5&ccb=7-5&_nc_sid=58cdad&efg=eyJ2ZW5jb2RlX3RhZyI6IkNMSVBTLnhwaWRzLjEyMDIuc2RyLnZpZGVvX2RlZmF1bHRfY292ZXJfZnJhbWUuQzMifQ%3D%3D&_nc_ohc=REDACTED&_nc_oc=REDACTED&_nc_zt=23&_nc_ht=scontent-xxc1-1.cdninstagram.com&_nc_gid=REDACTED&_nc_ss=7ea8c&oh=REDACTED&oe=6ADF666A",
"video_url": "https://scontent-xxc1-1.cdninstagram.com/o1/v/t16/f2/m84/AQN3fkvAohahzn0pNk1KNTt_fS758G2LeysKEZJ11h_V2FUXeWtZSR_OocjsOlPrwkl-X5F5Zl-JIxjBW8FgyLvqOQpvShlNIuCZJeU.mp4?_nc_cat=103&_nc_sid=5e9851&_nc_ht=scontent-xxc1-1.cdninstagram.com&_nc_ohc=REDACTED&efg=eyJ2ZW5jb2RlX3RhZyI6Inhwdl9wcm9ncmVzc2l2ZS5JTlNUQUdSQU0uQ0xJUFMuQzMuNzIwLmRhc2hfYmFzZWxpbmVfMV92MSIsInhwdl9hc3NldF9pZCI6MTE0NDA5NjE2NDYwODQ3NywiYXNzZXRfYWdlX2RheXMiOjI4LCJ2aV91c2VjYXNlX2lkIjoxMDgyNywiZHVyYXRpb25fcyI6MTYsInVybGdlbl9zb3VyY2UiOiJ3d3cifQ%3D%3D&ccb=17-1&vs=87ec90dae2b449ab&_nc_vs=HBksFQIYTGlnX2JhY2tmaWxsX3RpbWVsaW5lX3ZvZC9CNjQ2RDUxODJEQUYyOTBEN0I3RkIyREVEQUJEMUZCMF92aWRlb19kYXNoaW5pdC5tcDQVAALIARIAFQIYUWlnX3hwdl9wbGFjZW1lbnRfcGVybWFuZW50X3YyL0U3NERGQzMxQTQ3NzUyMTlFRkVBODRBQjg0OUJEMjhCX2F1ZGlvX2Rhc2hpbml0Lm1wNBUCAsgBEgAoABgAGwKIB3VzZV9vaWwBMRJwcm9ncmVzc2l2ZV9yZWNpcGUBMRUAACa659fXlKOIBBUCKAJDMywXQDAiDEm6XjUYEmRhc2hfYmFzZWxpbmVfMV92MREAdf4HZZapAQA&_nc_gid=REDACTED&_nc_ss=7ea8c&_nc_zt=28&oh=REDACTED&oe=6ADB60A5",
"audio_url": "https://scontent-xxc1-1.cdninstagram.com/o1/v/t2/f2/m78/AQPU0MwwtYsRI6FJzgo9vIjurSd_K5eI4UycrHEodsm4wweskVOEwL8a_ysCxj33SsM4tqNQxD8s-c4tZUFHvfvWde8Thk3HjwgfVsQ.mp4?_nc_cat=107&_nc_sid=9ca052&_nc_ht=scontent-xxc1-1.cdninstagram.com&_nc_ohc=REDACTED&efg=eyJ2ZW5jb2RlX3RhZyI6ImlnLXhwdmRzLmNsaXBzLmlnd3d3LUMzLmRhc2hfbG5faGVhYWNfdmJyM19hdWRpbyIsInZpZGVvX2lkIjpudWxsLCJvaWxfdXJsZ2VuX2FwcF9pZCI6OTM2NjE5NzQzMzkyNDU5LCJjbGllbnRfbmFtZSI6ImlnIiwieHB2X2Fzc2V0X2lkIjoxMTQ0MDk2MTY0NjA4NDc3LCJhc3NldF9hZ2VfZGF5cyI6MjgsInZpX3VzZWNhc2VfaWQiOjEwODI3LCJkdXJhdGlvbl9zIjoxNiwiYml0cmF0ZSI6NzMxOTEsInVybGdlbl9zb3VyY2UiOiJ3d3cifQ%3D%3D&ccb=17-1&_nc_gid=REDACTED&_nc_ss=7ea8c&_nc_zt=28&oh=REDACTED&oe=6ADB658C",
"media_urls_expire_at": "2026-10-23T13:27:01Z",
"width": 1440,
"height": 2560,
"sound_type": "licensed",
"audio_muted": null,
"audio_muted_reason": null,
"music": {
"title": "Azeem-O-Shaan Shahenshah",
"artist": "A.R. Rahman, Mohammed Aslam, Bonnie Chakravarty",
"audio_id": "1301690440176351",
"uses_original_audio": false
},
"music_trending": false,
"ai_label": null,
"topics": [
"leopard",
"safari",
"wildlife",
"jungle predator"
],
"latest_comments": [
{
"id": "1",
"text": "❤️❤️",
"timestamp": "2026-10-22T03:00:28Z",
"likes": 0,
"owner_username": "commenter_1",
"owner_id": null,
"owner_is_verified": false,
"gif_url": null
},
{
"id": "2",
"text": "Amazing capture 🔥",
"timestamp": "2026-10-17T16:49:35Z",
"likes": 1,
"owner_username": "commenter_2",
"owner_id": null,
"owner_is_verified": false,
"gif_url": null
}
],
"first_comment": "❤️❤️",
"details_status": "served",
"post_count": null,
"hashtag_id": null,
"hashtag_name": null,
"related_keywords": null,
"description": null,
"verdict": null,
"reels_listed": null,
"reels_delivered": null,
"avg_plays": null,
"median_plays": null,
"avg_likes": null,
"median_likes": null,
"avg_comments": null,
"median_comments": null,
"top_creators": null,
"note": null,
"scraped_at": "2026-10-22T04:13:23Z"
}

Pricing

Pay for the reels a run delivers, plus one run start; no platform usage is billed to you. The reel price falls with your Apify plan.

eventunitFreeStarterScaleBusiness
Reel (reel)per 1,000$2.70$2.295$1.89$1.35
Run start (start)per run$0.0018$0.0018$0.0018$0.0018

A reel is $2.70 per 1,000 on the Free plan ($0.0027 a reel) and $2.295 on Starter, with everything it carries: the details (owner name, music, location, tags, latest comments), and the views and the owners' followers when you ask for them, are inside the reel's price. Each run that delivers a reel also pays the run start, $0.0018 once; a run that delivers none pays nothing at all. So a hashtag's top 20 reels cost $0.0558 on the Free plan and $0.0477 on Starter; two keywords to the end of their lists (about 130 reels) $0.3528 and $0.30015; 1,000 reels $2.7018 and $2.2968; several hashtags and keywords in one run share one start. Free: every hashtag's or keyword's search row (the post count, the related keywords), a term with no ranked list, a term Instagram does not know, a value that names nothing, a reel listed under two of your inputs (one row, one charge), a reel a filter leaves out, and an input left unread at maxItems or the time limit. A run that stops early (a timeout, an abort) is charged for the reels it delivered. maxItems counts the charged reels. Before the first request the log names the price of a reel at your plan, the run start and the most the run can cost: maxReelsPerInput (at most 100) a hashtag or keyword and each related keyword walked, under maxItems and your charge limit. Instagram's ranked list ends sooner: about 50 to 70 reels a term (natgeo 59, nature 53, street food bangkok and woodworking 65 each on our runs), so a run to the lists' end costs less than its maximum. Enterprise plans have their own rates — the Actor's Pricing tab shows the price for your plan.

Usage patterns

  • What to give — hashtags: with or without #, or a hashtag link (instagram.com/explore/tags/natgeo/, instagram.com/popular/natgeo/). keywords: words or phrases, or a search-results link. Both lists give the same thing: Instagram's ranked reels for the term. A value is lower-cased (Instagram's list is case-sensitive), # and spaces at its ends are dropped, accents and scripts are kept. A term given twice is read once; a value that names nothing (a profile or post link, another site) is a free invalid_input row.
  • How many reels — maxReelsPerInput (20 by default, 100 = to the list's end) takes each list's top reels in Instagram's order; a reel a filter leaves out or already delivered under another input does not count. maxItems caps the charged rows of the whole run; the inputs are read side by side, so a cap under what they need is shared as their reels arrive, not in input order (each input still gets its top-ranked reels, and its search row says RUN_CAP). A ranked list holds about 50 to 70 reels: that is Instagram's list, not a limit of this Actor, and the search row says how many it held.
  • Filters — newerThan and olderThan (a date, a date and time, or 7 days) keep the reels published in a window; minPlays, minLikes and minComments keep a reel only above a count (a hidden like count does not pass a minimum above 0). The ranked list is not in date order, so a filter reads the whole list; a reel left out is free and frees its place.
  • Related keywords — Each search row lists Instagram's related keywords (relatedKeywordsCount, 10 by default, up to 48). relatedKeywordsDepth also reads the ranked reels of each input's first N related keywords: each is a whole list of its own, its rows say input_type related and related_to the input. A reel already delivered under another input is not delivered twice.

Input configuration

fieldtypedefaultwhat it does
hashtagsarray[]Hashtags, one per line, with or without # (natgeo, #natgeo), or a hashtag link (https://www.instagram.com/explore/tags/natgeo/, instagram.com/popular/natgeo/). Each gives Instagram's ranked reels for it, top first, up to maxReelsPerInput, and one free search row with the hashtag's post count and related keywords. Upper case is read as lower case (Instagram's list is case-sensitive); accents and other scripts are kept (café and cafe are two terms, ラーメン works). A value that names nothing is a free row that says why.
keywordsarray[]Search keywords or phrases, one per line (skincare routine, street food bangkok), or a search-results link (instagram.com/explore/search/keyword/?q=…). Each gives the ranked reels Instagram shows for the search, the same as a hashtag. A keyword and a hashtag with one spelling are read once.
maxReelsPerInputinteger20How many of each list's top reels, in Instagram's order. A ranked list holds about 50–70 reels (natgeo 59, nature 53 on our runs); 100 = every reel to the list's end. A reel left out by a filter or already delivered under another input does not count. The search row says how many the list held and why the walk stopped.
includeDetailsbooleantrueRead each reel's own record: the owner's full name and verified flag, the music title and artist, the location with coordinates, the tagged accounts, the coauthors, the latest comments (up to 15), Instagram's alt text and topic tags, the edited flag. On by default. Off = a faster, lighter run with the lists' fields only (plays, time, likes, comments, caption, owner username, media URLs, duration, the sound's kind).
includeViewsbooleanfalseAdd views, the counter Instagram's embed page shows (a quarter to a half of the plays; the plays are on every row anyway). One more call a reel: a run takes longer.
includeOwnerFollowersbooleanfalseAdd each reel owner's follower count (owner_followers) and the engagement rate per follower (engagement_rate). One call per distinct owner.
newerThanstring""Only reels published on or after this date: 2026-09-01, a date and time (2026-09-01T12:00:00Z), or a span back from now in lower case (7 days, 12 hours, 2 weeks, 3 months). The whole ranked list is read and the reels outside the window are left out, free.
olderThanstring""Only reels published on or before this date (a date includes its whole day), in the same forms as newerThan.
minPlaysinteger0Keep a reel only with at least this many plays (a reel of the list's tail, which Instagram serves without plays, is left out when this is above 0). Free when it leaves a reel out. 0 = every reel.
minLikesinteger0Keep a reel only with at least this many likes (a reel whose owner hides the likes is left out when this is above 0). Free when it leaves a reel out. 0 = every reel.
minCommentsinteger0Keep a reel only with at least this many comments. Free when it leaves a reel out. 0 = every reel.
relatedKeywordsCountinteger10How many of Instagram's related keywords the search row lists (related_keywords); Instagram serves up to 48.
relatedKeywordsDepthinteger0Also read the ranked reels of each input's first N related keywords (each a list of its own, with input_type related and related_to naming its input). A reel already delivered under another input is not delivered twice. 0 = the inputs only.
maxItemsinteger0The most charged rows (reels) of the whole run, over every hashtag, keyword and related keyword; 0 = no cap beyond maxReelsPerInput and your charge limit. The inputs are read side by side, so a cap under what they need is shared as their reels arrive, not in input order: each input still gets its top-ranked reels, and its search row says RUN_CAP.
proxyUrlstringYour own proxy (scheme://user:pass@host:port) for every call instead of ours. Leave empty: the Actor brings its own connections at no cost to you.
feedbackstringA note to the people who maintain this Actor: what you needed and did not get. For example a missing field, a wrong or empty result, or the Actor you switch from or to, and why. The run does not read it: the rows and the charges stay the same. A person reads every note.

Errors

A run does not fail because of your input. When an input cannot be used — a date that is not a date, an id in the wrong form, two settings that contradict each other — the run ends Succeeded, charges nothing, and says what to change:

  • the status message starts with INPUT REJECTED;
  • the dataset holds one row, {"error": true, "code": "…", "message": "…"}, and no results;
  • the key-value store record ERROR holds the same object.

From code, check error on the first row before reading results.

A hashtag or keyword Instagram shows no ranked list for, a term it does not know as typed, or a value that names nothing is not an error: it gets one free search row with its status and Instagram's own reason, and the run goes on with the others. A run that ends Failed is a fault on our side, never your input; it charges nothing, and we are alerted.

FAQ

Does it get the newest posts of a hashtag?

No: it gets the reels Instagram ranks for the hashtag or keyword, top first — the list Instagram shows logged out on a hashtag's and a search's page. Instagram does not show a hashtag's newest posts, or photos and carousels, to logged-out viewers; the scrapers that sell them read them with a logged-in account. Use newerThan to keep only recent reels of the ranked list.

Why do I get about 50 to 70 reels, not thousands?

That is the length of Instagram's ranked list for a term: the walk reads it to Instagram's own end flag (natgeo 59, nature 53 on our runs) and the search row's verdict says COMPLETE with the length. For more reels on a subject, add more hashtags or keywords, or let relatedKeywordsDepth read the related keywords' lists: each is a different list.

Why are some likes null?

The owner hid the like count on that reel. Instagram then serves a placeholder number, not the count, so the row gives likes null and likes_hidden true. The comment count and the plays are still there.

Why do the last few reels have no plays?

Instagram serves the plays with the first 52 to 68 reels of a list; its last 1 to 11 reels come without a play count. Those rows have plays null and plays_status not_in_ranked_head; everything else is there.

What is the hashtag's post count on a keyword?

The post count of the hashtag spelled as the keyword without spaces (skincare routine → #skincareroutine), as Instagram's own hashtag search shows it. When Instagram lists no such hashtag (a long phrase), post_count is null and the note says so.

What are the free rows?

One search row per hashtag or keyword (record_type search): ok with the figures, the verdict and the counts, or why it gave no reel — no_ranked_list (Instagram knows the term and shows no ranked list for it; its description and post count are on the row), unknown_term (Instagram does not know the term as typed: try another spelling), invalid_input, failed, not_read. Only reels are charged. For reels alone keep the rows whose record_type is reel.

Does it need an Instagram account, cookies or a login?

No. Everything is read from Instagram's public logged-out data with a plain HTTP client; nothing of yours is sent to Instagram.

Does it give shares, saves or reposts?

No. Instagram does not serve the share, save and repost counts to logged-out viewers. Each row has the plays, the likes and the comment count.

How long do the video and image URLs work?

Instagram signs every media URL with an expiry, 1 to 4 days after the read; each row gives that time in media_urls_expire_at. Download what you need before it.

I move from another Instagram hashtag scraper: which column is which?

The usual keys map one to one: shortCode → shortcode, caption, hashtags, mentions → the same, timestamp → timestamp, likesCount → likes (+ likes_hidden), commentsCount → comments_count, videoPlayCount → plays, videoViewCount → views, videoDuration → video_duration, ownerUsername / ownerId / ownerFullName → owner_username / owner_id / owner_full_name, musicInfo → music, coauthorProducers → coauthors, taggedUsers → tagged_users, locationName → location_name, displayUrl → display_url, videoUrl → video_url, latestComments → latest_comments, inputUrl → input, a rank or position → rank.

Integration

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('hyperbach/instagram-hashtag-scraper').call({"hashtags": ["natgeo"], "maxReelsPerInput": 20});
const { items } = await client.dataset(run.defaultDatasetId).listItems();

Python

from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('hyperbach/instagram-hashtag-scraper').call(run_input={'hashtags': ['natgeo'], 'maxReelsPerInput': 20})
items = client.dataset(run['defaultDatasetId']).list_items().items

CLI

$apify call hyperbach/instagram-hashtag-scraper --input '{"hashtags": ["natgeo"], "maxReelsPerInput": 20}'

REST

curl -X POST "https://api.apify.com/v2/acts/hyperbach~instagram-hashtag-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
-H 'Content-Type: application/json' -d '{"hashtags": ["natgeo"], "maxReelsPerInput": 20}'

AI agents and MCP

Apify's MCP server offers this Actor as a tool to Claude, Cursor, VS Code and any other MCP client. Connect https://mcp.apify.com?tools=hyperbach/instagram-hashtag-scraper and ask, for example: "Get the top 20 Instagram reels of the hashtag natgeo". The agent fills the input from the table above and reads the rows from the run's dataset. A field under the name another Actor gives it is read as this Actor's own: search, hashtag, tags, tag as hashtags; keyword, searchQueries, queries, query as keywords; resultsLimit, maxResults, resultsPerPage, limit as maxReelsPerInput; onlyPostsNewerThan, oldestPostDate, dateFrom as newerThan (and more). An agent or a person can add feedback to any run and say what was needed and not delivered: a missing field, a wrong or empty result, the Actor switched from or to, and why. The run returns the same rows at the same price, and a person reads every note.

n8n, Make and Zapier

The Apify node in n8n, the Apify app in Make and the Apify integration in Zapier run this Actor on a schedule or from a trigger and read its dataset. A webhook on the run's end (Integrations on the Actor page) sends the rows on to your own endpoint. Nothing to install on our side.

Support

Disagree with a charge? Write to apify@hyperbach.com with the run ID. We will ask Apify to compensate you, and the charge comes back to your Apify account as platform credit.

Did it do the job? A short review on the Store, at any rating, helps the next buyer choose.

See also

  • Meta Ad Library Scraper — every ad a page runs on Facebook, Instagram, Messenger, WhatsApp and Threads, with the landing URL, media, run dates and EU reach.
  • Threads Scraper — Threads profiles with the exact follower count, their posts and replies with view counts, and keyword and tag search, without a login.
  • Instagram Reels Transcript Scraper — the spoken words of Instagram reels, by reel link or creator, with the exact posting time.
  • Instagram Posts Scraper — the posts and reels of Instagram profiles, with the whole caption, the exact publish time, likes, comments and plays.
  • Facebook Pages Scraper — Facebook pages by URL, id, name or search words: the exact follower count, categories, address, phone, e-mail and websites, and the page transparency facts.
  • Facebook Marketplace Scraper — Marketplace listings by search, category and city: the price, the date listed and the seller, and on request the description and the vehicle facts.

This page is generated from the Actor's schemas and a live sample — it cannot describe a field the Actor does not have.

⌂ 换网址