Instagram Posts Scraper
Pricing
$19.99/month + usage
Instagram Posts Scraper
Instagram Posts Scraper extracts posts from any public Instagram profile. Get captions, media URLs, hashtags, timestamps, and engagement metrics fast. Ideal for research, content analysis, trend tracking, and automation workflows needing structured Instagram post data.
Pricing
$19.99/month + usage
Rating
0.0
(0)
Developer
API Empire
Maintained by CommunityActor stats
0
Bookmarked
42
Total users
2
Monthly active users
a day ago
Last modified
Categories
Share
Instagram Posts Scraper — Extract Posts, Hashtags & Engagement Data
Instagram Posts Scraper extracts a public Instagram profile's posts — captions, hashtags, mentions, media URLs, and optional engagement and video metadata — starting from a profile URL, username, or post shortcode, with no login required. Every run returns typed, normalized JSON: no HTML, no CSS selectors, no manual parsing. Point it at one profile or a hundred, set a post limit and a date window, and the dataset fills row by row as posts are collected, ready to export or feed straight into an agent or pipeline.
🧭 What is Instagram Posts Scraper?
Instagram Posts Scraper is an Apify Actor that collects a public Instagram profile's recent posts — accepting a profile URL, a plain username, or a post shortcode/URL as the starting point. It resolves the input automatically, fetches the profile's public post feed, and returns each post as a structured JSON row. No Instagram account or login is required: the Actor pulls its own anonymous session tokens from Instagram's public web pages for each request.
- Scrape recent posts from any public profile, by URL, username, or post shortcode
- Extract captions with hashtags and @mentions parsed out automatically
- Optionally include engagement metrics (likes, comments, views) and video metadata
- Filter posts by an absolute date or a relative time window (
7d,2w,1m,1y) - Export as JSON or CSV, or read the dataset via the Apify API
📊 What data does Instagram Posts Scraper collect?
Every scraped post carries three layers of data — post content, hashtags/mentions parsed from the caption, and optional engagement and media metadata:
| Data Type | Key Fields | JSON Field Names |
|---|---|---|
| Post content | ID, shortcode, media type, caption, publish date, post URL | id, shortcode, mediaType, captionText, publishedAt, url |
| Hashtags & mentions | Hashtags and @-mentions parsed out of the caption text | hashtags, mentions |
| Engagement metrics (optional) | Like and comment counts, plus Instagram's own raw counters | likeCount, commentCount, like_count, comment_count, view_count, share_count |
| Media & video metadata (optional) | Image/video CDN URLs, carousel items, video duration and codec | image_versions2, carousel_media, video_versions, video_duration, video_codec |
| Post owner (embedded) | The post author's username and internal Instagram ID | ownerUsername, ownerId |
Need more Instagram data?
If you also need a profile's pinned-post handling, a content-type filter, or the profile's "Tagged" feed as its own labeled dataset section, API-Empire also publishes Instagram Profile Post Scraper: Media Details & Tagged Posts, which exposes the full image/video size ladder and an optional tagged-posts collection alongside regular posts.
🆚 How does Instagram Posts Scraper differ from the official Instagram API?
Meta's Instagram Graph API is built for accessing content and insights on Instagram accounts you own or manage — not for reading an arbitrary public profile's posts by username. Instagram Posts Scraper is built for the opposite case: pulling public post data from any profile without owning it.
| Feature | Instagram Graph API | Instagram Posts Scraper |
|---|---|---|
| Account requirement | Business or Creator account you own, linked to a Facebook Page | None — any public profile URL, username, or post shortcode |
| Approval process | Meta App Review and Business Verification before going live | No approval step — start a run immediately |
| Data scope | Content and insights for accounts you manage or that grant you access | Public post history of any public Instagram profile |
| Authentication | OAuth 2.0 access token | None — no Instagram login or session required |
| Consumer-app access | Instagram's Basic Display API (the consumer-app path) was shut down December 4, 2024 | Unaffected — the Actor never authenticates as an app on a user's behalf |
| Output format | Graph API JSON keyed to Meta's own schema | Normalized JSON dataset ready for export or API pull |
The Graph API is the right choice when you already own or manage the Instagram account and need insights tied to your own app review. Instagram Posts Scraper is the right choice when you need the public post history of profiles you don't own or manage, without an approval process.
👥 Why do developers and teams scrape Instagram posts?
For AI engineers and agent builders
Structured post data — caption text, hashtags, mentions, media type, and timestamps — feeds directly into a RAG index or an agent's tool call without an HTML-parsing step. An agent tracking a set of creator accounts can call the Actor with startUrls and a relative filterDate like 7d, then index captionText and hashtags per post for retrieval, using publishedAt to keep the window current on every run.
For marketers and brand teams
Competitor and campaign monitoring depends on knowing what an account posted, when, and how it performed. Pulling mediaType, captionText, hashtags, and (with includeEngagement on) likeCount/commentCount for a list of competitor profiles turns manual feed-checking into a dataset that can be diffed run over run.
For researchers and analysts
Public posting behavior — hashtag usage, posting cadence, caption content — is a common input to social-media research. Because the Actor only ever fetches public profiles anonymously, the resulting dataset is limited to what any visitor could already see, which matters for studies scoped to public-data-only analysis.
For developers building data products
A scheduled run against a list of profiles, exported through the Apify API, is a stable base layer for a content-monitoring product or an internal dashboard — the field names stay the same run to run, so downstream code doesn't need to be rewritten when Instagram's own page markup changes.
🛠️ How to scrape Instagram posts (step by step)
- Open Instagram Posts Scraper on its Apify Store listing and click Try for free (or Run, if you already have it saved).
- Provide the required input: at least one entry in
startUrls— a profile URL, a username, or a post shortcode/URL. - Set
maxPostsand, optionally,dateFilterType+filterDateto limit how far back the run collects. - Toggle
includeEngagementand/orincludeVideoMetadataon if you need those fields, then start the run. - Download the results as JSON or CSV from the Output tab, or read them via the Apify API/
apify-client.
What to do when Instagram changes its structure
Instagram Posts Scraper is actively maintained, and the output field names and types are kept stable, so downstream integrations keep working even when Instagram changes its own page markup or internal endpoints. No specific turnaround time is published for any given fix.
⬇️ Input
Instagram Posts Scraper takes seven input parameters, defined in .actor/input_schema.json:
| Parameter | Required | Type | Description | Example Value |
|---|---|---|---|---|
startUrls | Yes | array | Instagram profile URLs, usernames, or post shortcodes/URLs. The Actor auto-detects which kind each entry is. | ["https://www.instagram.com/cristiano/"] |
maxPosts | No | integer | Maximum number of posts to scrape per profile. Default 10, minimum 1, maximum 1000. | 50 |
dateFilterType | No | string | Date filter mode: "absolute" or "relative". Default "relative". | "relative" |
filterDate | No | string | Absolute mode takes a calendar date (YYYY-MM-DD); relative mode takes an offset like 7d, 2w, 1m, 1y, or 12h. Default "" (no filter). | "7d" |
includeEngagement | No | boolean | Include engagement metrics like likes, shares, and comment counts. Default false. | true |
includeVideoMetadata | No | boolean | Include detailed video metadata like duration and quality. Default false. | false |
proxyConfiguration | No | object | Apify Proxy configuration used for every request. Residential proxy is recommended; leaving it off sends requests directly and may be blocked more often. | {"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]} |
Example input:
{"startUrls": ["https://www.instagram.com/cristiano/"],"maxPosts": 50,"dateFilterType": "relative","filterDate": "7d","includeEngagement": true,"includeVideoMetadata": false,"proxyConfiguration": {"useApifyProxy": true,"apifyProxyGroups": ["RESIDENTIAL"]}}
⚠️ maxPosts is silently clamped to the 1–1000 range in code — entering 5000 collects 1000, and entering 0 collects 1. The run does not error, so check the actual row count rather than assuming your input value was honored exactly. A second common mistake: leaving filterDate empty applies no date filter at all, regardless of what dateFilterType is set to.
⬆️ Output
Every row starts from Instagram's own raw post object and adds the Actor's derived fields on top; nothing is removed except two gated groups. Results export as JSON or CSV from the Output tab, or through the Apify API.
- Engagement fields —
likeCount,commentCount, and the rawlike_count,comment_count,play_count,ig_play_count,view_count,fb_play_count,share_count,has_liked,comment_likes_enabled,max_num_visible_preview_comments— are stripped, andlikeCount/commentCountset tonull, unlessincludeEngagementistrue. - Video fields —
video_versions,video_duration,video_dash_manifest,has_audio,number_of_qualities,is_dash_eligible,clips_metadata,video_codec,video_sticker_locales— are stripped unlessincludeVideoMetadataistrue. - Everything else Instagram's feed API returns for that post —
pk,code,caption,image_versions2,carousel_media,owner,location,coauthor_producers,is_paid_partnership,taken_at,media_type,product_type, and more — passes through unchanged, alongside the Actor's own added fields:id,shortcode,url,mediaType,captionText,hashtags,mentions,likeCount,commentCount,ownerUsername,ownerId,publishedAt,scrapedAt,scraped_username,scraped_at,post_url.
Scraped post
{"id": "3727992219681477950","shortcode": "DO8fSwLiNU-","url": "https://www.instagram.com/p/DO8fSwLiNU-/","mediaType": "Video","captionText": "Match day. Let's go! #football #Nassr @teammate","hashtags": ["football", "Nassr"],"mentions": ["teammate"],"likeCount": 452118,"commentCount": 3021,"ownerUsername": "cristiano","ownerId": "173560420","publishedAt": "2025-09-23T12:02:05+00:00","scrapedAt": "2026-07-29T10:15:00+00:00","pk": "3727992219681477950","code": "DO8fSwLiNU-","caption": { "text": "Match day. Let's go! #football #Nassr @teammate" },"taken_at": 1758628925,"media_type": 2,"product_type": "clips","like_count": 452118,"comment_count": 3021,"view_count": 9800215,"image_versions2": { "candidates": [ { "url": "https://scontent.cdninstagram.com/.../thumb.jpg", "width": 1080, "height": 1350 } ] },"video_versions": [ { "url": "https://scontent.cdninstagram.com/.../video.mp4", "width": 1080, "height": 1350 } ],"video_duration": 14.7,"video_codec": "h264","owner": { "pk": "173560420", "username": "cristiano", "is_verified": true },"location": null,"coauthor_producers": [],"is_paid_partnership": false,"scraped_username": "cristiano","scraped_at": 1769684100,"post_url": "https://www.instagram.com/p/DO8fSwLiNU-/"}
🆚 How does Instagram Posts Scraper compare to other Instagram scrapers?
| Feature | Instagram Posts Scraper | Generic alternative |
|---|---|---|
| Output format | Typed JSON per post, ready to export or query | Raw HTML requiring custom parsing |
| Input flexibility | One field accepts profile URLs, usernames, or post shortcodes | Usually needs a separate ID-lookup step |
| Proxy/anti-bot handling | Built-in Apify Proxy rotation with automatic retries | Self-managed proxy pool and retry logic |
| Entity coverage | Posts, parsed hashtags/mentions, optional engagement + video metadata | Often posts only, with no parsed hashtags/mentions |
| Schema stability | Same field names every run; gated fields are simply absent or null when disabled | Varies; often breaks silently when the site changes |
If you're building an AI agent or RAG pipeline, the output format row is the decision-maker — parsing HTML inside an agent loop is a reliability failure mode, not a feature.
🔢 How many results can you scrape with Instagram Posts Scraper?
maxPosts accepts 1–1,000 posts per profile, per run — this is a hard ceiling enforced in the Actor's own code (any value outside that range is clamped to it), not a number reported by Instagram. Pagination happens automatically: the Actor requests Instagram's feed in pages of 12 posts, continuing until maxPosts is reached, the date cutoff from filterDate is crossed, or Instagram's own feed response reports no more pages available. Multiple startUrls entries are processed one profile at a time, and rows are pushed to the dataset as each post is collected rather than all at once at the end of the run.
🔌 Integrate Instagram Posts Scraper and automate your workflow
Instagram Posts Scraper works with any language or tool that can send an HTTP request.
REST API integration
from apify_client import ApifyClientclient = ApifyClient("<APIFY_API_TOKEN>")run = client.actor("<YOUR_USERNAME>/instagram-posts-scraper").call(run_input={"startUrls": ["https://www.instagram.com/cristiano/"],"maxPosts": 50,"includeEngagement": True,})for item in client.dataset(run["defaultDatasetId"]).iterate_items():print(item["shortcode"], item["captionText"][:60])
Works in Python, Node.js, Go, Ruby, cURL.
Automation platforms (n8n, Make)
In Make, Apify's own module lets you run any Actor by ID and map its dataset output into downstream modules — set the Actor to instagram-posts-scraper and feed startUrls from an upstream trigger. In n8n, the Apify community node's "Run Actor" operation takes the same Actor ID and input JSON, so a scraped-posts step can hand rows straight to a Sheets, Airtable, or Slack node.
⚖️ Is it legal to scrape Instagram posts?
Yes — scraping publicly visible Instagram posts is generally lawful, but the personal data inside them (usernames, owner IDs, captions) is still subject to data-protection law once you store or process it. Instagram Posts Scraper only returns posts from public profiles; it never authenticates as a user, so private accounts and their posts are not accessible. Because each row is tied to an identifiable public account, GDPR and CCPA govern how you store, use, and retain that data if you're in or handling data from the EU/UK or California. Consult legal counsel for commercial use cases involving bulk personal data.
❓ Frequently asked questions
Does Instagram Posts Scraper work without an Instagram account?
Yes. The Actor never logs in — it fetches a fresh, anonymous app ID and CSRF token from Instagram's own public profile page for every request. No Instagram credentials or session cookies are part of the input schema.
How often is the scraped data updated?
Every run performs a live fetch against Instagram at the time it starts — there is no caching layer. Running the Actor again returns whatever is currently public on the profile, not a stored snapshot.
What happens if a post is deleted or a profile can't be reached?
⚠️ If a profile is private, deleted, or Instagram blocks the anonymous token request, that entry returns zero rows rather than raising a run error. Check the run log for a "❌ Failed to extract tokens" line or a "🏁 @username: pushed 0 posts" line to see which entries came back empty.
Can I scrape private Instagram content?
No. The Actor never authenticates as a user, so private accounts and any content gated behind a login (or Instagram's own "Tagged"/saved views on a private account) are not accessible. Only what a signed-out visitor could see on a public profile is returned.
Do I need to configure a proxy myself?
No, but it affects reliability. If proxyConfiguration is left empty, the Actor defaults to Apify's residential proxy group automatically; running with proxies disabled sends requests directly from Apify's infrastructure and may be blocked more often.
Does Instagram Posts Scraper work for AI agent workflows and LLM pipelines?
Yes. It's callable as an HTTP endpoint through apify-client (or plain HTTPS) from any agent framework. Every response is typed JSON — hashtags and mentions are already parsed out of the caption — so there's no parsing step before passing a post into an LLM context window.
How does Instagram Posts Scraper handle Instagram's anti-bot system?
It routes every request through Apify Proxy (residential recommended), resolves a fresh proxy session per page/profile rather than reusing one IP for an entire run, and retries failed requests automatically — token fetches retry up to 3 times with backoff, and a failed feed page is retried once on a new proxy session before that page is given up on.
What makes Instagram Posts Scraper different from writing your own script?
The input auto-detection is the main time-saver: one startUrls field accepts a profile URL, a bare username, or a post shortcode/URL, and the Actor works out which one it is instead of requiring separate fields or a manual resolve step. Retry logic, proxy rotation, and hashtag/mention parsing are already built in.
Does Instagram Posts Scraper return data in a format LLMs can use directly?
Yes. Every field is typed, normalized JSON with stable field names — no HTML, no selectors, no parsing. Pass a row straight into an LLM's context window, index it into a vector store, or route it through an agent tool call.
Can I use Instagram Posts Scraper without managing proxies?
Yes. Leaving proxyConfiguration at its default runs every request through Apify's residential proxy group automatically — there's no separate proxy pool or IP rotation to set up yourself.
What happens when Instagram changes its structure or blocks the scraper?
The scraper is actively maintained, and the output schema stays stable — field names and types don't change on your end even when Instagram changes its own page markup or internal endpoints. No specific numeric turnaround time is published.
💬 Your feedback
Found a bug, or need a field this Actor doesn't currently return? We want to know — reach out through the Actor's page on the Apify Store (Issues tab) or Apify Console support chat, and include the run ID so the report can be traced back to the exact request that produced it.