Instagram Posts Scraper avatar

Instagram Posts Scraper

Pricing

$19.99/month + usage

Go to Apify Store
Instagram Posts Scraper

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

API Empire

Maintained by Community

Actor stats

0

Bookmarked

42

Total users

2

Monthly active users

a day ago

Last modified

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 TypeKey FieldsJSON Field Names
Post contentID, shortcode, media type, caption, publish date, post URLid, shortcode, mediaType, captionText, publishedAt, url
Hashtags & mentionsHashtags and @-mentions parsed out of the caption texthashtags, mentions
Engagement metrics (optional)Like and comment counts, plus Instagram's own raw counterslikeCount, commentCount, like_count, comment_count, view_count, share_count
Media & video metadata (optional)Image/video CDN URLs, carousel items, video duration and codecimage_versions2, carousel_media, video_versions, video_duration, video_codec
Post owner (embedded)The post author's username and internal Instagram IDownerUsername, 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.

FeatureInstagram Graph APIInstagram Posts Scraper
Account requirementBusiness or Creator account you own, linked to a Facebook PageNone — any public profile URL, username, or post shortcode
Approval processMeta App Review and Business Verification before going liveNo approval step — start a run immediately
Data scopeContent and insights for accounts you manage or that grant you accessPublic post history of any public Instagram profile
AuthenticationOAuth 2.0 access tokenNone — no Instagram login or session required
Consumer-app accessInstagram's Basic Display API (the consumer-app path) was shut down December 4, 2024Unaffected — the Actor never authenticates as an app on a user's behalf
Output formatGraph API JSON keyed to Meta's own schemaNormalized 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)

  1. Open Instagram Posts Scraper on its Apify Store listing and click Try for free (or Run, if you already have it saved).
  2. Provide the required input: at least one entry in startUrls — a profile URL, a username, or a post shortcode/URL.
  3. Set maxPosts and, optionally, dateFilterType + filterDate to limit how far back the run collects.
  4. Toggle includeEngagement and/or includeVideoMetadata on if you need those fields, then start the run.
  5. 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:

ParameterRequiredTypeDescriptionExample Value
startUrlsYesarrayInstagram profile URLs, usernames, or post shortcodes/URLs. The Actor auto-detects which kind each entry is.["https://www.instagram.com/cristiano/"]
maxPostsNointegerMaximum number of posts to scrape per profile. Default 10, minimum 1, maximum 1000.50
dateFilterTypeNostringDate filter mode: "absolute" or "relative". Default "relative"."relative"
filterDateNostringAbsolute mode takes a calendar date (YYYY-MM-DD); relative mode takes an offset like 7d, 2w, 1m, 1y, or 12h. Default "" (no filter)."7d"
includeEngagementNobooleanInclude engagement metrics like likes, shares, and comment counts. Default false.true
includeVideoMetadataNobooleanInclude detailed video metadata like duration and quality. Default false.false
proxyConfigurationNoobjectApify 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 fieldslikeCount, commentCount, and the raw like_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, and likeCount/commentCount set to null, unless includeEngagement is true.
  • Video fieldsvideo_versions, video_duration, video_dash_manifest, has_audio, number_of_qualities, is_dash_eligible, clips_metadata, video_codec, video_sticker_locales — are stripped unless includeVideoMetadata is true.
  • 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?

FeatureInstagram Posts ScraperGeneric alternative
Output formatTyped JSON per post, ready to export or queryRaw HTML requiring custom parsing
Input flexibilityOne field accepts profile URLs, usernames, or post shortcodesUsually needs a separate ID-lookup step
Proxy/anti-bot handlingBuilt-in Apify Proxy rotation with automatic retriesSelf-managed proxy pool and retry logic
Entity coveragePosts, parsed hashtags/mentions, optional engagement + video metadataOften posts only, with no parsed hashtags/mentions
Schema stabilitySame field names every run; gated fields are simply absent or null when disabledVaries; 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 ApifyClient
client = 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.

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.