Instagram Profile Scraper avatar

Instagram Profile Scraper

Pricing

from $2.50 / 1,000 profile results

Go to Apify Store
Instagram Profile Scraper

Instagram Profile Scraper

Scrape public Instagram profiles from usernames, @handles or profile URLs. Extract bio, follower/following counts, posts count, profile picture, verified/private status, category, bio links, business email, phone and other public profile metadata. Export clean JSON, CSV or Excel.

Pricing

from $2.50 / 1,000 profile results

Rating

0.0

(0)

Developer

Delowar Munna

Delowar Munna

Maintained by Community

Actor stats

0

Bookmarked

1

Total users

1

Monthly active users

4 days ago

Last modified

Categories

Share

Instagram Profile Scraper

Scrape public Instagram profiles from usernames, @handles or profile URLs. Extract bio, follower/following counts, posts count, profile picture, verified/private status, category, bio links, business email, phone and other public profile metadata. Export clean JSON, CSV or Excel.

What this actor does

Instagram Profile Scraper takes a list of Instagram handles or profile URLs and returns one clean, structured row per profile:

  • 👤 Identity: username, full name, stable numeric user ID, profile URL, HD profile picture, bio, pronouns
  • 📊 Counts: followers, following, posts, highlight reels
  • ✅ Flags: verified, private, business account, professional (creator) account, has Reels, Threads badge, recently joined
  • 🏷️ Category: the business/creator category shown on the profile
  • 🔗 Links: the website field plus every bio link, not just the first one
  • 📇 Public business contact: business email, phone, address and preferred contact method, but only when Instagram itself shows them publicly
  • 🧭 Related profiles: Instagram-suggested similar accounts, when Instagram exposes them
  • 🖼️ Optional recent-posts preview: the latest few posts (URL, type, caption, timestamp, likes, comments, thumbnail)

Field availability: Instagram currently throttles anonymous traffic and errors on many business profiles. Those profiles are served by a fallback source, which returns identity, counts, flags, category, bio and links but not the posts count, highlight count, related profiles, recent posts or public email/phone. On a heavily throttled run, most rows look like the fallback sample below.

It is a profile metadata scraper, not a posts or Reels scraper. It's built for creator enrichment, lead enrichment, competitor tracking and as the profile layer in larger Instagram pipelines.

How it works

  1. Normalize inputs. nasa, @nasa, instagram.com/nasa, m.instagram.com/nasa/?igsh=… all become nasa. Tracking parameters are stripped and duplicate aliases are removed.
  2. Fetch. Each profile comes from Instagram's public web profile endpoint over plain HTTP. No browser, no login.
  3. Fall back instead of waiting. A rate limit or login wall gets one retry on a fresh session/IP. If Instagram still refuses, the profile is fetched from an alternative source. When Instagram refuses many requests in a row, the run sends profiles to the alternative source first and keeps checking whether Instagram has recovered. Profiles that don't exist are never retried.
  4. Export. One row per profile. Inputs that can't be resolved get a free status row, so every input can be matched to an output.

Speed: 100 profiles in about 70 seconds at the default concurrency of 10 (measured on the Apify platform). Raise maxConcurrency (up to 20) for larger lists.

Input

FieldTypeDefaultDescription
profilesstring[]requiredUsernames, @handles, profile URLs or numeric user IDs (up to 1,000 per run)
includeBusinessContactbooltruePublic business email / phone / address shown by Instagram
includeBioLinksbooltrueAll public bio links
includeRelatedProfilesbooltrueInstagram-suggested related accounts (listed, not scraped)
includeRecentPostsboolfalseLightweight preview of the latest posts
maxRecentPostsint3Posts per profile in the preview (1–12)
proxyConfigurationobjectApify Proxy onProxy settings
maxConcurrencyint10Profiles fetched in parallel
maxRetriesint4Retries per profile on rate limits / login walls / temporary errors
debugModeboolfalseVerbose logging

Example 1: Enrich a list of handles

{
"profiles": ["nasa", "@nike", "https://www.instagram.com/instagram/"]
}

Example 2: Lead enrichment with a recent-posts preview

{
"profiles": [
"https://www.instagram.com/glossier/",
"https://www.instagram.com/allbirds/",
"@gymshark"
],
"includeBusinessContact": true,
"includeBioLinks": true,
"includeRelatedProfiles": false,
"includeRecentPosts": true,
"maxRecentPosts": 5
}

Example 3: Bulk brand and creator lookup (used for the screenshot and samples below)

{
"profiles": [
"natgeo", "nasa", "@nike", "@starbucks",
"https://www.instagram.com/instagram/", "https://www.instagram.com/spotify/",
"netflix", "cristiano", "@therock", "taylorswift",
"https://www.instagram.com/bbcnews/", "nytimes", "@redbull", "gopro",
"airbnb", "https://www.instagram.com/lego/", "apple", "google", "@unicef", "time",
"this_profile_does_not_exist_9x",
"https://www.instagram.com/p/C0xAbCdEfGh/"
],
"includeBusinessContact": true,
"includeBioLinks": true,
"includeRelatedProfiles": true,
"includeRecentPosts": false
}

Example 4: Mixed valid and invalid inputs

Invalid and nonexistent entries don't stop the run; each gets its own free status row.

{
"profiles": [
"nasa",
"@nike",
"this_profile_does_not_exist_9x",
"https://www.instagram.com/p/C0xAbCdEfGh/"
]
}

Output

One row per profile. Unavailable values are null, never guessed. Every row has the same columns, so CSV/Excel exports stay stable. The dataset has three tabs: Profiles, Business & contact and Status & errors.

Profiles table view

Profiles tab: sample record

{
"profilePicUrl": "https://scontent-lga3-1.cdninstagram.com/v/t51.2885-19/29090066_159271188110124_1152068159029641216_n.jpg?stp=dst-jpg_s320x320_tt6",
"username": "nasa",
"fullName": "NASA",
"profileUrl": "https://www.instagram.com/nasa/",
"followersCount": 104267097,
"followingCount": 90,
"postsCount": 4955,
"isVerified": true,
"isPrivate": false,
"isBusinessAccount": true,
"categoryName": "Government Agencies",
"biography": "Making the seemingly impossible, possible. ✨",
"externalUrl": "https://www.nasa.gov/",
"highlightReelCount": 6,
"userId": "528817151",
"status": "SUCCESS",
"scrapedAt": "2026-10-08T12:13:29.284Z"
}

Business & contact tab: sample record

{
"username": "nike",
"fullName": "Nike",
"profileUrl": "https://www.instagram.com/nike/",
"isBusinessAccount": true,
"isProfessionalAccount": true,
"categoryName": null,
"businessEmail": null,
"businessPhone": null,
"businessAddress": {
"street": "One Bowerman Dr",
"zipCode": "97005",
"cityName": "Beaverton, Oregon",
"cityId": "108410602520455",
"regionName": null,
"countryCode": null,
"latitude": 45.5076448,
"longitude": -122.8269159
},
"businessContactMethod": "CALL",
"externalUrl": "http://empli.fi/nike",
"bioLinks": [
{ "title": null, "url": "http://empli.fi/nike", "linkType": "external" }
],
"followersCount": 291032089
}

Status & errors tab: sample records

Every input gets a row, so you can reconcile inputs with outputs. These rows are free. A deleted or renamed account is returned as PROFILE_NOT_FOUND, even when Instagram was throttling the request and the alternative source confirmed it:

{
"input": "justinbieber",
"status": "PROFILE_NOT_FOUND",
"errorMessage": "Instagram rate-limited the request; the fallback source reports this account does not exist (This account does not exist.)",
"username": "justinbieber",
"userId": null,
"profileUrl": "https://www.instagram.com/justinbieber/",
"scrapedAt": "2026-10-08T16:45:56.857Z"
}
{
"input": "https://www.instagram.com/p/C0xAbCdEfGh/",
"status": "INVALID_INPUT",
"errorMessage": "Post/Reel URL — provide the profile URL or username instead",
"username": null,
"userId": null,
"profileUrl": null,
"scrapedAt": "2026-10-08T12:12:45.218Z"
}

Profile served by the fallback source: sample record

Instagram's own profile endpoint currently errors for many business accounts and throttles heavy anonymous traffic, so these profiles come from an alternative source. Identity, follower counts, flags, category, bio and links are returned. postsCount, highlightReelCount, related profiles, the recent-posts preview and public email/phone aren't available for them. These rows are SUCCESS and charged like any other profile.

{
"status": "SUCCESS",
"errorMessage": null,
"username": "gopro",
"fullName": "GoPro",
"userId": "28902942",
"profileUrl": "https://www.instagram.com/gopro/",
"profilePicUrl": "https://scontent-mad1-1.cdninstagram.com/v/t51.2885-19/449069728_1006900254437011_2641997517452774766_n.jpg",
"biography": "We help the world to capture and share itself in immersive and exciting ways.\n#GoProMISSION1 Series👇",
"externalUrl": "http://gopro.com/MISSION1",
"bioLinks": [
{ "title": null, "url": "http://gopro.com/MISSION1", "linkType": "external" }
],
"followersCount": 20017422,
"followingCount": 240,
"postsCount": null,
"isVerified": true,
"isPrivate": false,
"isBusinessAccount": true,
"isProfessionalAccount": true,
"categoryName": "Product/service",
"pronouns": null,
"businessEmail": null,
"businessPhone": null,
"businessAddress": null,
"businessContactMethod": null,
"highlightReelCount": null,
"hasReels": true,
"hasChannel": null,
"facebookId": "17841401168260451",
"metaEntityId": null,
"hasThreadsProfile": false,
"isJoinedRecently": null,
"relatedProfiles": [],
"recentPosts": null,
"input": "gopro",
"scrapedAt": "2026-10-08T12:13:19.318Z"
}

Full record (all fields)

bioLinks and relatedProfiles are trimmed to two entries and image URLs are shortened; the real row for this profile has 5 bio links and 50 related profiles.

{
"status": "SUCCESS",
"errorMessage": null,
"username": "spotify",
"fullName": "Spotify",
"userId": "224223453",
"profileUrl": "https://www.instagram.com/spotify/",
"profilePicUrl": "https://scontent-ord5-1.cdninstagram.com/v/t51.2885-19/445718249_461892682885950_4604984260220263282_n.jpg?stp=dst-jpg_s320x320_tt6",
"biography": "the #VMAs may be over, but we’re replaying the performances on Spotify 💚",
"externalUrl": "https://open.spotify.com/episode/5oG3OBikHqGgz7WkzqOdZp?si=FjkBVeW3TqSZkI2DnqD3fQ",
"bioLinks": [
{ "title": "Billions Club Live with Olivia Rodrigo: A Concert Film", "url": "https://open.spotify.com/episode/5oG3OBikHqGgz7WkzqOdZp?si=FjkBVeW3TqSZkI2DnqD3fQ", "linkType": "external" },
{ "title": "Fitness with Spotify", "url": "https://open.spotify.com/genre/0JQ5DAqbMKFJ6dHNHTv6Mx", "linkType": "external" }
],
"followersCount": 14572641,
"followingCount": 2344,
"postsCount": 8699,
"isVerified": true,
"isPrivate": false,
"isBusinessAccount": true,
"isProfessionalAccount": true,
"categoryName": "Personal Goods & General Merchandise Stores",
"pronouns": null,
"businessEmail": null,
"businessPhone": null,
"businessAddress": null,
"businessContactMethod": null,
"highlightReelCount": 5,
"hasReels": true,
"hasChannel": false,
"facebookId": "17841400943593503",
"metaEntityId": "105569130841322",
"hasThreadsProfile": true,
"isJoinedRecently": false,
"relatedProfiles": [
{ "id": "20698621", "username": "iheartradio", "fullName": "iHeartRadio", "isVerified": true, "isPrivate": false, "profilePicUrl": "https://scontent-ord5-1.cdninstagram.com/v/t51.82787-19/564929969_18543059638026622_5952893746579818399_n.jpg" },
{ "id": "1156947332", "username": "amazonmusic", "fullName": "Amazon Music", "isVerified": true, "isPrivate": false, "profilePicUrl": "https://scontent-ord5-1.cdninstagram.com/v/t51.2885-19/464314201_916142467235385_4291848297418975667_n.jpg" }
],
"recentPosts": null,
"input": "https://www.instagram.com/spotify/",
"scrapedAt": "2026-10-08T12:13:23.804Z"
}

Status values

Every row has a status. Only SUCCESS rows are charged.

StatusMeaning
SUCCESSProfile returned (private accounts included: their public metadata is still a result)
PARTIAL_RESULTProfile found, but core fields (user ID, follower or following count) are missing. Delivered free
INVALID_INPUTNot a valid username / profile URL (e.g. a post or Reel URL)
PROFILE_NOT_FOUNDThe username or ID does not exist (also when Instagram was throttling and the fallback source confirmed the account doesn't exist)
PROFILE_UNAVAILABLEInstagram returned an error for this profile instead of its data (e.g. restricted, or an Instagram-side error)
RATE_LIMITED / LOGIN_WALL / BLOCKEDInstagram throttled or walled this profile and the fallback source couldn't return it either
TEMPORARY_INSTAGRAM_ERROR / PROVIDER_ERRORInstagram or network error persisted through retries

Recent posts preview fields

postId, shortCode, postUrl, type (Image / Video / Sidecar / Reel), caption, timestamp, likesCount, commentsCount, thumbnailUrl.

Run summary

Each run writes a SUMMARY record to the key-value store with status counts, charged profiles, retries, profiles/minute, how many profiles came from the fallback source (and why), and availability rates (private, business, email, phone, bio links, related profiles).

Pricing

Pay per event, per successfully returned unique profile. You are not charged for invalid inputs, duplicate inputs, profiles that don't exist, partial results or error rows. There is no start fee. The per-profile rate can differ by Apify plan, so see the Pricing tab for the current rate on yours. This README deliberately doesn't quote figures.

The actor respects the spending limit you set for a run: when it's reached, the run stops cleanly and no further profiles are fetched.

🚦 Proxy policy

Use Apify Datacenter proxy (the default) or no proxy for normal runs. Both are supported: when Instagram throttles the proxy's IPs, profiles are served by the fallback source instead.

Apify Residential proxy is not supported. The actor fails at startup if apifyProxyGroups includes RESIDENTIAL. In pay-per-event actors, residential bandwidth is billed per GB to the developer, not the run user, so a single bandwidth-heavy run could cost more than the per-result revenue.

If you need residential routing, supply your own residential provider in the proxy editor's Custom proxy URLs field. That traffic goes through your provider, not Apify, and is unaffected:

http://user:pass@proxy.iproyal.com:12321
http://user:pass@proxy.brightdata.com:22225
http://user:pass@proxy.oxylabs.io:7777

Limitations

  • Public data only. Private accounts return the metadata Instagram shows publicly (name, picture, counts, bio). Their posts are never accessed.
  • Numeric user IDs are best-effort. Instagram often requires login to look up an ID, so these inputs can end as LOGIN_WALL. Usernames and URLs are the reliable path.
  • Related profiles come from Instagram's own suggestions, typically up to ~50 per profile. Some profiles return none.
  • Some profiles are served by a fallback source. Instagram's own profile endpoint currently errors for many business and creator accounts, and it throttles anonymous traffic on busy runs. In both cases the actor retrieves the profile from an alternative source, returning the same identity, follower/following, verified/private/business flags, category, bio and link fields, but without public email/phone, the posts count (postsCount is null), highlight count, related profiles or the recent-posts preview. If the fallback source reports that the account doesn't exist, the row is a free PROFILE_NOT_FOUND; if it fails for another reason, a free PROFILE_UNAVAILABLE or RATE_LIMITED row. On a heavily throttled run, most rows can come from the fallback source.
  • Business contact fields are Instagram's own public fields. Large brands rarely show a public email or phone, so expect these mostly from smaller businesses and creators. The actor doesn't search the web for emails or extract hidden contact details.
  • Recent posts are a short preview from the profile response, capped at 12. Use a dedicated posts scraper for full content.
  • Instagram limits anonymous traffic per IP. Throttled profiles go to the fallback source after one retry; a profile neither source can return ends as RATE_LIMITED. Those rows are free.

This is an unofficial tool and is not affiliated with, endorsed by or sponsored by Instagram or Meta. It collects only publicly available profile metadata and doesn't log in, collect credentials or bypass private-account controls.

Public business contact fields can contain personal information. You are responsible for processing the data lawfully (e.g. GDPR/CCPA). Collect only what you need, and don't use profile data for unlawful discrimination, harassment or sensitive profiling.

Local development

cd actor
npm install
npm test # unit tests (normalizer, parser, response classification)
npm start # run with INPUT.json