# Instagram Bulk Profile Scraper — Followers & Engagement Rate (`foxlabs/instagram-profile-scraper`) Actor

Instagram profiles in bulk: user names or profile URLs in, one row per profile out — exact follower count, bio, bio links, verified and private flags, highlight titles, post count and engagement rate from the six latest posts. Public data as seen without signing in. No login, no cookies.

- **URL**: https://apify.com/foxlabs/instagram-profile-scraper.md
- **Developed by:** [Berkan Kaplan](https://apify.com/foxlabs) (community)
- **Categories:** Social media, Marketing
- **Stats:** 1 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.20 / 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 Bulk Profile Scraper — Followers & Engagement Rate 🚀

**foXLabs Instagram series:** [Profile Posts](https://apify.com/foxlabs/instagram-profile-posts-scraper) · [Post Details](https://apify.com/foxlabs/instagram-post-details-scraper) · [Comments](https://apify.com/foxlabs/instagram-comments-scraper) · [Reels](https://apify.com/foxlabs/instagram-reels-scraper)

🎉 Give a list of Instagram usernames or profile URLs and get one clean row per profile: exact follower count, bio, bio links, verified/private flags, highlight titles, Threads name and whether a story is up — plus, from the public embed page, the exact post count and the six newest posts, and from those **median likes, median comments, an engagement rate, posts per week and the last-post time**. Optionally the "accounts you might like" list.

**It reads only what a signed-out visitor sees.** No login, no cookies, nothing from your own Instagram account. Not affiliated with Instagram or Meta.

### 🔍 What is the Instagram Bulk Profile Scraper — and when should you use it?

Give this Actor a list of profiles and it returns a firmographic + engagement row for each — built for screening creators and brands by size and engagement, enriching an account list you already have, and watching follower counts run to run.

**Use it when you need:** to rank creators/brands by followers and engagement rate; to enrich a list of handles with bio, links and metrics; or to monitor profiles over time.

**Use something else when:** you need a profile's full post feed → [Profile Posts](https://apify.com/foxlabs/instagram-profile-posts-scraper); one post's details → [Post Details](https://apify.com/foxlabs/instagram-post-details-scraper); a post's comments → [Comments](https://apify.com/foxlabs/instagram-comments-scraper); reels → [Reels](https://apify.com/foxlabs/instagram-reels-scraper).

### 🤖 Use with AI agents

**Already on the Apify MCP server?** Ask for this Actor by name: `foxlabs/instagram-profile-scraper`. An agent can discover it, run it and read the dataset over MCP — and the Actor can run in Standby mode for on-demand single-profile lookups.

Otherwise paste this into Claude, ChatGPT, Cursor or any MCP-enabled assistant:

```
I want Instagram profiles with engagement using the Apify Actor
`foxlabs/instagram-profile-scraper`.

Input: `profiles` is a list of usernames/URLs; `includeRecentPosts` adds post count + six newest
posts + engagement; `includeSimilarAccounts` adds the "you might like" list. Each row has
followers, following, isVerified, biography, engagementRate, medianLikes and postsPerWeek.

Start with:
{ "profiles": ["natgeo", "nasa"] }

Ask me which profiles to screen, run the Actor, then rank them by engagement rate.
```

The machine-readable API, MCP config and OpenAPI definition live at `apify.com/foxlabs/instagram-profile-scraper.md`.

### 📋 Overview

Everything you need to turn Instagram usernames into clean, structured creator data — reach, engagement and bio — in one Actor, with no login, cookies or account.

**Why teams pick this Actor:**

- ✅ **Exact followers + engagement rate** — not an estimate; computed from the six newest posts.
- ⚡ **Bulk** — up to 10,000 profiles a run, read eight at a time.
- 🎯 **Honest** — an unknown value is `null`, never 0; the README's "What it does not do" spells out every limit.
- 🔗 **Bio links & emails** — bio links on 94.7% of profiles; a bio e-mail where the owner wrote one (rare).
- 💰 **Pay only for results** — one `profile` event per delivered row; status rows and unreached lines free.
- 🤖 **Agent-ready** — MCP + Standby for on-demand lookups.

### ✨ Features

- 🔍 **Profiles in bulk** — username, @handle or URL; duplicates read once.
- 👥 **Reach** — exact followers, following, posts count, verified/private flags.
- 📊 **Engagement** — median likes/comments, engagement rate, posts per week, last-post time, six newest posts.
- 🔗 **Bio** — text, links, external URL, hashtags, mentions, Threads name, bio e-mails (`extractBioContacts`).
- 🧩 **Extras** — highlights titles, story status, `includeSimilarAccounts`.

### 🎬 Quick Start

```bash
curl -X POST "https://api.apify.com/v2/acts/foxlabs~instagram-profile-scraper/runs?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"profiles": ["natgeo", "nasa"]}'
```

### 🚀 Getting Started (3 steps)

1. **List your profiles** — one per line: `natgeo`, `@natgeo` or a profile URL.
2. **Pick depth** — keep `includeRecentPosts` on for engagement; add `includeSimilarAccounts` if you want.
3. **Run and export** — get a clean dataset as JSON, CSV or Excel.

### 📥 Input

| Field | Default | What it does |
|---|---|---|
| `profiles` | required | One profile per line: `natgeo`, `@natgeo`, a URL. Up to 10,000; duplicates read once. |
| `includeRecentPosts` | true | Read the embed page: post count, six newest posts, engagement figures (one more request, the slow one). `false` = fast, profile fields only. |
| `includeSimilarAccounts` | false | Add the "accounts you might like" list (username, name, verified of up to 50). |
| `extractBioContacts` | true | List e-mail addresses written in the bio text in `bioEmails`. |
| `maxProfiles` | 100000 | Stop after this many rows. |
| `proxyConfiguration` | auto | Nothing to change for normal use (see "How requests leave"). |

```json
{ "profiles": ["https://www.instagram.com/tartinebakery/", "@onyxcoffeelab"], "includeSimilarAccounts": true }
```

### 📤 Output

One row per profile (`type: "profile"`); a free `type: "status"` row for a line that gave none. An unknown value is `null`, never 0. Fill below from platform run `4s2LqCYNeoReKq810` (150 public profiles).

| Field | What it holds | Filled (n=150) |
|---|---|---|
| `userId`, `graphId`, `username`, `url`, `fullName` | ids and identity | 100% |
| `followers`, `following` | exact counts | 100% |
| `isVerified`, `isPrivate` | flags | 100% |
| `biography`, `bioLinks`, `externalUrl` | bio text and links | 98.7% / 94.7% |
| `bioEmails` | e-mail written in the bio (`extractBioContacts`) | 0.7% |
| `bioHashtags`, `bioMentions`, `threadsUsername` | from the bio; Threads name | 10% / 17.3% / 44% |
| `hasActiveStory`, `lastStoryAt`, `hasReels`, `highlights` | story/reels/highlight titles | 100% known |
| `postsCount`, `recentPosts`, `recentPostsCount` | post count + six newest `{shortCode,url,isVideo,likeCount,commentCount,takenAt,isPaidPartnership,coauthors}` | 98% |
| `medianLikes`, `medianComments`, `engagementRate` | over those posts; rate = (median likes + median comments) ÷ followers | 96.7% |
| `postsPerWeek`, `lastPostAt`, `hasPaidPartnership` | posting rate, last post, paid-partnership flag | 98% |
| `recentPostsStatus` | `ok` / `not-offered` / `unanswered` / `unreadable` / `private` / `off` | 100% |
| `similarAccounts`, `similarAccountsCount` | with `includeSimilarAccounts` | — |
| `inputLine`, `scrapedAt` | the line this row answers; when read | 100% |

**Honest limits (summary; full detail below):** no e-mail/phone/category beyond a bio e-mail; engagement rests on the six newest posts (shared posts counted, `coauthors` names them — recompute without them to screen on own-content); no view counts for videos; a hidden like count stays hidden; nothing from behind the login; an age-restricted/signed-in-only profile gets a free status row.

### 💼 Use cases

**1. Influencer screening** — rank creators by followers and engagement rate, not guesswork.
*Input:* your handles, `includeRecentPosts` on. *Output:* followers + `engagementRate`. *Use:* shortlist by real engagement.

**2. List enrichment** — add profile data to an account list you already have.
*Input:* the handles. *Output:* bio, links, verified, followers. *Use:* fill a CRM.

**3. Follower monitoring** — watch counts run to run (compare runs yourself).
*Input:* the profiles, scheduled. *Output:* a row per run. *Use:* track growth over time.

### 🔗 Integration

**JavaScript / Node.js**

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('foxlabs/instagram-profile-scraper').call({ profiles: ['natgeo', 'nasa'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items[0]);
```

**Python**

```python
from apify_client import ApifyClient
client = ApifyClient('YOUR_TOKEN')
run = client.actor('foxlabs/instagram-profile-scraper').call(run_input={'profiles': ['natgeo', 'nasa']})
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)
```

Written for `apify-client` 3 for Python, where `call()` returns a run object; with version 1 or 2 it returns a dict — write `run['defaultDatasetId']` there.

**Automation (n8n / Zapier / Make):** schedule → HTTP request to the Actor API with your `profiles` → handle the JSON dataset → push to a sheet, CRM or dashboard.

### 📊 Pricing

Pay per event, one event: **`profile`** — one per delivered profile row, public or private, with or without post figures. Status rows are free, and so is every line that gave no row (not a profile, no such account, signed-in-only, a duplicate). [View current pricing.](https://apify.com/foxlabs/instagram-profile-scraper)

### ❓ FAQ

**Do I need an Instagram account, login or cookies?** No. It reads only what a signed-out visitor sees — figures can differ from what a signed-in user sees.

**Is there an engagement rate?** Yes — (median likes + median comments) ÷ followers, from the six newest posts. Shared posts are counted; `coauthors` names them, so you can recompute on own-content only.

**Can I get e-mail or phone?** No — the public profile carries none. The only contact a row can hold is an e-mail the owner wrote into the bio (`bioEmails`), and that's rare (~0.7%).

**Why do some profiles have no post figures?** Instagram's embed page sometimes shows no data (`recentPostsStatus: not-offered`); the row still has its profile fields.

**Can I export to CSV / Excel / JSON?** Yes — directly from the Apify dataset.

### 🐛 Troubleshooting / What it does not do

- **No e-mail/phone/business category** beyond a bio e-mail — the public record carries none.
- **Engagement rests on the six newest posts** as they stood when read; an account that posts many times a day reads low. Shared posts (common, ~33%) count with full numbers — recompute from `recentPosts` without `coauthors` to screen on own content.
- **No view/play counts for videos** — the six posts carry likes and comments only.
- **A hidden like count stays hidden** (`likeCount: null`); a profile whose six newest all hide it has no `engagementRate`.
- **Nothing from behind the login** — a private profile comes as its public header only; no follower lists, stories, highlight contents, tagged posts or search.
- **Signed-in-only / age-restricted profiles** get a free status row.
- **Before anything is read** the Actor checks one known profile's record and embed page; if Instagram changed its public queries or the embed form, the run ends there, uncharged.

### ⚠️ Trademark

Independent, third-party tool. Not affiliated with, endorsed by or connected to Instagram or Meta Platforms, Inc. "Instagram" and related marks belong to their owners and are used here for identification only.

### ⚖️ Is it legal to scrape this data?

Rows hold what an account shows publicly on its profile. A profile can belong to a private person or a minor even when it looks like a business; you are responsible for having a lawful reason to process personal data (GDPR and similar). `bioEmails` is exactly an address the owner wrote into the public bio — nothing hidden is looked up. The Actor writes only to your own run's dataset and key-value store. See Apify's blog post on the legality of web scraping.

### 🤝 Support & contact

- 🌐 **Website:** [data.foxlabs.com.tr](https://data.foxlabs.com.tr)
- 📧 **Email:** info@foxlabs.com.tr
- 🐛 **Issues:** open a ticket in the Actor's **Issues** tab — the run's `SOURCE_REPORT` record says which road was used and why the run stopped.
- 🧰 **More clean data actors:** [Fox Labs on Apify](https://apify.com/foxlabs)

### Changelog

#### 0.1.3 — 2026-10-10

- After an independent README review: `recentPostsStatus` tells `not-offered` from `unreadable`; a run that wants post figures checks one known embed page at start-up; `engagementRate` has four significant digits; a proxy set in the input is the road of every request.

#### 0.1 — 2026-10-09

- First version: profile rows from the public record, post figures from the public embed page, optional similar accounts, free status rows for lines without a profile; requests start ≥80 ms apart; measured on the Apify platform (150/150 profiles, 147 with post figures).

# Changelog

This Actor's version history is a separate document: https://apify.com/foxlabs/instagram-profile-scraper/changelog.md

# Actor input Schema

## `profiles` (type: `array`):

One profile per line: a user name (natgeo), an @name (@natgeo) or a profile address (https://www.instagram.com/natgeo/). Capital letters and addresses with a query string are read as well. Every line the run reads is answered: by a profile row, or by a free status row that says why there is none. Lines the run does not reach — after Maximum profiles, the spending limit, or when Instagram stops answering — get no row; the status message says how many. A line repeated letter for letter is read once. An input with no usable line ends the run as failed, with the reason.

## `includeRecentPosts` (type: `boolean`):

Also read the profile's public embed page: the exact post count and the six newest posts with their like and comment counts. From those the row gets median likes, median comments, engagement rate, posts per week and the time of the last post. This is one more request per profile, and the slow one (a few seconds). Turn it off for a fast run that delivers the profile fields only.

## `includeSimilarAccounts` (type: `boolean`):

Add the "accounts you might like" list Instagram shows next to the profile: user name, name and verified flag of up to 50 accounts, without follower counts. One more request per profile. Instagram gives a long list for large accounts and a short or empty one for many small accounts.

## `extractBioContacts` (type: `boolean`):

When the account owner wrote an e-mail address into the public bio text, list it in the column bioEmails. Nothing hidden is looked up and nothing is added from other sources. Turned off, bioEmails stays empty (null).

## `maxProfiles` (type: `integer`):

The run stops after this many profile rows. The default (100,000) is above most lists; raise it for a longer one (up to 1,000,000). With a small limit the run also stops once it has read 50 lines for every row wanted (at least 300 lines) without getting them. You are charged only for delivered rows, and status rows are free.

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

Nothing to change for normal use: requests leave from the run's own address, and the Actor moves to Apify Proxy by itself if Instagram turns that address away. Turn a proxy on here to send every request through it: the run then stays on that proxy, and a setting the platform refuses ends the run with a message before anything is read.

## Actor input object example

```json
{
  "profiles": [
    "natgeo",
    "nasa"
  ],
  "includeRecentPosts": true,
  "includeSimilarAccounts": false,
  "extractBioContacts": true,
  "maxProfiles": 100000,
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

# Actor output Schema

## `dataset` (type: `string`):

No description

# 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 = {
    "profiles": [
        "natgeo",
        "nasa"
    ],
    "proxyConfiguration": {
        "useApifyProxy": false
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("foxlabs/instagram-profile-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 = {
    "profiles": [
        "natgeo",
        "nasa",
    ],
    "proxyConfiguration": { "useApifyProxy": False },
}

# Run the Actor and wait for it to finish
run = client.actor("foxlabs/instagram-profile-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 '{
  "profiles": [
    "natgeo",
    "nasa"
  ],
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}' |
apify call foxlabs/instagram-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,foxlabs/instagram-profile-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/36ZCFWhIaxcsCejH3/builds/UOdNiYj6VVLYXTUyq/openapi.json
