# Instagram Profile Scraper (`dtrungtin/instagram-profile-scraper`) Actor

Extracts public profile data from [Instagram](https://www.instagram.com) by username — including follower and following counts, biography, external links, business contact details, verification status, and the latest posts.

- **URL**: https://apify.com/dtrungtin/instagram-profile-scraper.md
- **Developed by:** [Tin](https://apify.com/dtrungtin) (community)
- **Categories:** Lead generation, Social media
- **Stats:** 45 total users, 9 monthly users, 80.7% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.05 / actor start

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 Profile Scraper

**Instagram Profile Scraper** extracts public profile data from [Instagram](https://www.instagram.com) by username — including **follower and following counts, biography, external links, business contact details, verification status, and the latest posts** with their engagement metrics. Just provide one or more usernames and get clean, structured JSON back. It scrapes publicly viewable profiles with no setup, and can optionally use a logged-in session to reach login-gated accounts. Try it now with the default example username, no setup required.

Running on the [Apify platform](https://apify.com), this scraper gives you API access, scheduled runs, integrations (Make, Zapier, Google Drive, Slack, and more), automatic proxy rotation, and run monitoring out of the box.

### Why use Instagram Profile Scraper?

Instagram profiles hold valuable public data for marketing, research, and competitive analysis. This Actor turns that data into a structured dataset you can analyze or pipe into your own tools. Common use cases include:

- **Influencer marketing** — vet creators by follower counts, engagement on recent posts, verification, and business category before partnering.
- **Competitor monitoring** — track follower growth and posting activity of competing brands over time with scheduled runs.
- **Lead generation** — collect public business emails, phone numbers, and external links from professional accounts.
- **Audience and market research** — gather profile metadata across a list of accounts for analysis.
- **Social media management** — keep a refreshed snapshot of the profiles you manage or watch.

### How to use Instagram Profile Scraper

1. Click **Try for free** (or open the Actor in Apify Console).
2. In the **Input** tab, add the Instagram **usernames** you want to scrape (without the `@` symbol). You can paste a full profile URL too — the Actor extracts the username automatically.
3. (Optional) Paste your Instagram **cookies** (or just a **sessionid**) to unlock login-gated profiles (see [Scraping login-gated accounts](#scraping-login-gated-accounts) below). Leave both empty to scrape only publicly viewable profiles.
4. Click **Start** and wait for the run to finish.
5. Open the **Output** tab to preview results, or download the dataset as JSON, CSV, Excel, or HTML — or fetch it via the [Apify API](https://docs.apify.com/api/v2).

### Input

The Actor accepts the following input parameters, configurable through the visual editor in Apify Console or as a JSON object via the API.

| Field | Type | Description |
| --- | --- | --- |
| `usernames` | array | **Required.** List of Instagram usernames to scrape, without the `@` symbol (e.g. `zoebrownstone`). Full profile URLs are also accepted and normalized. |
| `sessionid` | string (secret) | **Optional.** The `sessionid` cookie from a logged-in instagram.com browser session. Used **only as a fallback** for login-gated accounts that Instagram hides from logged-out visitors. Public profiles never use it. See [Scraping login-gated accounts](#scraping-login-gated-accounts). |
| `cookies` | string (secret) | **Optional, recommended over a bare `sessionid`.** The full cookie set exported from the same logged-in browser session — either a JSON export (e.g. from the Cookie-Editor extension) or a raw `name=value; name2=value2` Cookie header. Including `mid`, `ig_did`, `datr`, `rur`, and `csrftoken` alongside `sessionid` makes the authenticated session look like the browser it came from, which greatly reduces rate-limit blocks. |

#### Input example

```json
{
    "usernames": ["zoebrownstone", "natgeo"]
}
```

### Output

Each scraped profile is stored as one item in the dataset. You can download the dataset in various formats such as JSON, HTML, CSV, or Excel.

#### Output example

```json
{
    "scrapeSucceeded": true,
    "username": "zoebrownstone",
    "fullName": "Zoe Brownstone",
    "userId": "1234567890",
    "biography": "Photographer & traveler 📷\nLA based",
    "bioLinks": [{ "title": "", "url": "https://example.com" }],
    "externalUrl": "https://example.com",
    "followersCount": 15234,
    "followingCount": 412,
    "mediaCount": 387,
    "highlightReelCount": 5,
    "isPrivate": false,
    "isVerified": false,
    "isBusinessAccount": true,
    "isProfessionalAccount": true,
    "categoryName": "Photographer",
    "businessCategoryName": "Creators & Celebrities",
    "businessEmail": "hello@example.com",
    "businessPhoneNumber": null,
    "profilePicUrl": "https://instagram.com/.../profile.jpg",
    "profilePicUrlHd": "https://instagram.com/.../profile_hd.jpg",
    "profileUrl": "https://www.instagram.com/zoebrownstone/",
    "hasClips": true,
    "latestMedia": [
        {
            "id": "3210000000000000000",
            "shortcode": "C1aBcDeFgHi",
            "type": "GraphImage",
            "isVideo": false,
            "takenAt": "2026-05-20T14:32:11.000Z",
            "caption": "Golden hour 🌅",
            "likeCount": 842,
            "commentCount": 37,
            "displayUrl": "https://instagram.com/.../image.jpg",
            "thumbnailSrc": "https://instagram.com/.../thumb.jpg",
            "postUrl": "https://www.instagram.com/p/C1aBcDeFgHi/"
        }
    ],
    "scrapedAt": "2026-05-30T09:15:00.000Z"
}
```

Usernames that could not be scraped are also written to the dataset (so nothing fails silently), with `scrapeSucceeded: false` and a reason:

```json
{
    "username": "someprivatehandle",
    "scrapeSucceeded": false,
    "error": "login_required",
    "scrapedAt": "2026-05-30T09:15:00.000Z"
}
```

Possible `error` values: `login_required` (account hidden from logged-out visitors — supply a `sessionid` to scrape it), `not_found` (username does not exist), or `http_<status>` for other rejections.

#### Data fields

| Field | Description |
| --- | --- |
| `scrapeSucceeded` | `true` for a successfully scraped profile; `false` on a failure record (see `error`). |
| `username` | Account handle. |
| `fullName` | Display name on the profile. |
| `userId` | Internal Instagram user ID. |
| `biography` | Profile bio text. |
| `bioLinks` | Array of links shown in the bio. |
| `externalUrl` | Primary external website link. |
| `followersCount` | Number of followers. |
| `followingCount` | Number of accounts followed. |
| `mediaCount` | Total number of posts. |
| `highlightReelCount` | Number of story highlight reels. |
| `isPrivate` | Whether the account is private. |
| `isVerified` | Whether the account is verified (blue badge). |
| `isBusinessAccount` | Whether it is a business account. |
| `isProfessionalAccount` | Whether it is a professional account. |
| `categoryName` / `businessCategoryName` | Profile category labels. |
| `businessEmail` / `businessPhoneNumber` | Public business contact details, when available. |
| `profilePicUrl` / `profilePicUrlHd` | Profile picture URLs (standard and HD). |
| `profileUrl` | Full URL to the profile. |
| `hasClips` | Whether the account has Reels. |
| `latestMedia` | Array of the most recent posts with shortcode, type, caption, like/comment counts, media URLs, timestamp, and post URL. |
| `scrapedAt` | ISO timestamp when the profile was scraped. |

> **Note:** Private accounts return profile metadata (followers, bio, etc.) but not post details, since posts are not publicly available.

### How much does it cost to scrape Instagram profiles?

Cost depends on the number of profiles and the platform compute resources used. Because each profile requires a headless browser to load and capture Instagram's profile API response, scraping is metered in Apify [compute units](https://docs.apify.com/platform/actors/running/compute-units). Small batches of a few profiles typically cost a fraction of a compute unit. New Apify accounts include free monthly platform credits, so you can test the Actor at no cost. To estimate your own cost, run a small batch first and check the **compute units** reported on the run's overview.

### Tips and advanced options

- **Batch usernames.** Pass many usernames in a single run to amortize startup cost rather than running the Actor once per profile.
- **Schedule recurring runs.** Use Apify [Schedules](https://docs.apify.com/platform/schedules) to refresh profile snapshots daily or weekly and track changes over time.
- **Deduplication is automatic.** The Actor lowercases, validates, and de-duplicates usernames, and skips invalid entries (logged as warnings).

#### Scraping login-gated accounts

Instagram serves some profiles (age-restricted, sensitive, or otherwise hidden from logged-out visitors) only to authenticated sessions. For these, the anonymous request returns no data and the Actor records `error: "login_required"`.

To scrape them, provide the browser's cookies. The best option is the **`cookies`** field:

1. Log in to [instagram.com](https://www.instagram.com) in a browser.
2. Export the site's cookies as JSON (e.g. with the [Cookie-Editor](https://cookie-editor.com/) extension: **Export → JSON**), or copy them from DevTools → **Application/Storage → Cookies → `https://www.instagram.com`**.
3. Paste the export into the Actor's `cookies` input field. A raw `name=value; name2=value2` Cookie header works too.

Alternatively, paste just the **`sessionid`** cookie value into the `sessionid` field. This works, but a bare session with none of its companion cookies (`mid`, `ig_did`, `datr`, `rur`, `csrftoken`) is easier for Instagram to flag and rate-limit, so prefer the full export.

The Actor scrapes **anonymously by default** and only uses this session as a fallback for gated profiles — public profiles never touch it, minimizing exposure of the account. Authenticated requests go through a single sticky IP and back off automatically if Instagram rate-limits the session, protecting the account from escalating blocks.

> **Use a throwaway account, not your main one.** Automated use of a session can get the associated account rate-limited, flagged, or blocked by Instagram. Treat the `sessionid` as a secret credential — anyone holding it can act as that logged-in account.

### FAQ, disclaimers, and support

**Is it legal to scrape Instagram?**
This Actor only collects **publicly available** data from Instagram profiles. Scraping public data is generally legal, but how you use the data is your responsibility. Do not collect or process personal data in violation of applicable laws (such as GDPR or CCPA) or Instagram's Terms of Service. Consult legal counsel if you are unsure. This tool is intended for legitimate research, marketing, and analytics purposes.

**Why are some fields empty?**
Fields like `businessEmail`, `businessPhoneNumber`, or `externalUrl` are only present when the account publishes them. Private accounts will not return post-level data.

**A profile failed to scrape — why?**
Check the failure record's `error` field in the dataset. `login_required` means the account is hidden from logged-out visitors — provide cookies to scrape it (see [Scraping login-gated accounts](#scraping-login-gated-accounts)). `not_found` means the username does not exist. An `http_*` value usually indicates temporary rate-limiting — smaller batches reduce this. `auth_http_401`, `auth_http_429`, and `auth_rate_limited` mean Instagram rate-limited the supplied logged-in session — wait a while, then re-run the failed usernames (a full cookie export instead of a bare `sessionid` makes these blocks much rarer). Every attempted username is recorded in the dataset, so nothing fails silently.

**Support and feedback.**
Found a bug or have a feature request? Open an issue in the **Issues** tab of this Actor. Custom scraping solutions are also available on request.

# Actor input Schema

## `usernames` (type: `array`):

List of Instagram usernames to scrape (without the @ symbol).

## `sessionid` (type: `string`):

Optional. The `sessionid` cookie value from a logged-in instagram.com browser session. Required to scrape login-gated accounts (age-restricted / sensitive / accounts Instagram hides from logged-out visitors). Leave empty to scrape only publicly viewable profiles. For fewer rate-limit blocks, prefer the **Instagram cookies** field below.

## `cookies` (type: `string`):

Optional, recommended over a bare sessionid. The full cookie set exported from the same logged-in instagram.com browser session — paste either a JSON export (e.g. from the Cookie-Editor extension: Export → JSON) or a raw `name=value; name2=value2` Cookie header. Including `mid`, `ig_did`, `datr`, `rur`, and `csrftoken` alongside `sessionid` makes the authenticated session look like the browser it came from, which greatly reduces 429 blocks.

## Actor input object example

```json
{
  "usernames": [
    "zoebrownstone"
  ]
}
```

# 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 = {
    "usernames": [
        "zoebrownstone"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("dtrungtin/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 = { "usernames": ["zoebrownstone"] }

# Run the Actor and wait for it to finish
run = client.actor("dtrungtin/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 '{
  "usernames": [
    "zoebrownstone"
  ]
}' |
apify call dtrungtin/instagram-profile-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,dtrungtin/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/3GPUylw9oFNCnhnID/builds/fInZX61MBBjilJynk/openapi.json
