Instagram Followers / Following Scraper avatar

Instagram Followers / Following Scraper

Pricing

from $1.00 / 1,000 relationship results

Go to Apify Store
Instagram Followers / Following Scraper

Instagram Followers / Following Scraper

Export followers and following lists from public Instagram profiles. Get usernames, user IDs, names, profile URLs, verification and privacy status, plus optional profile metrics. Process multiple source accounts and export clean JSON, CSV or Excel.

Pricing

from $1.00 / 1,000 relationship results

Rating

0.0

(0)

Developer

Delowar Munna

Delowar Munna

Maintained by Community

Actor stats

0

Bookmarked

21

Total users

3

Monthly active users

6 days ago

Last modified

Categories

Share

Instagram Followers / Following Scraper

Export followers and following lists from public Instagram profiles. Get usernames, user IDs, names, profile URLs, verification and privacy status, plus optional profile metrics. Process multiple source accounts and export clean JSON, CSV or Excel. No Instagram login or cookies required.

What this actor does

Instagram Followers / Following Scraper takes Instagram usernames, @handles or profile URLs and returns one clean row per relationship:

  • 👥 Followers, following or both in one run. Every row is labelled FOLLOWER or FOLLOWING and carries its source profile.
  • 🪪 Identity fields for each returned account: user ID, username, full name, profile URL, profile picture, verified badge, private flag
  • 🔢 Rank: the account's position in the list as Instagram returned it, from 1, per source profile and list
  • 📊 Optional profile metrics: follower and following counts, bio, external URL, category and business flag for each returned account
  • 🎯 Filters: verified accounts only, drop private accounts, or a follower-count range (with metrics on). Filtered rows are free.
  • 🧾 Honest coverage: a free summary row per profile and list says whether you got the full available list, hit your limit, or Instagram served only part of it
  • 🔁 No double billing: duplicates within a list are removed before they are charged

It is a relationship scraper. For full profile data (bio links, business contact, recent posts) feed the usernames into Instagram Profile Scraper.

How it works

  1. Normalize inputs. natgeo, @NatGeo and https://www.instagram.com/natgeo/ all become natgeo; duplicates are removed. Post, Reel and Story URLs are rejected with a free error row.
  2. Resolve each source profile. Private and nonexistent profiles are reported straight away, without paging anything. The profile's displayed follower and following counts are kept for the coverage check.
  3. Page the list. Followers and following are fetched page by page, in order, until your limit, the end of the list, or a safety stop. Each list keeps its own cursor.
  4. Filter and enrich. Private and unverified filters run first. With profile metrics on, each remaining account is looked up once per run, then the follower-count range is applied.
  5. Export. One row per relationship, then one summary row per source profile and list with its coverage status.

FAQ

Which input formats are supported? Usernames (natgeo), @handles (@natgeo) and profile URLs (https://www.instagram.com/natgeo/, instagram.com/natgeo, mobile and _u/ links). Up to 100 source profiles per run.

Do I need an Instagram login or cookies? No. You never provide a login, cookies, a session ID or a Meta API token.

Can I scrape followers, following or both? Yes. Set relationshipType to FOLLOWERS, FOLLOWING or BOTH. With BOTH, rows from both lists are mixed in the dataset and labelled by relationshipType.

Can I process multiple profiles? Yes, up to 100 per run, several in parallel. One profile failing never stops the others.

Are private source profiles supported? No. A private profile's followers and following are not public. It gets a free summary row with status SOURCE_PRIVATE.

Can private accounts appear in the results? Yes. A public profile can be followed by, or follow, private accounts. They appear with public identity fields only (isPrivate: true); their content is never accessed. Turn off includePrivateAccounts to drop them, at no charge.

What fields are returned? See Output. Base rows carry the source profile, relationship type, rank and the account's identity fields.

Are follower counts for returned users included? Only with includeProfileMetrics. Base rows leave the metric fields null, because the lists themselves don't contain counts.

What does includeProfileMetrics do? It looks up each returned account once to add followersCount, followingCount, biography, externalUrl, categoryName and isBusinessAccount. postsCount is part of the schema but is usually null, because the lookup source rarely provides it. It costs one extra lookup per account, so these rows are billed at a separate, higher per-row price and the run is slower. It is required for minFollowers / maxFollowers.

Why might results stop before the displayed follower count? Three reasons. Your limit (maxFollowersPerProfile / maxFollowingPerProfile) was reached. Instagram's displayed counts include deactivated and restricted accounts that are never listed. And Instagram serves only part of very large follower lists. On accounts with tens of millions of followers you may get only the first few dozen. The summary row tells you which case applied.

What does coverage status mean?

Coverage statusMeaning
FULL_AVAILABLE_SETThe list ended naturally and roughly matches the profile's displayed count: you have everything Instagram lists.
LIMIT_REACHEDYour per-profile limit was reached; there are more.
PROVIDER_LIMITEDThe list ended well short of the displayed count. Typical for very large follower lists, which Instagram limits.
PARTIAL_PUBLICStopped early by an error, a safety stop or your spending limit. The rows delivered are valid.
SOURCE_PRIVATEThe source profile is private.
SOURCE_NOT_FOUNDThe source profile doesn't exist (or was renamed).
BLOCKEDInstagram or the data source refused the request even after retries.

How does pricing work? See Pricing.

Can I resume a large export? Within a run, yes. If a list hits a temporary error it resumes at the page where it stopped, and if Apify migrates the run to another server the run continues where it left off without charging rows twice. Across runs, profiles that failed for a temporary reason are saved to RETRY_INPUT, a ready-to-run input. A new run starts each list from the top.

Can I use it through the API or MCP? Yes. Call it like any Apify actor through the Apify API, the Apify clients for JavaScript and Python, or the Apify MCP server from an AI agent:

curl -X POST "https://api.apify.com/v2/acts/coregent~instagram-followers-following-scraper/run-sync-get-dataset-items?token=<YOUR_API_TOKEN>" \
-H "Content-Type: application/json" \
-d '{ "profiles": ["nasa"], "relationshipType": "FOLLOWING", "maxFollowingPerProfile": 100 }'

Input

FieldTypeDefaultDescription
profilesstring[]["nasa"]Usernames, @handles or profile URLs (max 100)
relationshipTypeenumFOLLOWINGFOLLOWERS, FOLLOWING or BOTH
maxFollowersPerProfileint1000Max follower rows per profile
maxFollowingPerProfileint1000Max following rows per profile
includePrivateAccountsbooltrueKeep returned accounts that are private
verifiedOnlyboolfalseReturn verified accounts only
includeProfileMetricsboolfalseAdd per-account counts, bio, external URL and category (enriched-row price)
minFollowersint0Returned accounts with at least this many followers (needs metrics; 0 = off)
maxFollowersint0Returned accounts with at most this many followers (needs metrics; 0 = off)
proxyConfigurationobjectApify Proxy onProxy settings, see Proxy policy
maxConcurrencyint5Source profiles processed in parallel (pages of one list are always sequential)
maxRetriesint4Retries per profile on rate limits or temporary errors
debugModeboolfalseVerbose logging

The run fails at startup, without charging anything, for an empty profiles list, a relationshipType other than the three above, a limit below 1, minFollowers greater than maxFollowers, or a follower-count filter without includeProfileMetrics.

Example 1: Followers of a profile

{
"profiles": ["natgeo"],
"relationshipType": "FOLLOWERS",
"maxFollowersPerProfile": 1000
}

natgeo has over 260 million followers, and Instagram serves only the first few dozen of a list that large (PROVIDER_LIMITED). Follower lists of small and mid-sized accounts, and following lists, page through to your limit.

Example 2: Who a profile follows

{
"profiles": ["nasa"],
"relationshipType": "FOLLOWING",
"maxFollowingPerProfile": 1000
}

Example 3: Both lists for several profiles

{
"profiles": ["natgeo", "@nasa", "https://www.instagram.com/europeanspaceagency/"],
"relationshipType": "BOTH",
"maxFollowersPerProfile": 500,
"maxFollowingPerProfile": 500
}

Example 4: Verified accounts only

{
"profiles": ["nasa"],
"relationshipType": "FOLLOWING",
"maxFollowingPerProfile": 100,
"verifiedOnly": true
}

Example 5: Followed accounts with 100k+ followers, with metrics

{
"profiles": ["nasa"],
"relationshipType": "FOLLOWING",
"maxFollowingPerProfile": 50,
"includeProfileMetrics": true,
"minFollowers": 100000
}

Output

The dataset holds three row types, with the same columns on every row so CSV and Excel exports stay stable:

  • rowType: "relationship": one returned follower or followed account (charged)
  • rowType: "summary": one per source profile and list, with the coverage status (free)
  • rowType: "error": an input that isn't a valid profile (free)

Filter on rowType when you only want relationships. The dataset has three tabs: Relationships, Profile metrics and Coverage & status.

Instagram Followers / Following Scraper: Relationships table view

The Relationships and Coverage & status records below come from a real run with the default input: nasa's full following list, 90 rows over 2 pages, plus 1 summary row. Long Instagram CDN URLs are shortened with ….

{
"profiles": ["nasa"],
"relationshipType": "FOLLOWING",
"maxFollowingPerProfile": 100
}

Relationships tab

{
"rowType": "relationship",
"status": "SUCCESS",
"errorMessage": null,
"coverageStatus": null,
"sourceProfile": {
"username": "nasa",
"id": "528817151",
"profileUrl": "https://www.instagram.com/nasa/",
"followersCount": 104341198,
"followingCount": 90
},
"relationshipType": "FOLLOWING",
"rank": 18,
"user": {
"id": "1387463011",
"username": "europeanspaceagency",
"fullName": "ESA - European Space Agency",
"profileUrl": "https://www.instagram.com/europeanspaceagency/",
"profilePicUrl": "https://scontent-man2-1.cdninstagram.com/v/t51.82787-19/654052426_…_n.jpg?stp=dst-jpg_e0_s150x150…",
"isVerified": true,
"isPrivate": false,
"followersCount": null,
"followingCount": null,
"postsCount": null,
"biography": null,
"externalUrl": null,
"categoryName": null,
"isBusinessAccount": null
},
"enriched": false,
"coverage": null,
"input": "nasa",
"scrapedAt": "2026-10-13T16:43:25.425Z"
}

Without includeProfileMetrics, enriched is false and followersCount through isBusinessAccount are null.

Profile metrics tab

With includeProfileMetrics on, the same row carries the account's metrics and enriched: true. Illustrative record from a FOLLOWING run on nasa:

{
"rowType": "relationship",
"status": "SUCCESS",
"errorMessage": null,
"coverageStatus": null,
"sourceProfile": {
"username": "nasa",
"id": "528817151",
"profileUrl": "https://www.instagram.com/nasa/",
"followersCount": 104341198,
"followingCount": 90
},
"relationshipType": "FOLLOWING",
"rank": 20,
"user": {
"id": "1234567890",
"username": "example_agency",
"fullName": "Example Space Agency",
"profileUrl": "https://www.instagram.com/example_agency/",
"profilePicUrl": "https://scontent.cdninstagram.com/…",
"isVerified": true,
"isPrivate": false,
"followersCount": 7218931,
"followingCount": 602,
"postsCount": null,
"biography": "Exploring the universe.",
"externalUrl": "https://example.org",
"categoryName": "Government organization",
"isBusinessAccount": true
},
"enriched": true,
"coverage": null,
"input": "nasa",
"scrapedAt": "2026-10-13T11:52:04.512Z"
}

Coverage & status tab

One summary row per source profile and list. This one is from the real run above: the list ended at nasa's displayed following count, so you have the full list.

{
"rowType": "summary",
"status": "SUCCESS",
"errorMessage": null,
"coverageStatus": "FULL_AVAILABLE_SET",
"sourceProfile": {
"username": "nasa",
"id": "528817151",
"profileUrl": "https://www.instagram.com/nasa/",
"followersCount": 104341198,
"followingCount": 90
},
"relationshipType": "FOLLOWING",
"rank": null,
"user": null,
"enriched": null,
"coverage": {
"listCount": 90,
"rowsReturned": 90,
"rowsScanned": 90,
"filteredOut": 0,
"pages": 2,
"stopReason": "end"
},
"input": "nasa",
"scrapedAt": "2026-10-13T16:43:33.261Z"
}

Very large follower list

A real summary row from a natgeo FOLLOWERS run: Instagram served 45 of natgeo's 268 million followers.

{
"rowType": "summary",
"status": "SUCCESS",
"errorMessage": "Instagram returned 45 of 268396514 listed accounts and no further pages. Very large lists are limited upstream; the rows returned are complete for what Instagram serves.",
"coverageStatus": "PROVIDER_LIMITED",
"sourceProfile": {
"username": "natgeo",
"id": "787132",
"profileUrl": "https://www.instagram.com/natgeo/",
"followersCount": 268396514,
"followingCount": 194
},
"relationshipType": "FOLLOWER",
"rank": null,
"user": null,
"enriched": null,
"coverage": {
"listCount": 268396514,
"rowsReturned": 45,
"rowsScanned": 45,
"filteredOut": 0,
"pages": 1,
"stopReason": "end"
},
"input": "natgeo",
"scrapedAt": "2026-10-13T15:34:13.811Z"
}

Private source profile

{
"rowType": "summary",
"status": "SOURCE_PRIVATE",
"errorMessage": "This Instagram profile is private: its followers and following are not public. Use coregent/instagram-profile-scraper for its public profile metadata.",
"coverageStatus": "SOURCE_PRIVATE",
"sourceProfile": { "username": "a_private_account", "id": "...", "profileUrl": "https://www.instagram.com/a_private_account/", "followersCount": 812, "followingCount": 455 },
"relationshipType": "FOLLOWER",
"rank": null,
"user": null,
"enriched": null,
"coverage": { "listCount": 812, "rowsReturned": 0, "rowsScanned": 0, "filteredOut": 0, "pages": 0, "stopReason": "failed" },
"input": "a_private_account",
"scrapedAt": "2026-10-13T11:45:32.020Z"
}

Status values

StatusMeaning
SUCCESSRelationship delivered, or the list finished normally
NO_RELATIONSHIPSThe list is empty
PARTIAL_RESULTSome rows were delivered before the list stopped (see the message)
INVALID_PROFILEThe input isn't a valid username or profile URL
PROFILE_NOT_FOUNDThe source profile doesn't exist
SOURCE_PRIVATEThe source profile is private
RATE_LIMITED / BLOCKEDRefused upstream even after retries
TEMPORARY_INSTAGRAM_ERROR / PROVIDER_ERRORTemporary or data-source error after retries

Run summary and retry input

Each run writes RUN_SUMMARY to the key-value store: profiles processed, succeeded and failed, follower and following rows saved, duplicates skipped, rows filtered (private, unverified, follower count), private and verified accounts returned, the coverage distribution, a per-profile/per-list breakdown, and request and timing figures. If any profile failed for a temporary reason, RETRY_INPUT holds a ready-to-run input containing just those profiles.

Pricing

Pay per event, per returned unique relationship row. There are two row prices:

  • Relationship: a follower or following row with identity fields.
  • Relationship with profile metrics: charged instead of the relationship price for rows enriched by includeProfileMetrics. It costs more because each account needs its own lookup.

You are not charged for profile resolution, pagination, retries, duplicates, filtered-out accounts, summary rows, invalid inputs or failed profiles. There is no start fee. Rates can differ by Apify plan, so see the Pricing tab for the current rates on yours. This README deliberately doesn't quote figures.

The actor respects the spending limit you set for a run: it never charges past it, and when the limit is reached the run stops cleanly and no further rows are fetched. Profiles cut short or not started get a free summary row saying so (stop reason spendingLimit). With profile metrics on, the limit is checked against the metrics price, and no profile is looked up unless its row can still be charged.

🚦 Proxy policy

Use Apify Datacenter proxy (the default) or no proxy for normal runs. The proxy is used only to look up source profiles on Instagram; lists come from the actor's own data source.

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 source profiles only. Private profiles' lists are not public.
  • Very large follower lists are limited by Instagram. Accounts with millions of followers may return only the first few dozen; the summary row says PROVIDER_LIMITED. Following lists and small-to-mid follower lists page through fully.
  • Order is not a ranking. rank is the position Instagram returned the account in. Instagram doesn't guarantee that order and it changes over time.
  • Lists change. Follows and unfollows happen constantly; two runs rarely match exactly.
  • Profile metrics are a snapshot from the moment of lookup. postsCount is usually null.
  • Safety stops. With filters, a list is scanned for up to 20× its limit (at least 2,000 accounts). A run also stops lookups that keep returning nothing billable, such as a follower-count filter almost nothing matches. Affected lists end with PARTIAL_PUBLIC and a message. Loosen the filters or split the run.
  • Not included: audience overlap, change tracking, bot or audience-quality scoring, contact details, and posts. Those belong to other actors or downstream analysis.

This is an unofficial tool. It is not affiliated with, endorsed by or sponsored by Instagram or Meta. It processes only publicly available relationship information from public source profiles and never accesses private profiles' content. Public usernames and profile data can still be personal data. You are responsible for having a lawful basis for collecting and processing it (for example under GDPR or CCPA) and for complying with Instagram's terms in your use of the data. The actor does no follow/unfollow or messaging automation and infers no sensitive traits.

Local development

cd actor
npm install
npm test # unit tests
npm start # runs with INPUT.json

Locally, put a TikHub API key in storage/key_value_stores/tikhub-config/TIKHUB_API_KEY.txt or the TIKHUB_API_KEY environment variable; without it, lists can't be fetched.