Instagram Scraper: Profiles, Posts, Reels & People Search
Pricing
from $3.50 / 1,000 saved records
Instagram Scraper: Profiles, Posts, Reels & People Search
Scrape public Instagram profiles, recent posts and Reels, or discover people by keyword. Managed session and proxies are included. Export structured data and monitor accounts for new content.
Pricing
from $3.50 / 1,000 saved records
Rating
5.0
(1)
Developer
Steafanie Braid
Maintained by CommunityActor stats
0
Bookmarked
4
Total users
3
Monthly active users
a day ago
Last modified
Categories
Share
Instagram Scraper: Profiles, Posts, Reels and People Search
Collect public Instagram profile data and recent posts and Reels from the profiles you choose. Start from usernames, profile URLs, or Instagram people search terms, and get clean, structured records you can export as JSON, CSV, or Excel.
The published Actor manages Instagram access, proxies, and request pacing. No account or proxy setup is required. Only-new monitoring skips content that earlier runs already delivered.
What this Instagram scraper collects
- Instagram people search. Enter keywords and collect the public profiles that Instagram returns for them, with the search term and ranking position saved on each record.
- Instagram profile data. Username, user ID, display name, biography, external link, profile picture URL, follower, following, and post counts, verification status, privacy status, and category.
- Instagram posts and Reels from the profile feed. Shortcode, URL, caption, alt text, publish date, like, comment, and view counts, image and video URLs, carousel items, hashtags, and mentions.
- Only-new monitoring. Skip content that an earlier run already saved, so each run delivers only fresh posts and Reels.
- Run reports. A run summary, the full people-search outcome, and diagnostics are saved next to the results.
What it does not collect
- Post, Reel, or Story URLs as starting points. Use a profile URL or username instead.
- Content from private profiles. For a private profile you get the public profile record only.
- A complete Reels-tab archive. Reels are included when Instagram shows them in the profile feed.
- Older content beyond the recent window. Each profile is limited to its 50 most recent feed items.
- Comments, follower or following lists, Stories, and media file downloads. Media URLs are returned, but files are not downloaded.
- Exhaustive search. People search follows Instagram's own ranking and result limits.
Use cases
- Influencer and creator research. Search for a niche such as "vegan bakery" or "trail running", then compare follower counts, bios, and recent engagement.
- Competitor and brand monitoring. Track a fixed list of accounts and collect their new posts and Reels on a schedule.
- Content analysis. Export captions, hashtags, mentions, and publish dates for recent posts to study topics and posting frequency.
- Lead lists. Collect public profile details, categories, and bio links for a set of accounts.
Before your first run
Enter the profiles or search terms, select the limits, and start the run. The Actor handles authentication, proxy rotation, retries, and request pacing automatically.
For only-new monitoring, use the same history store on each run. If managed access becomes unavailable, contact the developer with the failed run URL. The developer maintains the account and proxies.
Quick start
- Open the Actor input.
- Under Usernames, enter one account, such as
instagram. - Start the run. The prefilled input collects one profile and three recent feed items with managed access.
- Open the Output tab to see the dataset, run summary, search outcomes, and diagnostics.
Once the first run works, raise the limits or add search terms.
Input examples
These examples use managed access on Apify. Developer setup for local runs appears in Run locally or in Docker.
Collect specific profiles and their recent posts and Reels:
{"usernames": ["natgeo", "nasa"],"startUrls": ["https://www.instagram.com/instagram/"],"maxProfiles": 3,"postsPerProfile": 12,"maxResults": 100}
Find profiles with Instagram people search:
{"searchTerms": ["coffee roaster", "specialty coffee"],"searchResultsPerTerm": 10,"maxProfiles": 15,"postsPerProfile": 5,"maxResults": 200}
Collect profile data only, without posts:
{"usernames": ["natgeo", "nasa", "instagram"],"postsPerProfile": 0}
Monitor accounts for new posts and Reels:
{"usernames": ["natgeo"],"postsPerProfile": 10,"onlyNew": true,"stateStoreId": "instagram-seen-content"}
Use the same stateStoreId on every run. The first run returns up to 10 recent items. Later runs return only items from the 10 most recent that earlier runs have not saved.
Input reference
Provide at least one search term, username, or profile URL. Omitted fields use their defaults. Empty strings, explicit null values, wrong types, and values outside the allowed range fail validation before any request is made.
What to collect
| Field | Default | Description |
|---|---|---|
searchTerms | [] | Keywords for Instagram people search, up to 100 terms of up to 200 characters each. Each term returns ranked accounts. Public matches are collected. Private matches appear only in the search outcomes. |
usernames | [] | Instagram usernames to collect, with or without @. Up to 100. Matching is case-insensitive, and duplicates are removed. |
startUrls | [] | Instagram profile URLs, such as https://www.instagram.com/natgeo/. Up to 100. Post, Reel, Story, Explore, and other non-profile URLs fail validation. |
Usernames and profile URLs are collected first. Search results fill the remaining profile slots.
Limits
Four limits control run size. Each one counts something different:
| Field | Default | Range | What it counts |
|---|---|---|---|
maxProfiles | 20 | 1–100 | Unique profiles in the whole run, from all inputs combined. A profile listed twice uses one slot. |
searchResultsPerTerm | 10 | 1–30 | Search matches taken from each search term. Private matches use a slot but are not collected. |
postsPerProfile | 10 | 0–50 | Recent feed items (posts, Reels, and videos) per profile. 0 collects profile records only. |
maxResults | 1000 | 1–10000 | Dataset records in the whole run, counting profile records and content records together. The run stops when it is reached. |
For example, with maxProfiles: 5, postsPerProfile: 10, and maxResults: 30, the run stops after 30 records. That would be about three profiles with ten items each, even though five profiles were allowed. To get every profile and all its items, set maxResults to at least maxProfiles × (postsPerProfile + 1).
Search outcomes, the run summary, and diagnostics never count toward maxResults. The run also stops before more Instagram requests when its remaining spending budget cannot pay for another record.
Only new content
| Field | Default | Description |
|---|---|---|
onlyNew | false | Skip posts and Reels that an earlier run already saved for the same profile. Profile records are always returned. |
stateStoreId | none | Required when onlyNew is on. The name or ID of a Key-Value Store that keeps the list of saved content between runs. Use the same value on every run. |
Only-new filtering checks the selected recent window only. With postsPerProfile: 10, the Actor reads the 10 most recent feed items and drops the ones it has seen. It does not search further back to fill the gap. Up to 5000 content IDs are remembered per profile. An item is marked as seen only after it is saved to the dataset, so items cut off by maxResults are delivered on a later run.
Failure handling
| Field | Default | Description |
|---|---|---|
allowPartialResults | false | When a search, profile, or feed request fails, the saved records are kept but the run is marked as failed. Turn this on to let the run succeed with status partial when at least one record was saved. |
Runs with no saved records after an error, storage errors, and session save errors always fail.
Output
Dataset: profile and content records
Every record has a recordType:
recordType | Meaning |
|---|---|
profile | One Instagram profile. |
post | An image or carousel post from the profile feed. |
reel | A Reel from the profile feed. |
video | A feed video that Instagram does not mark as a Reel. |
Profile record example:
{"recordType": "profile","source": "instagram","username": "examplecoffee","userId": "1234567890","fullName": "Example Coffee Roasters","biography": "Small-batch roastery. Fresh beans every Monday.","externalUrl": "https://example.com/","profilePicUrl": "https://scontent.cdninstagram.com/...","followersCount": 18450,"followingCount": 312,"postsCount": 964,"isVerified": false,"isPrivate": false,"category": "Coffee Shop","profileUrl": "https://www.instagram.com/examplecoffee/","sourceQuery": "coffee roaster","searchPosition": 3,"collectedAt": "2026-10-10T09:15:02.481Z"}
Reel record example:
{"recordType": "reel","source": "instagram","shortcode": "DAbC123xYz","url": "https://www.instagram.com/reel/DAbC123xYz/","sourceProfileUsername": "examplecoffee","ownerUsername": "examplecoffee","ownerId": "1234567890","caption": "Monday roast day with @guestbarista #coffee #roasting","altText": null,"publishedAt": "2026-10-06T07:30:00.000Z","likeCount": 842,"commentCount": 0,"viewCount": 15230,"mediaUrl": "https://scontent.cdninstagram.com/...mp4","thumbnailUrl": "https://scontent.cdninstagram.com/...jpg","videoUrl": "https://scontent.cdninstagram.com/...mp4","isVideo": true,"productType": "clips","carouselMedia": [],"hashtags": ["coffee", "roasting"],"mentions": ["guestbarista"],"sourceQuery": "coffee roaster","searchPosition": 3,"collectedAt": "2026-10-10T09:15:06.910Z"}
The values above are illustrative.
Field reference
On every record
| Field | Meaning |
|---|---|
recordType | profile, post, reel, or video. |
source | Always instagram. |
sourceQuery | The search term that found the profile. null when the profile came from usernames or startUrls. |
searchPosition | The profile's 1-based rank in the search results. null for usernames and profile URLs. |
collectedAt | When the record was collected, in ISO 8601 UTC. |
Profile records
| Field | Meaning |
|---|---|
username, userId | Lowercase username and numeric user ID (as a string). Always present. |
profileUrl | Profile link. Always present. |
fullName, biography, category | Public display name, bio text, and account category. null when empty or not shown. |
externalUrl | The bio link, or the first of several bio links. null if none. |
profilePicUrl | Profile picture link. Instagram CDN links expire after some time. |
followersCount, followingCount, postsCount | Public counts. null when Instagram does not provide them. |
isVerified, isPrivate | Verification and privacy status. null when unknown. Private profiles produce no content records. |
Content records (post, reel, video)
| Field | Meaning |
|---|---|
shortcode | Unique content ID. Use it to deduplicate. Always present. |
url | Link to the post (/p/...) or Reel (/reel/...). Always present. |
sourceProfileUsername | The profile whose feed contained the item. |
ownerUsername, ownerId | The author. For collaboration posts, this can differ from sourceProfileUsername. |
caption | Caption text. null when the post has no caption. |
altText | Accessibility text for the media, separate from the caption. Often null. |
publishedAt | Publish time in ISO 8601 UTC. null if unknown. |
likeCount, commentCount, viewCount | Engagement counts. null when hidden by the owner or not provided. viewCount is usually null for images. |
mediaUrl | The main media link: the video for videos and Reels, otherwise the image. CDN links expire. |
thumbnailUrl, videoUrl | Image preview link and video link. videoUrl is null for images. |
isVideo | true for videos and Reels. |
productType | Instagram's media type label, such as feed, carousel_container, or clips. null if unknown. |
carouselMedia | For carousel posts, one entry per slide with mediaUrl, thumbnailUrl, videoUrl, and isVideo. An empty list for single-media posts. |
hashtags, mentions | Hashtags and @mentions found in the caption, without # or @. Empty lists when there are none. |
Missing values and zeros
A count of 0 means Instagram reported zero. null means the value is unknown or hidden, for example when the owner hides like counts. Do not treat null as zero in your analysis.
Run reports in the Key-Value Store
| Record | Contents |
|---|---|
RUN_SUMMARY | Run status, record counts, failed and empty searches, failed profiles, private profiles, duplicates skipped, request and retry counts, response bytes, and proxy statistics. Failed runs include a failure code and message. |
SEARCH_RESULTS | One entry per completed search term, with every match (username, user ID, name, privacy, and position), including private and empty results. |
DIAGNOSTICS | One entry per problem, with its scope (search, profile, or content), target, error code, and a short explanation. |
The run status in RUN_SUMMARY is one of these values:
| Status | Meaning |
|---|---|
finished | Everything requested was collected. |
limit_reached | The run stopped at maxResults. The run succeeds. |
spending_limit_reached | The remaining run budget cannot pay for another record. The run succeeds and keeps saved results. |
empty | No errors, but nothing was found, for example a search with no results. The run succeeds. |
partial | Some requests failed after records were saved. The run fails unless allowPartialResults is on. |
failed | Errors occurred and no records were saved, or the run hit a fatal error such as invalid input, an unreadable proxy list, or a storage failure. |
Records saved before an error stay in the dataset in every case.
Troubleshooting
| Code | What it means | What to do |
|---|---|---|
SESSION_REQUIRED | The managed session is unavailable or expired. | Contact the developer with the failed run URL. The developer maintains the session. |
ACCOUNT_CHALLENGE | Instagram requires a check of the managed account. | Contact the developer with the failed run URL. The developer handles the account check. |
PROXY_POOL_EXHAUSTED | The managed proxy pool is temporarily unavailable. | Retry later. If the error continues, contact the developer with the failed run URL. |
PROXY_RETRY_LIMIT | A request failed after the Actor tried its available proxy attempts. | Retry later. If the error continues, contact the developer with the failed run URL. |
PROFILE_NOT_FOUND | Instagram search did not return an account with that exact username. | Check the spelling. The account may be renamed, removed, or hidden from search. |
IDENTITY_MISMATCH | Instagram returned a different account than requested. | Retry later. The record is skipped rather than saved under the wrong name. |
PAGINATION_STALLED, PAGE_LIMIT, INCOMPLETE_FEED | The feed stopped returning new items. | Records collected so far are kept. Retry later or lower postsPerProfile. |
UNEXPECTED_RESPONSE, QUERY_REJECTED | Instagram returned an unexpected or rejected response. | Retry later. If it persists, Instagram may have changed its web queries. |
FAQ
Do I need an Instagram account? No. The published Actor includes managed Instagram access. The developer maintains the account.
Are proxies included? Yes. Proxy access is included in the price. The Actor handles proxy selection, rotation, and retries automatically.
Can I scrape a single post or Reel by URL? No. Start from the profile that posted it instead. Post, Reel, and Story URLs fail input validation.
Does it get all Reels from an account? It gets the Reels that appear among the most recent feed items, up to 50 items per profile. It does not read the separate Reels tab.
Why is a like count null when the post clearly has likes?
The owner may hide like counts, or Instagram did not include the value. Unknown counts are null. Real zeros stay 0.
Can I scrape private accounts?
You get the public profile record, with isPrivate: true. Content from private accounts is never collected.
Why did my run fail when only one username was wrong?
By default, any failed profile fails the run, while saved records stay in the dataset. Turn on allowPartialResults to accept partial output, and check DIAGNOSTICS for the failed target.
How long does a run take? The Actor paces requests automatically. A run with 20 profiles usually takes a few minutes. More content, retries, or slower responses increase the duration.
Is it legal to scrape Instagram? This Actor collects public data only, but you are responsible for how you use it. Personal data is protected by laws such as the GDPR, and Instagram's terms apply to your account. If you are unsure, consult a lawyer.
Run locally or in Docker
Use Node.js 20.12 or later. Local runs use file storage and do not require an Apify account.
npm cinpm testnpm start
npm start reads storage/key_value_stores/default/INPUT.json. To use another input file, run npm start -- --input input.example.json. With the Apify CLI, run apify validate-schema and apify run --input-file input.example.json.
This section applies to developers who run their own copy. The published Actor already includes the access described here.
- Log in to an Instagram account that you own in your normal desktop browser.
- Export the cookies for
instagram.comto a local JSON file. The export must includesessionid. - Copy the user agent from the same browser.
- Copy
.env.exampleto.env. - Set the following environment variables:
WEBSHARE_PROXY_LIST_URL=your proxy list download linkINSTAGRAM_SESSION_FILE=C:/path/to/instagram-cookies.local.jsonINSTAGRAM_USER_AGENT=the user agent from your session browser
Instead of a session file, you can set INSTAGRAM_SESSION_COOKIES. Cookie formats include a browser JSON export, a name-value object, or a Cookie header. For a developer-managed cloud session store, use INSTAGRAM_SESSION_STORE_ID.
Without a proxy list URL, local runs read proxy.txt in the project folder. Each line contains IP:port:username:password or an authenticated HTTP proxy URL. The managed pool uses Webshare. Apify Proxy requires a separate integration.
The session file must be writable. After each run, the Actor saves refreshed cookies, the user agent, and the preferred proxy to that file. If Instagram requests an account check, complete it in your browser and update the saved session.
.env, proxy.txt, cookie files, and local storage are excluded from Git, Docker images, and Actor uploads. Session and proxy values never appear in the dataset or diagnostics. For cloud deployments, supply secrets through encrypted environment variables. For Docker sessions, mount a writable directory and point INSTAGRAM_SESSION_FILE to a file inside it.
How it works
The Actor sends HTTP requests to Instagram's web endpoints with your session. It reads fresh web tokens at the start of each run. Requests use Apify impit with Chrome TLS and HTTP/2 profiles, client hints that match your user agent, and TLS certificate validation. It does not run a browser, solve CAPTCHAs, or log in with a password. With a session, usernames are matched to user IDs through people search, and each returned profile is checked against the requested username and ID. Feed pages hold up to 12 items, with at most 10 pages per profile. Instagram can change its undocumented web queries at any time. At startup, the Actor discovers current query IDs and required feature flags from Instagram's public web scripts. Script requests exclude session cookies and CSRF headers. Fallback query IDs are in src/instagram.js.
Pricing
The published Actor charges $3.50 per 1,000 saved dataset records ($0.0035 each). One profile, post, Reel, or video is one record. A profile plus three feed items produces four records and costs $0.014 in result events.
The startup event costs $0.00005 per started GB of allocated memory, with a minimum of one event. Managed session and proxy access are included. Search outcomes, diagnostics, and run summaries have no separate result charge. Profile records remain chargeable on only-new runs. Skipped duplicate content has no result charge.
Set a maximum run charge in Apify to control the result budget. The Actor stops before another Instagram request when it cannot pay for another record. The event price includes standard Apify platform usage. The Pricing tab shows the current rates.
Project status
The October 22, 2026 update fixes feed collection after Instagram added a required query flag. All 76 automated tests pass. The Changelog tab lists the changes.