Instagram API Scraper By Likes, Keywords & Date Range
Pricing
from $3.99 / 1,000 results
Instagram API Scraper By Likes, Keywords & Date Range
Pricing
from $3.99 / 1,000 results
Rating
0.0
(0)
Developer
Scraply
Maintained by CommunityActor stats
0
Bookmarked
10
Total users
2
Monthly active users
9 days ago
Last modified
Categories
Share
Instagram Scraper โ Posts & Reels by Likes, Keywords, Dates
Instagram Scraper By Likes, Keywords & Date Range scans a public Instagram profile's timeline posts, reels or @mentions and keeps only the ones that pass your filters โ minimum likes, comments or views, caption keywords to include or exclude, a two-sided posted-after / posted-before window, and a photo/video/reel/carousel filter. Every match ships as typed JSON with likesCount, commentsCount, viewCount, caption, hashtags, matchedKeywords and mediaCategory already attached. Social media managers, competitive analysts and lead-gen teams use it to pull only the posts that matter instead of paging a whole feed by hand.
โ ๏ธ Read this before your first run: scanBudget and keepPerTarget are two different caps. scanBudget limits how many posts get examined; keepPerTarget limits how many matches get kept. A tight scanBudget with a strict minLikes can return zero rows even with keepPerTarget set high โ the run gives up scanning before it ever finds enough qualifying posts. If a run comes back empty, widen scanBudget first.
๐ธ What is Instagram Scraper By Likes, Keywords & Date Range?
It is an Apify Actor that pages a public Instagram profile's feed through Instagram's own logged-out web API and applies your filters while it pages โ the dataset holds matches, not a spreadsheet you still have to sort. No Instagram account, login, cookie or session is required; every field returned is already visible to an anonymous visitor on the profile.
- ๐ฏ Point it at any public profile by URL or bare username (
filterTargets) โ no login needed - ๐๏ธ Choose the feed to scan: timeline posts, the reels-only clips feed, or
@mentionsfound inside matching posts (contentMode) - ๐ Set engagement floors on likes, comments and video views, with honest rejection reasons instead of silent zeros
- ๐ค Filter captions with an include list (any/all) and a separate exclude list
- ๐ Close a two-ended posted-after / posted-before date window, absolute or relative
- ๐ผ๏ธ Restrict output to a single media type โ photo, video, reel or carousel
- ๐ฆ Export matches as JSON, CSV or Excel through the Apify dataset, with an uncharged per-profile filter-audit row included by default
What data can I extract with Instagram Scraper By Likes, Keywords & Date Range?
A matching post or reel is one dataset row carrying identity, engagement, caption and filter-provenance fields together โ every key below is read straight off the row-building code, not the shorter list the default dataset view shows.
| Field | Example Value | Use Case |
|---|---|---|
id | "3234567890123456789" | Instagram's internal media ID |
type | "Video" | Photo, Video or Sidecar (carousel), from the raw payload |
shortCode | "Cx1AbCdEfGh" | Instagram's shortcode, used to rebuild the post URL |
caption | "New collection drops Friday #nyc" | Full caption text |
hashtags | ["nyc"] | Hashtags parsed out of the caption |
mentions | ["humansofny"] | @usernames parsed out of the caption |
url | "https://www.instagram.com/p/Cx1AbCdEfGh/" | Direct post link |
commentsCount | 842 | Comment count at scrape time |
firstComment | "" | First comment text, when the feed payload carried inline comments (usually empty โ see note below) |
latestComments | [] | Inline comments the feed happened to embed โ see nested shape below |
dimensionsHeight | 1350 | Media height in pixels |
dimensionsWidth | 1080 | Media width in pixels |
displayUrl | "https://scontent.cdninstagram.com/โฆ" | Best-available image/cover URL |
images | ["https://scontent.cdninstagram.com/โฆ"] | Display image plus one URL per carousel child |
alt | "Two people standing on a rooftop at night" | Instagram's own accessibility caption, or null |
likesCount | 54213 | Like count at scrape time |
timestamp | "2026-06-14T18:32:00.000Z" | Post date, ISO 8601 UTC |
childPosts | [] | Carousel children โ see nested shape below |
ownerFullName | "Humans of New York" | Profile display name |
ownerUsername | "humansofny" | Profile username |
ownerId | "185253363" | Profile's numeric Instagram ID |
isCommentsDisabled | false | Whether the post owner turned comments off |
inputUrl | "humansofny" | The exact filterTargets entry this row came from |
parentData | {"name": "humansofny", "type": "profile", "url": "https://www.instagram.com/humansofny/"} | Only present when attachSourceMetadata is on |
viewCount | 128430 | Video/reel plays; null on photos and carousels (no view metric exists there) |
mediaCategory | "reel" | photo, video, reel or carousel, derived from the payload |
likeCountsHidden | false | true when the owner hid like counts โ likesCount is not faked as 0 in that case |
matchedKeywords | ["nyc"] | Which captionKeywords terms actually fired on this caption |
filtersPassed | ["minLikes", "captionKeywords"] | Which active rules this row satisfied |
filtersApplied | 2 | How many filter rules were active for the run |
scrapedAt | "2026-07-26T09:41:12.000Z" | When this row was scraped, ISO 8601 UTC |
section | "posts" | posts, reels, mentions or audit โ set by the Actor, not by Instagram |
A row carries 31 fields on every run, 32 when attachSourceMetadata adds parentData. The default dataset view shows only 18 of them (type, mediaCategory, shortCode, ownerUsername, caption, matchedKeywords, likesCount, commentsCount, viewCount, likeCountsHidden, timestamp, filtersPassed, filtersApplied, url, displayUrl, hashtags, inputUrl, scrapedAt) โ switch to the Console's "Reels view", "Mentions view" or "Filter audit" tab, or just read the JSON/CSV export, to see the rest.
Nested objects, filter provenance, and the honest zero
latestComments is an array of comment objects (id, text, ownerUsername, ownerProfilePicUrl, timestamp, repliesCount, replies, likesCount, and a nested owner object with Instagram's own username, profile_pic_url, is_verified, id, full_name, is_mentionable, is_private, profile_pic_id and latest_reel_media keys). This variant does not fetch per-post comment detail, so latestComments and firstComment are populated only when Instagram's feed listing happened to embed inline comments โ in practice they are usually empty. childPosts is an array with the same shape as a top-level post (minus caption/engagement) for each carousel child, populated only when mediaCategory is "carousel".
filtersPassed, matchedKeywords, viewCount, mediaCategory and likeCountsHidden are never guessed: a photo's viewCount is null (not 0) because photos carry no view metric logged-out, and a post whose owner hid like counts is rejected with reason likes_hidden rather than silently compared against 0.
Three feed modes produce three different row shapes
contentMode picks which feed of the profile gets scanned and filtered โ pick one per run:
posts(default) โ the timeline grid: photos, videos and carousels, in the 31/32-field shape documented above,section: "posts".reelsโ the dedicated clips feed only. Same field shape, buttypeis forced to"Video"andsectionis"reels". If Instagram's clips endpoint is unreachable, the Actor falls back to reading reels out of the timeline feed instead of returning an empty run โ the audit row'sreelsSourcefield then reads"timeline_feed_fallback".mentionsโ a derived row type, not the post itself. The Actor first runs the same posts pipeline (same filters, samescanBudget/keepPerTarget) internally, then emits one row per@mentionfound inside each post that passed. A mentions row has a different, smaller shape:type("mention"),mentionedUsername,postShortCode,postUrl,ownerUsername,timestamp,inputUrl,section("mentions") โ 8 fields, no engagement or filter-provenance keys, because those live on the post that produced it, not on the mention.
The uncharged filter-audit row
With includeFilterAudit on (default true), one extra row is pushed per filterTargets entry โ and it is never billed, regardless of contentMode. It carries: type ("filter_audit"), isAudit (true), inputUrl, target, targetKind, contentMode, postsScanned, postsKept, postsRejected, keepRate, rejectedBy (an object counting every rejection reason โ below_min_likes, likes_hidden, no_view_metric, keyword_not_found, excluded_keyword, older_than_window, newer_than_window, media_type_mismatch, and more), filtersActive, pagesFetched, scanBudgetReached, reelsSource, errorReason, modeSubstituted, scrapedAt, section ("audit") โ 19 fields, only 15 of which appear in the Console's default "Filter audit" view.
Two separate things trigger this row:
- Every normal run gets one audit row per profile, so a 120-scanned / 4-kept run is auditable instead of looking broken.
- A single post, reel or hashtag URL passed into
filterTargets. Those surfaces are login-walled for a logged-out client โ Instagram returns nothing for them without a session. Instead of a silent empty run, the audit row'serrorReasonnames exactly why:post_detail_login_walled,hashtag_surface_login_walled,no_items_returned(private or empty account), orfeed_fetch_failed(network/proxy failure after 3 retries). IfincludeFilterAuditis turned off, a login-walled single-URL target produces no row at all for that target.
To exclude audit rows from your paid results when reading the dataset (via the API, a filter, or downstream code), keep only rows where type is not "filter_audit" โ equivalently, where isAudit is not true:
matches = [row for row in items if row.get("type") != "filter_audit"]
Why not build this yourself?
Meta's Instagram Graph API is the platform's own official API, and it is built for a different job: it only returns data for Instagram Business or Creator accounts that have explicitly connected to your app โ you cannot point it at an arbitrary public profile you do not own or manage on behalf of a client. It has no endpoint for caption-keyword search, no engagement-threshold parameter, and no two-sided date-range query over someone else's feed. For the exact use case this Actor covers โ "show me this account's posts that cleared 50,000 likes and mention a keyword last quarter" over a profile that is not yours โ there is no official API path at all, for you or for anyone else.
The alternative is a DIY scraper: reverse-engineer Instagram's logged-out web endpoints, handle pagination and rate limiting, build a caption-keyword and engagement filter engine, and maintain a proxy escalation ladder for when Instagram starts blocking. This Actor does all of that already โ filtering happens while the feed is being paged, live, against a public feed endpoint, with the proxy ladder and filter engine already built and maintained.
How to use data extracted from Instagram
๐ฑ Social media managers and marketers
A social media manager auditing a competitor's account sets filterTargets to that profile, minLikes to a threshold above the account's typical post, and a wide scanBudget โ then reads likesCount, caption and timestamp off the matches to see exactly which content formats and topics outperform for that brand.
๐ข Agencies benchmarking clients
An agency running the same audit across a client's competitor set repeats the run once per profile with the same filters โ minLikes, mediaTypeFilter and a fixed postedAfter/postedBefore window โ so every competitor is measured against the same bar for the same period, and the filtersPassed field confirms each row cleared the same rules.
๐ Market and campaign research
A researcher tracking how a hashtag campaign performed sets captionKeywords to the campaign tag with keywordMatchMode: "any", a postedAfter/postedBefore window matching the campaign dates, and reads likesCount, commentsCount and matchedKeywords across every profile that ran the tag to compare which accounts' posts about it actually landed.
๐ค AI agents and automated pipelines
An agent tool wraps this Actor to answer "did this account post anything about X that did numbers last month" on demand โ the typed JSON row (caption, engagement counts, matchedKeywords, timestamp) drops straight into an LLM context or a vector store with no parsing step, and the uncharged audit row lets the agent report "0 matches, but only 40 posts were scanned" instead of a bare empty list.
๐ผ Input sample
| Parameter | Required | Type | Description | Example Value |
|---|---|---|---|---|
filterTargets | No | array | Instagram profile URLs or bare usernames whose feed should be scanned and filtered. Single post, reel and hashtag URLs are accepted too, but produce an uncharged audit row instead of results (see above). | ["humansofny"] |
contentMode | No | string | Which feed to scan. Default "posts". Enum: "posts" (๐ท Timeline posts), "reels" (๐ฌ Reels feed), "mentions" (๐ Mentions found in posts). | "posts" |
keepPerTarget | No | integer | Matching items to keep per profile. Minimum 1, maximum 2400. Default 10. | 20 |
scanBudget | No | integer | Max posts to scan per profile before giving up. Minimum 0, maximum 2400. 0 = no cap (engine ceiling ~2,400 posts). Default 120. | 300 |
minLikes | No | integer | Minimum likes. Minimum 0. Default 0 (off). | 50000 |
minComments | No | integer | Minimum comments. Minimum 0. Default 0 (off). | 0 |
minViews | No | integer | Minimum views, video only. Minimum 0. Default 0 (off). | 0 |
captionKeywords | No | array | Case-insensitive substrings the caption must contain. Hashtags work too. | ["nyc"] |
keywordMatchMode | No | string | How to combine captionKeywords. Default "any". Enum: "any" (๐ OR), "all" (๐ AND). | "any" |
captionKeywordsExclude | No | array | Case-insensitive substrings that disqualify a post. | ["giveaway"] |
postedAfter | No | string | Lower edge of the date window. Absolute ("2026-01-31") or relative ("7 days", "2 months", "1 year"). | "2026-01-01" |
postedBefore | No | string | Upper edge of the date window. Absolute or relative. | "2026-06-30" |
mediaTypeFilter | No | string | Which media types to keep. Default "any". Enum: "any", "photo", "video", "reel", "carousel". | "any" |
includeFilterAudit | No | boolean | Add an uncharged filter-audit row per profile. Default true. | true |
attachSourceMetadata | No | boolean | Attach a parentData object (source profile name/type/URL) to every result row. Default false. | false |
proxyConfiguration | No | object | Proxy configuration. Default {"useApifyProxy": false} โ direct connection, escalating automatically if blocked. | {"useApifyProxy": false} |
Example input
{"filterTargets": ["humansofny"],"contentMode": "posts","keepPerTarget": 20,"scanBudget": 300,"minLikes": 50000,"captionKeywords": ["nyc"],"keywordMatchMode": "any","captionKeywordsExclude": ["giveaway"],"postedAfter": "2026-01-01","postedBefore": "2026-06-30","mediaTypeFilter": "any","includeFilterAudit": true,"attachSourceMetadata": false}
Common pitfall: raising keepPerTarget does nothing if scanBudget is too small to reach that many qualifying posts. scanBudget is the number of posts examined; keepPerTarget is the number of matches kept. Fix an empty-looking run by raising scanBudget, not keepPerTarget.
๐ฝ Output sample
Typed, normalized JSON, one row per matching post, reel or mention, plus one uncharged audit row per profile. Export as JSON, CSV or Excel through the Apify dataset, or read it through the Apify API.
Example output โ a matching post (contentMode: "posts")
{"id": "3234567890123456789","type": "Sidecar","shortCode": "Cx1AbCdEfGh","caption": "New collection drops Friday #nyc","hashtags": ["nyc"],"mentions": [],"url": "https://www.instagram.com/p/Cx1AbCdEfGh/","commentsCount": 842,"firstComment": "","latestComments": [],"dimensionsHeight": 1350,"dimensionsWidth": 1080,"displayUrl": "https://scontent.cdninstagram.com/v/example.jpg","images": ["https://scontent.cdninstagram.com/v/example.jpg"],"alt": "Two people standing on a rooftop at night","likesCount": 54213,"timestamp": "2026-06-14T18:32:00.000Z","childPosts": [],"ownerFullName": "Humans of New York","ownerUsername": "humansofny","ownerId": "185253363","isCommentsDisabled": false,"inputUrl": "humansofny","viewCount": null,"mediaCategory": "carousel","likeCountsHidden": false,"matchedKeywords": ["nyc"],"filtersPassed": ["minLikes", "captionKeywords"],"filtersApplied": 2,"scrapedAt": "2026-07-26T09:41:12.000Z","section": "posts"}
Example output โ the uncharged filter-audit row
{"type": "filter_audit","isAudit": true,"inputUrl": "humansofny","target": "humansofny","targetKind": "profile","contentMode": "posts","postsScanned": 120,"postsKept": 4,"postsRejected": 116,"keepRate": 0.0333,"rejectedBy": {"below_min_likes": 109, "excluded_keyword": 7},"filtersActive": ["minLikes", "captionKeywords", "captionKeywordsExclude"],"pagesFetched": 10,"scanBudgetReached": true,"reelsSource": null,"errorReason": null,"modeSubstituted": null,"scrapedAt": "2026-07-26T09:41:20.000Z","section": "audit"}
Example output โ a mention row (contentMode: "mentions")
{"type": "mention","mentionedUsername": "brooklynvintage","postShortCode": "Cx1AbCdEfGh","postUrl": "https://www.instagram.com/p/Cx1AbCdEfGh/","ownerUsername": "humansofny","timestamp": "2026-06-14T18:32:00.000Z","inputUrl": "humansofny","section": "mentions"}
How do you filter and target specific posts?
filterTargets accepts profile URLs or bare usernames โ that is the only target type this Actor scans and filters (single post/reel/hashtag URLs are still accepted but return an audit row only, per above). Real precision comes from four levers working together, in a fixed order:
- Scope, first.
scanBudgetdecides how many posts get examined per profile before the run gives up;keepPerTargetdecides how many of the examined posts that pass filters get kept. Filtering happens strictly inside the scanned set โ a strictminLikeswith a smallscanBudgetcan legitimately return nothing. - Engagement floors.
minLikes,minCommentsandminViewseach reject honestly rather than guessing: a post whose owner hid like counts is rejected aslikes_hidden, not compared against a fake0; a photo checked againstminViewsis rejected asno_view_metric, since photos carry no view count at all. - Caption wording.
captionKeywordswithkeywordMatchMode: "any"keeps a post if at least one term appears (OR);"all"keeps it only if every term appears (AND).captionKeywordsExcludeis then applied on top โ any post containing an excluded term is dropped even if it matched the include rule. Every include term that fired is reported back inmatchedKeywords; case is ignored throughout. - Date window and media type.
postedAfter/postedBeforeaccept absolute ("2026-01-31") or relative ("7 days","2 months","1 year") values and both ends can be set together to isolate a single month or quarter.mediaTypeFiltermatches on the payload's ownproduct_type/media_type:"photo"and"carousel"match only their own category,"reel"matches only clips-product posts, and"video"matches bothvideoandreelcategories (a reel is a video).
Three real examples:
Viral-post finder โ a handful of the account's biggest hits, scanning deep:
{ "filterTargets": ["humansofny"], "minLikes": 100000, "keepPerTarget": 5, "scanBudget": 2000 }
Campaign audit โ every on-brand post from a quarter, excluding giveaways:
{ "filterTargets": ["humansofny"], "captionKeywords": ["nyc", "collection"], "keywordMatchMode": "all", "captionKeywordsExclude": ["giveaway", "#ad"], "postedAfter": "2026-01-01", "postedBefore": "2026-03-31" }
Reels engagement scan โ only reels that cleared a view floor:
{ "filterTargets": ["humansofny"], "contentMode": "reels", "minViews": 200000, "mediaTypeFilter": "reel" }
โถ๏ธ Want to try other Instagram scrapers?
| Scraper Name | What it extracts |
|---|---|
| Instagram Followers Count Scraper | Follower, following and post counts plus full public profile data from a username or URL |
| Instagram Comment Engagement Scraper | A post or reel's comment section โ comments, replies and per-comment engagement metrics |
| Instagram Reels Hashtag Scraper | Reels by hashtag with audio metadata, a minimum play-count filter and engagement ranking |
| Instagram Profile Engagement Estimator | A profile's engagement rate estimated from its follower base and a sample of recent posts |
| Instagram Brand Mention Tracker | Inbound posts where other accounts tag or @mention a brand handle, with keyword filtering |
| Instagram Single Reels Scraper | A single Reel URL โ caption, like/comment/play counts, video and thumbnail URLs, music metadata and comments |
How to extract Instagram data programmatically
Instagram Scraper By Likes, Keywords & Date Range runs on Apify: one API call starts the run, structured JSON comes back from the dataset. No separate developer account or API key for Instagram itself โ only your Apify token.
Python example
from apify_client import ApifyClientclient = ApifyClient("<YOUR_APIFY_TOKEN>")run = client.actor("<YOUR_USERNAME>/instagram-api-scraper-by-likes-keywords-date-range").call(run_input={"filterTargets": ["humansofny"],"contentMode": "posts","minLikes": 50000,"captionKeywords": ["nyc"],"keepPerTarget": 20,"scanBudget": 300,})for row in client.dataset(run["defaultDatasetId"]).iterate_items():if row.get("type") == "filter_audit":continueprint(row["shortCode"], row["likesCount"], row["matchedKeywords"])
Works in Go, Ruby, Node.js, cURL โ any language that can call the Apify API.
Export to spreadsheets or CRM
Export the dataset as CSV directly from the Apify Console or API. Flat keys โ likesCount, commentsCount, caption, url, ownerUsername, timestamp โ map straight to spreadsheet columns; nested keys like latestComments and childPosts serialize as JSON strings in the CSV, ready to re-parse downstream or in an Airtable/Sheets automation step.
Is it legal to scrape Instagram?
Scraping publicly accessible Instagram content is broadly permissible when no login or access control is bypassed, and this Actor collects only what an anonymous visitor already sees on a profile's public feed. Every row is still built around the identity of the profile it came from โ ownerUsername, caption, engagement counts and timestamps are tied to a specific, identifiable account โ so this output is personal data under GDPR and CCPA, not anonymous business records. A lawful basis (typically legitimate interest) is needed to store and process it, the profile owner's rights (access, deletion) still apply, and it does not cover private accounts or anything Instagram gates behind a login. Consult legal counsel for commercial applications involving bulk storage of personal data.
โ Frequently asked questions
What if a profile has zero posts matching the filters within the scan budget?
The run still returns a row: the uncharged filter-audit row, with postsScanned and postsKept: 0, rejectedBy broken down by reason, and scanBudgetReached: true if the budget ran out before enough matches were found. Zero matches with scanBudgetReached: true means "raise scanBudget and try again"; zero matches with scanBudgetReached: false means the account genuinely has nothing that clears your filters.
Can I get reels and posts in the same run?
Not in one run โ contentMode scans one feed at a time (posts, reels or mentions). Run the Actor twice against the same filterTargets with different contentMode values to cover both.
How accurate is the likes/views/comments data?
The Actor returns counts exactly as Instagram's feed API reports them at request time. Some owners hide like counts โ those rows carry likeCountsHidden: true and are rejected rather than compared against a fake 0 if minLikes is set. View counts exist only for videos and reels; photos and carousels report viewCount: null, never 0.
How many posts can I get per run?
keepPerTarget caps matches kept, from 1 to 2400 (default 10). scanBudget caps posts examined before giving up, from 0 (no cap) to 2400 (default 120) โ 0 still bottoms out at the engine's own ~2,400-post pagination ceiling. Both caps apply per filterTargets entry, not across the whole run.
What's the difference between scanBudget and keepPerTarget?
scanBudget is a scanning limit โ how many posts get examined, newest first. keepPerTarget is a keeping limit โ how many of those examined posts, after filters, get saved. A run stops as soon as either limit is hit, whichever comes first. Raising keepPerTarget alone cannot produce more matches if scanBudget runs out before enough qualifying posts are found.
Does Instagram Scraper By Likes, Keywords & Date Range work with Claude, ChatGPT and AI agent frameworks?
Yes. It is callable as a standard HTTP endpoint through the Apify API, so LangChain, CrewAI, n8n or a hand-written tool definition can invoke it and get typed JSON back with no parsing step.
How does this compare to other Instagram scrapers?
Checked on the Apify Store on 26 July 2026: datadoping/instagram-likes-scraper and scraping_solutions/instagram-engagers-likes-and-comments-no-cookies both extract likers or commenters of a single post, not a profile's own feed filtered by engagement, keywords and date โ a structurally different job. patient_discovery/instagram-likes is the same single-post-likers model, documented at $2.50 per 1,000 results on its listing. None of the three documents scanning a profile's timeline or reels feed, filtering on caption keywords, or a two-ended date window โ this Actor's targeting axis is the profile itself, filtered down, rather than a single post's engager list.
Can I use this without an Instagram API key or developer account?
Yes. No Instagram account, API key, cookie or session is required โ the Actor talks to Instagram's public logged-out feed API directly. The only credential you need is your Apify account to run the Actor.
Conclusion
Instagram Scraper By Likes, Keywords & Date Range turns a profile's entire feed into just the posts, reels or mentions that clear your engagement, keyword and date rules โ with an uncharged audit row so a low match count is explained, not mysterious. It is built for anyone who needs a filtered slice of a public account's content rather than a full re-export of the feed. Open it on the Apify Console or call it through the Apify API to start a run.