Request a tool
All toolsGuidesMCP serverRequest a toolPlatformsCategories
Instagram Profile Scraper icon

Instagram Profile Scraper

Scrape Instagram profiles by username: bio, followers, following, posts count, verified flag, business category, bio links and HD avatar. No login.

14 runs on Apify
Run this in the cloudRun on Apify →

Social Media Scrapers

How it works

  1. 1
    Open it on Apify

    Hit Run on Apify — it opens the tool in the cloud, no install.

  2. 2
    Set the inputs

    Adjust usernames, profileUrls, includeLatestPosts (sensible defaults are pre-filled).

  3. 3
    Click Run

    The tool runs on Apify’s cloud and collects the data for you.

  4. 4
    Export the results

    Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.

Inputs

FieldWhat it doesType
usernamesInstagram handles to scrape, one profile per row. With or without the @.array
profileUrlsPaste full profile URLs instead of handles — https://www.instagram.com/nasa/ works too.array
includeLatestPostsAdds the account's most recent posts (up to 12) to each row as latestPosts. Costs nothing extra.boolean
resultsLimitStop after this many profiles. Leave empty to scrape every handle you supplied. Hard ceiling 1000.integer
maxConcurrencyHow many profiles to fetch at once. 8 is the default and is also the cheapest setting - the run bills by wall-clock time, so finishing sooner costs less.integer
notionConnectorOptional. Deliver the scraped profiles straight to your connected Notion workspace.string
notionParentIdOptional Notion database/data-source id to create the pages in.string

What you get

A structured dataset — each result includes fields like:

usernamefullNamefollowersCountfollowsCountpostsCountverifiedbiographyexternalUrlurl

Export every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.

Related tools in Social Media Scrapers

Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.

Instagram Reel Scraper iconSocial Media Scrapers

Instagram Reel Scraper

Scrape any public Instagram profile's reels: play counts, likes, comments, captions, duration, MP4 and cover links, audio track. No login or API key.

Ready to run — no setup

Instagram Reel Scraper iconSocial Media Scrapers

Instagram Reel Scraper

Scrape any public Instagram profile's reels: play counts, likes, comments, duration, video and cover URLs, audio track. No login or API key.

Ready to run — no setup

LinkedIn Post Search Scraper iconSocial Media Scrapers

LinkedIn Post Search Scraper

Scrape public LinkedIn posts by keyword: author, text, exact date, reactions, comments and post URL. No login or cookies.

Ready to run — no setup

LinkedIn Profile Search Scraper iconSocial Media Scrapers

LinkedIn Profile Search Scraper

Find public LinkedIn profiles by keyword, job title, company, school or location. Get name, headline, location, current role and profile URL.

Ready to run — no setup

YouTube Shorts Scraper iconSocial Media Scrapers

YouTube Shorts Scraper

Extract YouTube Shorts by channel or keyword: titles, video ids, URLs, exact views and likes, publish dates, durations, thumbnails and channel details.

Ready to run — no setup

TikTok Scraper - Profiles, Videos, Hashtags & Search iconSocial Media Scrapers

TikTok Scraper - Profiles, Videos, Hashtags & Search

Keyless TikTok scraper for profiles, videos, hashtags & search. Get views, likes, comments & video URLs as JSON/CSV. Cheaper, no API key, failed runs free.

5 use cases

See all Social Media Scrapers →

Instagram Profile Scraper

Give it Instagram handles, get one row per public profile back: full biography, follower / following / post counts, verified and private flags, professional-account and business-category fields, every bio link, the HD avatar, the account's related-profile suggestions, and — if you tick the box — its 12 most recent posts.

No Instagram account. No cookies to paste. No session token. No proxy of your own. Type handles, get rows.

Price

$0.55 per 1,000 profiles, plus $0.0000125 to start a run.

That makes it the cheapest Instagram profile scraper on the market. The rate is also flat: the same $0.55 on the free plan as on any paid plan, with no volume tiers, no minimum spend and no plan gates, so the number below is what you pay from your very first run.

ProfilesCost here
100$0.055
1,000$0.55
10,000$5.50
100,000$55.00

Plus the $0.0000125 run-start fee, once per run, whatever the size of the run.

What is actually billed

  • profile-scraped — $0.00055. Charged once, immediately after a real profile row is written

to the dataset. One charge per profile, never per post: turning on "include the latest posts" adds up to 12 posts to the row and costs nothing extra.

  • apify-actor-start — $0.0000125 per GB of run memory. The Actor's default memory is 1 GB, so

that is $0.0000125 per run.

  • Free: everything else. The sample row a run with no input returns is not charged. Diagnostic

rows (profile not found, blocked, bad input) are not charged. A run that finds nothing costs the start fee alone.

There are no add-on events

profile-scraped is the only result event this Actor has. Switching on includeLatestPosts adds up to 12 posts to the row and costs nothing extra; neither do relatedProfiles, the HD avatar, the full externalUrls array or the e-mail/phone extraction — they are all part of the same profile row. Nothing is metered per page, per request or per proxy gigabyte, so the table above plus the fractional start fee is the entire bill. A run you cancel mid-way is billed only for the rows it had already written.

Input

FieldWhat it does
usernamesInstagram handles. nasa, @nasa and https://www.instagram.com/nasa/ are all accepted.
profileUrlsSame thing, if you would rather paste URLs. Merged with usernames, de-duplicated.
includeLatestPostsOff by default. On, each row gets latestPosts — up to 12 recent posts with caption, hashtags, mentions, media URLs and timestamp.
resultsLimitStop after this many profiles. Leave empty to do every handle you supplied. Ceiling 1,000.
maxConcurrencyHow many profiles to fetch at once. Default 8, ceiling 16.
proxyConfigurationLeave empty. See "How it works" for why.
{
  "usernames": ["nasa", "natgeo", "@nike"],
  "profileUrls": ["https://www.instagram.com/spotify/"],
  "includeLatestPosts": true,
  "resultsLimit": 10
}

usernames is a prefill, not a default — running with genuinely empty input returns one labelled sample row, uncharged, so you can see the row shape before spending anything.

Output

A real row, trimmed for length (this is nasa, run 2026-08-15):

{
  "inputUrl": "https://www.instagram.com/nasa/",
  "id": "528817151",
  "username": "nasa",
  "url": "https://www.instagram.com/nasa/",
  "fullName": "NASA",
  "biography": "Making the seemingly impossible, possible. ✨",
  "externalUrl": "https://www.nasa.gov/",
  "externalUrlShimmed": "https://l.instagram.com/?u=https%3A%2F%2Fwww.nasa.gov%2F&e=AUA5zD4…",
  "externalUrls": [
    { "title": "NASA.gov Homepage", "url": "https://www.nasa.gov", "lynxUrl": "https://l.instagram.com/?u=…", "linkType": "external" },
    { "title": "NASA Internships", "url": "http://intern.nasa.gov", "lynxUrl": "https://l.instagram.com/?u=…", "linkType": "external" }
  ],
  "followersCount": 104395191,
  "followsCount": 92,
  "postsCount": 4882,
  "hasChannel": false,
  "highlightReelCount": 5,
  "igtvVideoCount": 171,
  "isBusinessAccount": true,
  "isProfessionalAccount": true,
  "joinedRecently": false,
  "businessCategoryName": "Government Agencies",
  "categoryName": null,
  "businessEmail": null,
  "businessPhoneNumber": null,
  "businessContactMethod": "CALL",
  "businessAddress": null,
  "private": false,
  "verified": true,
  "profilePicUrl": "https://scontent.cdninstagram.com/v/t51.2885-19/29090066_159271188110124_…",
  "profilePicUrlHD": "https://scontent.cdninstagram.com/v/t51.2885-19/29090066_159271188110124_…",
  "fbid": "17841401474538262",
  "relatedProfiles": [
    { "id": "1067259270", "username": "nasagoddard", "fullName": "NASA Goddard", "isVerified": true, "isPrivate": false, "profilePicUrl": "https://…" }
  ],
  "latestPosts": [
    {
      "id": "3963668990156895830",
      "type": "Video",
      "shortCode": "DcBx_I1iHZW",
      "url": "https://www.instagram.com/p/DcBx_I1iHZW/",
      "caption": "Check out the eclipse from 50,000 feet in the air!…",
      "hashtags": ["NASA", "Eclipse2026", "Aircraft"],
      "mentions": [],
      "likesCount": 187209,
      "commentsCount": 1234,
      "videoViewCount": 4026346,
      "displayUrl": "https://scontent.cdninstagram.com/v/t51.82787-15/774149093_…",
      "images": ["https://scontent.cdninstagram.com/v/t51.82787-15/774149093_…"],
      "alt": "Video by NASA on August 14, 2026…",
      "isVideo": true,
      "timestamp": "2026-08-14T18:02:41.000Z",
      "ownerUsername": "nasa",
      "ownerId": "528817151"
    }
  ],
  "emailsFound": [],
  "phonesFound": [],
  "bioHashtags": [],
  "bioMentions": [],
  "pronouns": [],
  "dataSource": "web_profile_info",
  "scrapedAt": "2026-08-15T02:31:07.882Z"
}

The field names follow the conventions used across Instagram profile Actors — username, fullName, followersCount, followsCount, postsCount, verified, private, isBusinessAccount, businessCategoryName, externalUrl, externalUrls, profilePicUrl, profilePicUrlHD, relatedProfiles, latestPosts, highlightReelCount, igtvVideoCount, fbid, inputUrl — so an existing pipeline can be pointed at this Actor without editing the code that reads the rows. Everything extra (emailsFound, phonesFound, bioHashtags, bioMentions, businessEmail, businessPhoneNumber, businessAddress, isProfessionalAccount, dataSource) is appended after those.

Field coverage

Measured on a real 40-account run on the platform, 2026-08-15. 40 of 40 handles returned a row.

FieldPresent
username, id, url, followersCount, verified, private100%
profilePicUrl, profilePicUrlHD, fbid, highlightReelCount100%
latestPosts (with includeLatestPosts on)100%
fullName98%
followsCount95%
isBusinessAccount, igtvVideoCount93%
externalUrl, externalUrls90%
biography88% (the rest genuinely have an empty bio)
postsCount83%
relatedProfiles70% (Instagram returns none for some accounts)
businessCategoryName20%
businessEmail, businessPhoneNumber0% — see below

Missing values are null. Nothing is ever guessed or interpolated.

Limits

Read this part before you build on it.

  • businessEmail and businessPhoneNumber were null on every one of the 22 accounts tested,

large brands and small shops alike. Instagram no longer returns public contact details on the logged-out endpoints. The fields are still in the row, so the row shape stays stable for existing pipelines, but do not plan a lead-gen pipeline around them. What does work: any e-mail or phone number an account writes into its bio text is extracted into emailsFound and phonesFound.

  • postsCount is null on about 17% of accounts. Instagram's primary profile endpoint currently

returns HTTP 400 for a large minority of professional accounts (see "How it works"), and the fallback path can only recover the exact post total when the profile page states it exactly. When the page rounds it — "9.5M Posts" — the field is left null rather than reporting a rounded number as if it were a count. Follower and following counts are exact on every path.

  • Public profiles only. A private account returns its bio, counts and avatar — that is all

Instagram shows a logged-out visitor — with private: true. Its posts are not accessible and no attempt is made to get them.

  • latestPosts is up to 12 posts, never more. This Actor reads profiles. It does not paginate

a feed, and it does not scrape comments, followers, stories, tagged posts or hashtags.

  • Counts move. A followers number is a reading at scrapedAt, not a stable identifier. Two runs

a minute apart on a large account will differ by thousands.

  • A handle that does not exist returns an uncharged NOT_FOUND diagnostic row, not a crash and

not a charge.

  • 1,000 profiles per run (resultsLimit ceiling), and the run timeout is 5 minutes. 40

profiles took 77 seconds at the default concurrency of 8, so a run covers a few hundred handles comfortably; for very large lists, split them across runs or raise maxConcurrency.

FAQ

Do I need an Instagram account, cookies or a session id? No. Nothing to log in to and nothing to paste. Every endpoint used here is one a logged-out visitor hits.

Do I need to buy proxies? No. Proxy rotation is built in and its cost is already inside the $0.55.

What does 1,000 profiles cost? $0.55, plus the $0.0000125 start fee.

Is this really the cheapest Instagram profile scraper? Yes — $0.55 per 1,000 profiles, and it is the same $0.55 on every plan rather than a headline rate you only reach at high volume. The full billing mechanics are spelled out under "Price".

Can I switch from another Instagram profile Actor without changing my code? Usually. Input field names follow the common conventions used across similar Actors — usernames is the same field it is everywhere — and the output field names match too, so switching is normally a drop-in change. An "about section" block (date joined, country) that some Actors offer has no equivalent here; in the other direction, this Actor returns fields (emailsFound, phonesFound, bioHashtags, bioMentions, pronouns, dataSource) that most do not.

Does it return e-mail addresses? Only ones written into the bio text, in emailsFound. Instagram's public contact-e-mail field came back empty on every account tested — see "Limits".

How fast is it? 40 profiles in 77 seconds on the platform at the default settings, half of them on the slower fallback path. Accounts on the fast path take 1.5–2 seconds each.

Can I export to CSV or Excel? Yes — Apify exports the dataset as JSON, CSV, Excel or XML, and the same data is available over the REST API.

What happens if I run it with no input? One labelled sample row, uncharged, and the run finishes as SUCCEEDED.

Is this affiliated with Instagram or Meta? No. It reads public profile data. Check Instagram's terms and your own local rules before using the output commercially.

How it works

Instagram's logged-out profile API is metered per IP address, not per account, and it answers a spent address with 401 "Please wait a few minutes before you try again" — an HTTP status, not a captcha. The fix is a large pool you can hop through rather than a fast pool you keep hitting, so this Actor requests a fresh Apify datacenter address for every attempt. Datacenter addresses are not billed per gigabyte, which matters because Instagram answers a profile request with 100–800 KB. Residential proxy is deliberately not used: it is metered by the gigabyte, and at that response size the bandwidth alone would cost more per row than a row is priced at. The cheap egress is the reason this price is possible.

Plain Node fetch is refused from every address — Instagram is judging the TLS handshake, not the IP. Requests go through impit with a genuine Chrome fingerprint instead, which returns HTTP 200 from the same addresses in the same second.

There is one more thing, and it is the reason this Actor returns rows for accounts where a single-endpoint scraper returns nothing. As of 2026-08-14 Instagram's main profile endpoint answers HTTP 400 for a large minority of professional accounts:

{"message":"Asset asset://laser.provider/ig_business_category_subvertical has been deleted.
You cannot use this schema"}

That is a bug in Instagram's own schema, not a block: it is deterministic per account and it reproduces from every address, so retrying and rotating cannot fix it. Measured across 20 well-known handles, 9 of 20 fail this way — natgeo, netflix, adidas, beyoncé, starbucks, airbnb, leomessi, shakira and hubspot among them. Any scraper that calls only that endpoint returns nothing for exactly those accounts.

So this one falls down a ladder instead of failing:

1. web_profile_info with the ordinary web app id — the complete answer when it works. 2. The same endpoint with a different app id, which is not subject to the broken schema. Its descriptive fields are good; its follower/following and post counts are not, so they are dropped rather than reported. 3. The logged-out profile page, whose embedded payload carries the exact follower and following counts and the recent posts, with the post total read from the page's own meta description. 4. The feed-by-username route, used only to recover recent posts when rung 3 is rate limited.

Rungs 2, 3 and 4 are merged into one row and dataSource records which of them produced it. In the 40-account run above, 21 rows came from rung 1 and 19 needed the ladder — and all 40 returned.