🔥 Instagram Profile Scraper
Pricing
from $0.50 / 1,000 results
🔥 Instagram Profile Scraper
Scrape Instagram profile data and profile statistics from public Instagram pages with an Apify Actor. This actor focuses on profiles (not posts) and returns a clean dataset with the essentials (identity, stats, and account flags), plus optional previews like latest_posts, etc.
Pricing
from $0.50 / 1,000 results
Rating
0.0
(0)
Developer
Instagram Scraper
Maintained by CommunityActor stats
9
Bookmarked
1K
Total users
148
Monthly active users
1.4 hours
Issues response
a day ago
Last modified
Categories
Share
Instagram Profile Scraper
Scrape Instagram profile data and profile statistics from public Instagram pages with an Apify Actor.
This actor focuses on profiles (not posts) and returns normalized profile fields (identity, stats, and account flags),
plus additional raw Instagram profile metadata when available, along with optional previews like latest_posts
and discovery via related_profiles.
What this actor can do
- Scrape Instagram profile stats: followers, following, number of posts
- Get key profile attributes: verified/private flags, profile pictures, bio, external links, and counts
- Keep additional raw profile metadata from Instagram when available in the public payload
- Optionally scrape a linked Facebook profile into
fb_profilewhenscrapeFacebookProfileis enabled - Return latest posts as lightweight previews or opt-in detailed post data
- Return a list of related profiles from
Accounts you might likewhen that enrichment succeeds - Accept both usernames and profile URLs
Want to get other details from Instagram?
This actor is optimized for profiles (not full post feeds). If you want to scrape other Instagram data, use a dedicated scraper for that specific data type.
Related actors from the instagram-scraper:
| Actor | Description | Stats |
|---|---|---|
| Instagram Profile Finder | Find Instagram profiles | |
| Fast Instagram Profile Posts Scraper | Scrape post data from Instagram profile pages | |
| Instagram Profile Posts Scraper | Extract profile post details such as hashtags, counts, media, and shortcode | |
| Fast Instagram Profile Reels Scraper | Scrape public Instagram Reels from profile pages | |
| Instagram Posts & Reels Scraper | Scrape public Instagram posts and Reels from URLs or shortcodes | |
| Instagram Hashtags Posts Scraper | Scrape public Instagram hashtag pages | |
| Instagram Related Profiles Scraper | Discover related accounts and recursively expand profile networks |
What data can I scrape from Instagram profiles?
Using this Instagram Profile API, you can extract both normalized fields and additional Instagram profile metadata (when available on the public profile):
| Category | Fields | What you get |
|---|---|---|
| Identity & IDs | pk, id, pk_id, username, full_name, url | Basic profile identifiers returned by Instagram, plus the canonical profile URL built by the actor. |
| Profile media & links | profile_pic_url, profile_pic_url_hd, profile_pic_id, has_profile_pic, profile_pic_genai_tool_info[], biography, contact_email, bio_links[], external_url, external_url_linkshimmed, pronouns[] | Profile picture fields (including HD URL mapped from hd_profile_pic_url_info), profile bio text, extracted contact email, profile links, and external website fields available on the Instagram profile. external_url_linkshimmed is passed through from Instagram's external_lynx_url when present. Each bio_links[] item may include fields such as image_url, is_pinned, link_type, lynx_url, media_accent_color_hex, media_type, title, url, and creation_source. profile_pic_genai_tool_info[] is a raw Instagram array and is often empty. |
| Facebook enrichment | fb_profile | Optional Facebook profile lookup from one detected profile URL in external_url, bio_links, fb_profile_biolink, biography, or full_name when scrapeFacebookProfile is enabled. The nested payload includes url, status, message, bio, profile_type, profile_name, page_id, counts, and other status fields when available. |
| Counts & activity | followers, following, post_count, total_clips_count, has_any_clips, mutual_followers_count, latest_reel_media, live_broadcast_visibility, live_broadcast_id | High-level counts for analysis, monitoring, and profile summaries, plus activity hints exposed by Instagram. With skipAdditionalData: false, an available main-profile count is retained; if none is available, public profiles parse post_count from profile-page HTML og:description (for example, <meta property="og:description" content="42M Followers, 1,455 Following, 14K Posts - …">). Instagram abbreviates counts above ~10k in that tag (14K, 1.2M, and so on), so values are approximate rather than exact. post_count is null when skipAdditionalData is enabled (the default), or when the main profile has no count and the optional page is skipped or cannot provide one. has_any_clips is derived from total_clips_count when available. latest_reel_media, live_broadcast_visibility, and live_broadcast_id are raw pass-through fields and are commonly null. |
| Account flags & capabilities | is_private, is_verified, show_text_post_app_badge, text_post_app_badge_label, is_active_on_text_post_app, is_unpublished, is_memorialized, is_coppa_enforced, is_regulated_c18, account_type, is_business, is_professional_account, category, should_show_category, is_embeds_disabled, is_cannes, has_story_archive | Visibility, verification, account-type, audience-safety, and account-status fields available on the Instagram profile. These fields are always emitted on found profiles, using explicit null when Instagram does not return a value (except category, which may be an empty string). |
| Profile context & relationship hints | linked_fb_info, profile_context_links_with_user_ids, profile_context_facepile_users, supervision_info, has_chaining | Extra profile-context blocks returned by Instagram for social graph, supervision, or related-surface hints. These are pass-through fields and are often null on public profile pages. |
| Business & location | address_street, city_name, zip | Optional business/contact location metadata when Instagram exposes it on the public profile. These fields are usually null for non-business accounts. |
| Transparency & badges | account_badges[], show_account_transparency_details, transparency_label, transparency_product, hide_creator_marketplace_badge, is_ring_creator, show_ring_award | Transparency, badge, and creator-surface metadata exposed by Instagram. These are stable pass-through fields when present; arrays such as account_badges[] are emitted as [] when empty. |
| Latest posts | latest_posts[] | latestPostsMode: "preview" (default) uses a fixed 17-field shape with identifiers, captions, hashtags, mentions, preview images, authors, media type, and scrape time. "detailed" includes richer media and business fields when available. See Latest posts output below. |
| Related profiles | related_profiles[] | Suggested accounts from the Accounts you might like enrichment: id, username, full_name, is_verified, profile_pic_url. When enabled, the actor returns the full related-profiles list Instagram exposes for that profile. On final enrichment failure, the actor emits [] and logs a warning instead of failing the whole profile. |
| Scrape metadata | crawled_at, ig_status | Timestamp of the scrape and a simple status indicator. ig_status is ok when profile data is returned and not_found when the profile does not exist or is restricted. Invalid input entries are listed in run logs and skipped before scraping; they do not create Dataset rows. |
Notes:
- Field availability depends on what Instagram returns for a given profile (especially for private accounts).
- Some fields are normalized by the actor (
followers,following), while other raw Instagram profile fields may still be passed through when present. - Raw Instagram metadata can change over time, so downstream consumers should treat optional fields as non-guaranteed.
- When
skipAdditionalDataisfalse,post_countretains a usable main-profile value or falls back to the public profile page'sog:descriptionmeta tag. Instagram abbreviates large counts (for example,14K Posts), so HTML-derived values are approximate. Private profiles skip HTML and retain only a count already supplied by the main profile. With additional data skipped (the default), or no usable source after retries,post_countisnull. contact_emailis extracted frombiographyorfull_namewhen an email address is present on a found profile, and isnullotherwise.fb_profileisnullwhen the toggle is disabled or no Facebook profile URL is found. If a Facebook lookup fails after retries, the actor returnsfb_profile.status = "error"orfb_profile.status = "not_found"instead of throwing. Successfulfb_profilepayloads includebioinstead of the olderintroname.- Preview posts contain exactly the 17 fields documented below. Detailed posts use the expanded shape described below. Known missing scalar/object values are
null; known list fields use[]when empty. - Additional data is skipped by default. Set
skipAdditionalData: falseto include available first-page posts in the selected mode and a post count; private profiles skip additional lookups.
Typical use cases
- Influencer discovery and enrichment (profile stats, verification, public profile metadata)
- Competitor monitoring (track follower growth over time)
- Lead enrichment for sales/marketing (public business profiles)
- Content research (quick look at latest post captions and preview images)
Input
Configure these fields in the Actor’s Input tab in the Apify Console:
instagramUsernames (required)
A list of Instagram usernames or profile URLs you want to scrape.
Usernames support 2–256 ASCII letters, digits, periods, or underscores, with an
optional leading @. Complete profile URLs support up to 8,192 characters and
may point to the profile itself or its reels or tagged tab. These are input
format limits; a syntactically valid entry does not guarantee that a profile
exists or is available to the scraper.
Before creating scraping tasks, the Actor validates each entry and removes duplicates without regard to capitalization. Invalid entries are skipped and listed in run logs with their original list position and rejection reason. Credential-bearing values are redacted in logs. Only valid, unique profiles enter the scraping queue and contribute to the requested-profile total. If every entry is invalid or the list is empty, the run ends without scraping or creating Dataset rows.
Examples:
googlehttps://www.instagram.com/google/
scrapeFacebookProfile (optional)
When enabled, the actor looks for one Facebook profile URL in this order: external_url, bio_links, fb_profile_biolink, biography, then full_name.
In the current public payload model, bio_links is usually the main place where profile links are exposed.
The nested fb_profile payload includes url, status, message, bio, profile_name, page_id, followers, following, is_business_page_active, category_name, and profile_type when available.
skipAdditionalData (optional, default: true)
Controls enrichment for both latest_posts[] and post_count. Keep it enabled
for faster scraping. Set it to false to include available posts in the selected
latestPostsMode and the post count for public profiles. Preview mode shares a
page lookup with the post count; detailed mode fetches posts separately and
only needs the page lookup when the main profile has no usable count.
When enabled, latest_posts is [] and post_count is null, including when
the main profile response contains a post count. This takes precedence over
latestPostsMode, including "detailed". Private profiles skip additional post
and page lookups. If an optional lookup fails after retries, the main profile
is still saved successfully.
This option replaces skipLatestPosts and skipPostCount. Saved inputs with
those removed keys are accepted and ignored; use skipAdditionalData: false
to request both values.
{"instagramUsernames": ["instagram"],"skipAdditionalData": false}
latestPostsMode (optional, default: "preview")
Choose how much detail to include in latest_posts. Requires
skipAdditionalData: false; setting this mode alone does not enable enrichment.
| Value | Behavior |
|---|---|
"preview" | Basic post previews using the fixed 17-field shape below. This is the default and preserves existing output. |
"detailed" | Richer post information when available, including publication times, engagement counts, video details, tagged users, music, and carousel previews. May take longer and adds a post event charge per saved post at the configured Actor price. |
Both modes fetch only the first page for public profiles. Detailed mode requests
12 posts for all users; the actual number returned can differ. Neither mode
paginates, pads the result, truncates the returned posts locally, or performs
per-post lookups. Private profiles return latest_posts: []. Unrecognized mode
values are rejected during input validation.
For backward compatibility, latestPostsV2: true selects "detailed", including
when latestPostsMode is set to "preview". A false or omitted latestPostsV2
leaves latestPostsMode unchanged. This compatibility input also requires
skipAdditionalData: false to enable enrichment and uses the same detailed
output and post event charges.
To request detailed posts:
{"instagramUsernames": ["instagram"],"skipAdditionalData": false,"latestPostsMode": "detailed"}
The equivalent input using the compatibility option is:
{"instagramUsernames": ["instagram"],"skipAdditionalData": false,"latestPostsV2": true}
Latest posts output: preview
Post previews come from the public profile page and include only the first
page available there, commonly 12 posts. The Actor keeps all valid previews
without padding, local truncation, pagination, or per-post lookups. Pinned and
collaborative posts can appear; the media author can differ from the profile.
Missing, damaged, or unavailable previews produce latest_posts: [] without
failing or retrying the main profile. Post-count retries can still occur
independently, and any successfully parsed previews are retained.
Each post contains exactly these 17 fields:
| Fields | Current output |
|---|---|
pk, id | Source identifiers and types; missing values are null |
code, shortcode, url | Matching shortcodes and a canonical post or Reel URL; null if unavailable |
media_type, product_type | Source media classification, or null |
caption | Plain text; missing text is null, an explicit empty string stays "" |
hashtags, mentions | Unprefixed, deduplicated lists in order of first appearance; [] if absent |
accessibility_caption | Source accessibility text, or null |
display_uri, image | Preview image URL, or null |
is_video | Boolean indicating whether the source identifies the preview as video |
user | Author object containing id and username, or null; absent author values are null |
carousel_media_count | Source carousel count, or null; carousel children are not fetched |
crawled_at | UTC ISO 8601 scrape time shared by the batch; this is not a publication time |
Previews do not include publication times, engagement counts, video URLs or durations, dimensions, music, tagged users, or carousel children. Those values are unavailable from this preview source and are not reconstructed.
Latest posts output: detailed
With latestPostsMode: "detailed", the same latest_posts[] field contains
expanded post objects. This mode has a separate output shape; consumers that
require exactly 17 fields should keep "preview".
| Fields | Detailed output |
|---|---|
pk, id, code, shortcode, url | Source identifiers, matching shortcode aliases, and a canonical post or Reel URL. |
caption, hashtags, mentions | Plain-text caption and deduplicated, unprefixed hashtags/mentions. Empty lists use []. |
taken_at_timestamp, taken_at | Publication time as Unix seconds and a UTC ISO 8601 string, or null when unavailable. |
like_count, comment_count, play_count, view_count | Available engagement counts; unavailable counts remain null, and counts with different meanings are not substituted. |
media_type, product_type, is_video, accessibility_caption | Media classification and accessibility text when available. |
display_uri, image, image_versions2, video_url, video_versions, video_duration, dimensions, original_height, original_width | Available image/video sources, duration in seconds, and dimensions. |
user, owner, coauthor_producers, tagged_user, location | Available author, collaboration, tagging, and location information. Known list fields, including tagged_user, use [] when empty. |
clips_metadata, clips_music_attribution_info, music_metadata | Available music and clip metadata. Some source-specific fields are present only when returned. |
carousel_media_count, carousel_media | Reported carousel size and available child-media previews. Children can be partial; the Actor does not fetch the remaining slides. |
timeline_pinned_user_ids, clips_tab_pinned_user_ids, is_paid_partnership | Available pinning and partnership information. |
crawled_at | UTC ISO 8601 scrape time shared by the batch, separate from publication time. |
Additional returned business fields are preserved. Known missing scalar/object
fields use null, and known missing list fields use []. Nested business
objects retain their available structure. Carousel children retain source
caption and timestamp types and receive media convenience fields; their shape
is not identical to a root post. Media authors can differ from the requested
profile for collaborative posts.
Detailed post failures are retried up to six attempts. If they remain
unavailable, the Actor saves the profile with latest_posts: [] and retains any
available post_count. It does not silently fall back to preview mode. Post
count lookup failures likewise do not discard successful detailed posts.
Selected fields from a detailed post are shown below. Other root fields are omitted for readability; the included nested objects are shown in full.
{"pk": null,"id": "1","code": "SHORT","shortcode": "SHORT","url": "https://www.instagram.com/p/SHORT/","media_type": 2,"product_type": null,"caption": "hello #news @caption_mention","hashtags": ["news"],"mentions": ["caption_mention"],"taken_at_timestamp": 1772730134,"taken_at": "2026-03-05T17:02:14Z","like_count": null,"comment_count": null,"play_count": null,"view_count": null,"image": "https://example.com/top-candidate.jpg","video_url": "https://example.com/top-video.mp4","video_duration": null,"dimensions": {"height": 1137,"width": 640},"is_video": true,"user": null,"tagged_user": [{"pk": "10","full_name": "Top User","username": "top_user","profile_pic_url": "https://example.com/u.jpg","is_verified": true,"id": "10","is_private": true,"profile_pic_id": "pic-10"}],"clips_music_attribution_info": {"artist_name": "Sample Artist","song_name": "Sample Song","uses_original_audio": false,"should_mute_audio": false,"should_mute_audio_reason": null,"audio_id": "audio-1"},"carousel_media_count": null,"crawled_at": "2026-09-27T00:00:00Z"}
Detailed post billing
On pay-per-event runs, latestPostsMode: "detailed" adds a post charge for
each post saved in latest_posts[], in addition to existing profile and optional
Facebook charges. Preview mode does not trigger this event. The Actor uses the
event price configured on Apify; it does not accept or hardcode a separate price.
After each successful batch save, the Actor sums the lengths of latest_posts
for the profiles confirmed saved and submits one post charge for that total.
The account-wide post_count is not used. Carousel children do not count as
additional posts. Empty post lists, skipped enrichment, and failed Dataset
writes do not trigger a post charge. If only part of the batch is saved, only
those saved profiles contribute to the charge.
A Post billing estimate log lists the saved profiles, their post counts, the
total, the event count reported as charged by the SDK, and an estimated cost in
USD. unitPriceUsd is the runtime event price used for this estimate. Counts are
integers; USD values are decimal strings. Refer to the Actor's pricing and your
Apify billing records for actual charges. For illustration only, a runtime price
of $0.001 per post would produce this estimate for 22 posts:
{"eventName": "post","status": "charged","profileCount": 2,"totalPostCount": 22,"chargedPostCount": 22,"unchargedPostCount": 0,"unitPriceUsd": "0.001","estimatedCostUsd": "0.022","billingNote": "Estimated cost only. Refer to the Actor's pricing and your Apify billing records for actual charges.","eventChargeLimitReached": false,"profiles": [{ "username": "username1", "postCount": 12 },{ "username": "username2", "postCount": 10 }]}
profiles[].postCount describes saved posts. If the budget permits only a
partial charge, chargedPostCount reflects the SDK-reported count and
estimatedCostUsd is calculated from that count and the runtime unit price.
unchargedPostCount shows the difference. The Actor stops further
work when the post charge limit is reached. Already saved profiles remain
available and are not charged again when the run resumes.
If the post event is not configured, the log says not_configured and
reports zero charged posts and zero estimated post cost. Non-pay-per-event runs report
not_pay_per_event; empty batches of posts report empty. If the charge
outcome cannot be confirmed, the log says unconfirmed and uses null
for the charged count and estimated cost. These estimates cover only the post
event, not the total run cost. The Actor retains the saved profiles and
does not automatically retry an uncertain charge or backfill charges for
profiles already found in the Dataset during recovery.
skipRelatedProfiles (optional, default: true)
If related_profiles is not required for your use case, keeping this enabled helps speed up scraping.
When disabled, the actor returns the full related_profiles list Instagram exposes.
Quick start (Apify Console)
- Add one or more values to
instagramUsernames(either usernames likenypostor URLs likehttps://www.instagram.com/google/). - Adjust
retriesonly if you hit temporary errors. - Click Run → open the Dataset tab to view/export results (JSON, CSV, Excel, etc.).
Invalid usernames and malformed profile URLs are listed in run logs with a rejection reason and skipped before tasks are created. They do not create Dataset rows.
This makes the actor usable as an Instagram profile scraping API, because datasets can be consumed programmatically via Apify’s API.
Example input
{"instagramUsernames": ["kevinhart4real"],"scrapeFacebookProfile": true,"skipAdditionalData": false,"skipRelatedProfiles": false}
Example output
{"pk": "123","username": "sampleprofile","full_name": "Sample Profile","is_private": false,"is_verified": false,"is_business": false,"requested_by_viewer": false,"business_email": null,"profile_pic_url": "https://example.com/profile.jpg","profile_pic_url_hd": "https://example.com/profile-hd.jpg","biography": "Sample profile","external_url": "https://example.com/","bio_links": [],"post_count": 42,"id": "123","url": "https://www.instagram.com/sampleprofile/","contact_email": null,"followers": 321,"following": 12,"latest_posts": [{"pk": "media-0","id": "opaque-media-0","code": "SHORT0","shortcode": "SHORT0","url": "https://www.instagram.com/p/SHORT0/","media_type": 8,"product_type": "carousel_container","caption": "Example post 0 #sample @collaborator","hashtags": ["sample"],"mentions": ["collaborator"],"accessibility_caption": "Example preview","display_uri": "https://example.com/preview-0.jpg","image": "https://example.com/preview-0.jpg","is_video": false,"user": {"id": "author-0","username": "sampleprofile"},"carousel_media_count": 7,"crawled_at": "2026-10-31T00:00:00Z"}],"related_profiles": [],"fb_profile": null,"ig_status": "ok","crawled_at": "2026-10-31T00:00:00Z","is_professional_account": null,"category": null,"should_show_category": null}
Example dataset item when a profile is not found:
{"username": "11","ig_status": "not_found","message": "Profile not found or restricted","url": "https://www.instagram.com/11/","crawled_at": "2026-02-06T08:03:20.522Z"}
Here, ig_status: "not_found" means Instagram did not return profile data for that username because the profile does not exist or access to it is restricted.
Tips & troubleshooting
Don’t overload the actor. If you need to scrape large lists, split inputs into batches.
Legal & ethical notice
You are responsible for ensuring your use of this actor complies with:
- Instagram’s Terms of Service
- Applicable laws and regulations (privacy, data protection, etc.)
Only scrape data you have the right to access, and avoid collecting personal data without a lawful basis.