# Instagram Followers / Following Scraper (`arisma_tech/instagram-followers-scraper`) Actor

Scrape a seed account's followers or following list — one lightweight row per profile. No posts by default. Pay per delivered profile only, single flat price. Requires the user's own Instagram session token, because Instagram requires a login for followers/following lists.

- **URL**: https://apify.com/arisma_tech/instagram-followers-scraper.md
- **Developed by:** [Arishma](https://apify.com/arisma_tech) (community)
- **Categories:** Social media, Lead generation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.30 / 1,000 profiles

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Instagram Followers / Following Scraper

**NEW, separate Actor. Do not confuse it with the existing Instagram
Profile & Posts Scraper, and do not overwrite, republish or change
that Actor. Do not merge any existing Instagram PR into this project.**

### What it does

Input a seed Instagram username or URL, choose **followers** or
**following**, set a limit (default 200, range 1–1,000 per seed).
Output is one lightweight row per follower/following profile:

- username, full name, profile URL
- is_private, is_verified, profile picture URL
- followerCount / followingCount / biography — **filled by default**
  (one small detail request per profile, see below). They are null
  only if that detail request fails, or if you set
  `includeProfileDetails: false` for the fast lightweight run — the
  list payload itself does not carry them.

**No posts by default.** Post scraping is an explicit opt-in flag
(`includePosts`, default false) and is not part of the core job.
Per-profile detail enrichment is ON by default
(`includeProfileDetails`, default true) since 2026-10-26.

### How it stays cheap

- API-style HTTP list pages (50 profiles per page), no browser.
- **Session required for the list:** the user running the Actor
  supplies their own Instagram session token (`sessionToken` input).
  Instagram requires a login for followers/following lists, even
  for public accounts — without a session the run stops with
  `login_required`.
- Pagination with cursor, dedupe across pages (by user id, else
  username), hard stop at the limit.
- Charge event `profile` is fired only for a row actually pushed to
  the dataset. Failed, duplicate and gated rows are never charged.
- Charge event `proxy-traffic` is fired ONLY when the client uses
  Apify Proxy, at $0.0008 per full 100 KB of response body (same
  rate as the Instagram and LinkedIn Actors). No Apify Proxy = no
  proxy charge. A run under 100 KB charges 0 proxy units.
- On a hard stop (429 rate limit, login gate, seed not resolvable),
  the run keeps the partial rows it already delivered and logs the
  reason, instead of failing the whole run and losing them.

### Honest limitation

Instagram's followers endpoints are undocumented and can change,
rate-limit or gate accounts without warning. This Actor is built to
fail cleanly and partially, not to guarantee a complete list for
every seed, especially large or private accounts. That limitation
is NOT proved by the local tests, which use sample payloads
only — see Live test status below.

### Files

- `src/instagram.js` — pure parser / pagination / dedupe (tested locally)
- `src/main.js` — Apify Actor entry point (not run locally)
- `.actor/input_schema.json` — input: seeds, listType, limit, two opt-in flags, proxy
- `.actor/output_schema.json` — one row per profile
- `.actor/actor.json` — Actor metadata

### Local tests (no Apify credit, no network, no login)

```sh
npm test          # node --test test/instagram.test.js
npm run sample    # sample run against test/fixtures/*.json
```

Result on 2026-10-26, after the follower-count fix: **17/17 tests pass**,
sample run returns 5 unique profiles from 2 pages (3 + 3 rows minus
1 duplicate), stopped = `no_more_pages`, partial = false.

### Pricing

- **$0.30 per 1,000 delivered profiles, flat — one single price,
  no tiers, no discounts.**
- **Plus proxy-traffic at $0.0008 per 100 KB ONLY if the client
  uses Apify Proxy** (same rate as the Instagram and LinkedIn
  Actors). Client total: $0.30 without proxy, $0.3032 base /
  $0.3304 stress with proxy per 1,000.
- Actor start: $0.00005 per run.

### Live test status (2026-10-25, updated 2026-10-26)

- Session test with seed `natgeo`, followers: **delivered rows**
  (username, full name, profile URL, user id, private/verified,
  picture). The session path works, and the list IS followers.
- Old default run: followerCount / followingCount /
  biography were null, because the list payload does not carry them.
  That was the bug reported 2026-10-26 (e.g. quinn92752 has
  48 followers / 542 following on its own page, null in the dataset).
- Fix: detail mode is now ON by default — one small extra request
  per profile fills those three fields. Local tests pass (17/17,
  including quinn92752's 48/542 shape and geetaksh06's 3/7 user-info
  shape); a live detail-mode test with a real session is still pending — test with limit 10 first
  before running large jobs.
- FIX 2026-10-27: live limit-3 run 0bY6HSf2xfHRau75M proved
  web_profile_info alone fails for every profile (detail ok=0,
  failed=3, listSource=web) even with a session — so details now
  fall back to users/{id}/info (web, then mobile) and the log now
  reports detail sources and failure reasons. Re-test with limit 3
  and read the detail sources/reasons line from the log.

### Session token (required for followers/following lists, Oct 2026)

Instagram returns `401 require_login` for followers/following lists without a
session, even for public accounts (verified live 2026-10-25: GraphQL 400,
mobile 400, web 401, all logged-out). Seed resolution works logged-out
(profile page HTML), but the list itself does not.

So the Actor now takes an optional `sessionToken` input: the user running
the Actor supplies their own Instagram `sessionid` value (or a cookie
string containing `sessionid=...`). It is sent only to instagram.com as a
Cookie for that run, never logged, and never stored in the dataset.
Without it, a followers/following run is expected to stop with
`login_required`. Do not paste a session token in chat or anywhere else
except the Actor's input in Apify Console.

### Follower counts (why they were null, and how they are filled now)

The followers/following list payload Instagram returns carries username,
full name, picture, private/verified flags and user id — but NOT each
profile's own follower count, following count or biography. So the old
default run delivered those three fields as null.

FIX 2026-10-26: profile details are now ON by default. The Actor makes
one small `web_profile_info` request per profile (with your sessionToken),
paced ~0.8s apart, and fills the three fields before pushing the row.
Set `includeProfileDetails: false` only for the fast lightweight run
with null counts. If a detail request fails for a profile, that row
keeps nulls and the run logs how many profiles failed, instead of
failing the whole run.

# Actor input Schema

## `includePosts` (type: `boolean`):

OFF by default. If true, posts are scraped in addition to the list. This is a different, much heavier and more expensive job — do not enable it for a followers-list job.

## `includeProfileDetails` (type: `boolean`):

ON by default (changed 2026-10-26). The Actor makes one extra web_profile_info request per profile (with your sessionToken) to fill followerCount / followingCount / biography, paced ~0.8s apart. Without it those fields are null, because the followers/following list payload does not carry them — a follower actor without follower counts is useless, so this is no longer opt-in. Set false only if you want the fast lightweight rows with null counts. It needs a sessionToken to work, and makes runs slower with a small extra proxy cost.

## `limit` (type: `integer`):

Maximum profiles returned per seed account. Default 200 matches the typical small DM-list use case. Hard range 1–1,000 per seed — this cap is what keeps a run lightweight and cheap.

## `listType` (type: `string`):

Which list to scrape from each seed account.

## `proxyConfiguration` (type: `object`):

Apify Proxy. Residential proxies are recommended for Instagram; datacenter IPs are rate-limited far more often.

## `seeds` (type: `array`):

One or more seed accounts. For each seed, the Actor returns that seed's followers OR following list (see listType). Each entry may be a username (e.g. natgeo) or a full profile URL. Limit applies PER seed.

## `sessionToken` (type: `string`):

Your own Instagram session token (the sessionid cookie value from a logged-in Instagram browser session). REQUIRED in Oct 2026: Instagram returns login_required for followers/following lists without a session, even for public accounts. Paste only the sessionid value, or a cookie string containing sessionid=... — the Actor sends it only to instagram.com as a Cookie for this run, never logs it and never stores it in the dataset. Leave empty only to try logged-out (expected to fail for lists). Do NOT share this token with anyone else; it gives access to your Instagram session.

## Actor input object example

```json
{
  "includePosts": false,
  "includeProfileDetails": true,
  "limit": 200,
  "listType": "followers",
  "proxyConfiguration": {
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "useApifyProxy": true
  },
  "seeds": [
    "natgeo"
  ]
}
```

# Actor output Schema

## `results` (type: `string`):

Profile records from the run.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "includePosts": false,
    "includeProfileDetails": true,
    "limit": 200,
    "listType": "followers",
    "proxyConfiguration": {
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ],
        "useApifyProxy": true
    },
    "seeds": [
        "natgeo"
    ],
    "sessionToken": ""
};

// Run the Actor and wait for it to finish
const run = await client.actor("arisma_tech/instagram-followers-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "includePosts": False,
    "includeProfileDetails": True,
    "limit": 200,
    "listType": "followers",
    "proxyConfiguration": {
        "apifyProxyGroups": ["RESIDENTIAL"],
        "useApifyProxy": True,
    },
    "seeds": ["natgeo"],
    "sessionToken": "",
}

# Run the Actor and wait for it to finish
run = client.actor("arisma_tech/instagram-followers-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "includePosts": false,
  "includeProfileDetails": true,
  "limit": 200,
  "listType": "followers",
  "proxyConfiguration": {
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ],
    "useApifyProxy": true
  },
  "seeds": [
    "natgeo"
  ],
  "sessionToken": ""
}' |
apify call arisma_tech/instagram-followers-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,arisma_tech/instagram-followers-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/g7JeW6X3nNYkiirKn/builds/7Q8VIKb1IqHXrl6QG/openapi.json
