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

Instagram profile scraper: export followers, bio, email in bio, links, category, latest 12 posts with likes and comments, engagement rate and related profiles. No login or cookies.

- **URL**: https://apify.com/keklik/instagram-profile-scraper.md
- **Developed by:** [Keklik Technologies](https://apify.com/keklik) (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.70 / 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.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

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** lets you **scrape public Instagram profiles** and export the data to JSON, CSV or Excel: **followers, following, bio, email in bio, bio links, category, verified and business flags, the 12 latest posts with likes and comments, engagement rate and related profiles**. Paste a few usernames or profile URLs, press Start, and get **one row per profile**. **No Instagram account, no login and no cookies** are needed.

### What data can you extract from Instagram?

Each profile becomes one row with 63 fields:

| Group | Fields |
|---|---|
| **Identity** | Profile URL, username, full name, bio, profile picture, Instagram ID |
| **Counters** | Followers, following, posts, story highlights, long videos |
| **Flags** | Private, verified, business account, professional account, joined recently, has reels, has guides, has a channel |
| **Business details** | Category (for example "Government Agencies"), preferred contact method (for example "CALL"), business address |
| **Email** | An email address the account wrote in its bio |
| **Bio links** | Every link in the bio, with its title |
| **Latest 12 posts** | URL, type, caption, likes, comments, video views, date, image URL, location, tagged users, audio |
| **Latest 12 long videos** | URL, title, caption, duration, views, likes, comments, date, thumbnail |
| **Related profiles** | Up to about 50 profiles Instagram suggests as similar |
| **Derived** | Average engagement rate, hashtags used in the bio and in the latest posts |

### Use cases

- **Influencer marketing**: vet creators by followers, engagement rate, category and recent posts before you reach out.
- **Lead generation**: build lists of business accounts with their category, bio email, address and website links.
- **Competitor tracking**: run the same list on a schedule and watch follower growth and posting activity over time.
- **Market research**: use Discovery mode to map the accounts around a brand or niche through Instagram's related profiles.
- **Academic and social research**: collect public profile metrics for a set of accounts in a clean table.

### How to scrape Instagram profiles

1. Open **Instagram Profile Scraper** on Apify and click **Try for free**.
2. In **Profiles**, paste Instagram usernames or profile URLs, one per line.
3. Turn on **Discovery mode** if you also want the related profiles Instagram suggests, and set **Max results** to cap the run.
4. Click **Start** and wait for the run to finish. A list of 100 profiles usually takes a couple of minutes.
5. Open the **Output** tab and download the results as JSON, CSV, Excel, XML or HTML, or fetch them with the Apify API.

### Input

| Field | What it does |
|---|---|
| **Profiles** | Profile URLs or usernames, one per line. `https://www.instagram.com/nasa/`, `@nasa` and `nasa` all work. Post, reel and hashtag links are skipped. |
| **Discovery mode** | Also scrapes the related profiles Instagram suggests for each profile in your list, one level deep. Each discovered row names the profile it came from. Off by default. |
| **Max results** | Stops the run after this many profiles. Leave it empty for no limit. Use it to cap Discovery mode. |

```json
{
    "usernames": ["https://www.instagram.com/nasa/", "@natgeo", "starbucks"],
    "discoveryMode": false,
    "maxResults": 10
}
```

### Output

A shortened row from a real run (the full row has 63 fields):

```json
{
    "profile_url": "https://www.instagram.com/nasa/",
    "username": "nasa",
    "full_name": "NASA",
    "biography": "Making the seemingly impossible, possible. ✨",
    "followers_count": 104346308,
    "follows_count": 90,
    "posts_count": 4963,
    "highlight_reel_count": 6,
    "is_verified": true,
    "is_business_account": true,
    "category": "Government Agencies",
    "business_contact_method": "CALL",
    "email_address": null,
    "external_url_1": {
        "title": "NASA.gov Homepage",
        "url": "https://www.nasa.gov",
        "link_type": "external"
    },
    "avg_engagement": 0.003153,
    "post_hashtags": ["NASA", "Space", "Stars", "Hubble", "Galaxy"],
    "latest_post_1": {
        "url": "https://www.instagram.com/p/DeJ28eTxo4s/",
        "type": "GraphImage",
        "caption": "Brewing up new stars 🪄 @NASAWebb’s unique view of the stellar nursery …",
        "likes": 235535,
        "comments": 719,
        "posted_at": 1791292211
    },
    "related_profiles": [
        {
            "username": "sciencechannel",
            "full_name": "Science Channel",
            "is_verified": true
        }
    ],
    "discovered_from": null,
    "hop_depth": 0,
    "source": "api",
    "scraping_time": "2026-10-13T12:33:42+00:00"
}
```

A few fields worth knowing:

- **`avg_engagement`** is the average of likes plus comments on the latest posts, divided by followers. `0.003153` means 0.32%.
- **`posted_at`** is a Unix timestamp in seconds.
- **`latest_post_N.type`** is `GraphImage` for a photo, `GraphVideo` for a video and `GraphSidecar` for a carousel.
- **`discovered_from`** and **`hop_depth`** tell your own profiles (hop 0) apart from the ones Discovery mode found (hop 1).

The **Output** tab has two ready-made views: **Overview** and **Contacts and links**. You can export the dataset to **JSON, CSV, Excel, XML and HTML**.

#### Full rows and partial rows

Every row has a **`source`** field:

- **`api`**: a full row with every field above.
- **`fallback`**: a partial row. For some accounts, most of them businesses, Instagram shows logged-out visitors only part of the profile. In our tests about 4 profiles in 10 came back this way. These rows still have the identity, exact follower and following counts, bio, links, highlights and the 12 latest posts. They do **not** have the category, contact method, business address, long videos or related profiles, and **`posts_count` is rounded** (32000 for "32K"). The joined recently, has a channel and has guides flags are empty, meaning unknown, and so are the business and professional flags when the account has no visible posts.

Discovery mode cannot expand from a partial row, because it has no related profiles.

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

Instagram Profile Scraper uses **pay-per-event pricing**: you pay only for the profiles you get.

- **$1.00 per 1,000 profiles** on the Apify Free plan.&#x20;
- Bronze, Silver and Gold Apify plans pay less: $0.90, $0.80 and $0.70 per 1,000 profiles.&#x20;
- Each profile found by Discovery mode is a result like any other, so set **Max results** to keep costs predictable.
- Profiles that fail are not results, so you are not charged for them.

The Apify Free plan's monthly credits let you try the scraper before you pay.

### Integrations and API

You can run Instagram Profile Scraper from your own code with the **Apify API**. Here is how to scrape a few profiles with the `apify-client` package.

**Python**

```python
from apify_client import ApifyClient

client = ApifyClient("<YOUR_APIFY_TOKEN>")
run = client.actor("keklik/instagram-profile-scraper").call(
    run_input={"usernames": ["nasa", "natgeo"], "maxResults": 10}
)
for profile in client.dataset(run["defaultDatasetId"]).iterate_items():
    print(profile["username"], profile["followers_count"])
```

**Node.js**

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

const client = new ApifyClient({ token: '<YOUR_APIFY_TOKEN>' });
const run = await client.actor('keklik/instagram-profile-scraper').call({
    usernames: ['nasa', 'natgeo'],
    maxResults: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.map((p) => [p.username, p.followers_count]));
```

You can also:

- **Schedule** runs to track follower counts and posting activity daily or weekly.
- Use **webhooks** to get notified, or trigger your own pipeline, when a run finishes.
- Connect the results to **Make, Zapier, Google Sheets**, Airbyte and other tools through Apify integrations.
- Give AI agents access through the **Apify MCP server**, so Claude, ChatGPT or Cursor can look up Instagram profiles for you.

### FAQ

#### Is it legal to scrape Instagram profiles?

This scraper collects only data that Instagram shows publicly to visitors who are not logged in. Profiles can still contain personal data, which laws such as the GDPR and CCPA protect. Make sure you have a lawful reason to collect and use it, and don't scrape private information. If you are unsure, ask a lawyer.

#### Do I need an Instagram account?

No. You don't need an Instagram account, a login or cookies, and the scraper never uses yours.

#### Can I scrape private Instagram profiles?

Private profiles are returned with their counters, bio and flags, but without posts, because Instagram does not show their posts to visitors.

#### Can I get a business account's email and phone number?

Instagram does not show a business account's contact email or phone number to logged-out visitors, even when the account has set a public contact method such as Call. The `business_email` and `business_phone_number` fields exist but come back empty. What you can get instead:

- **`email_address`**: an email the account typed into its bio. In our tests fewer than 1 profile in 10 had one.
- **Bio links** (`external_url_1` and `all_external_urls`): most business profiles link to a website, where contact details usually are. Feed those links to a contact details scraper to collect emails and phone numbers.
- **`business_address`** and **`category`**: on full rows, when the account has set them.

#### Why did some profiles fail?

Profiles that fail are not in the dataset. They are listed, with the reason, in the **`FAILED`** record of the run's key-value store (open the run, then **Storage**, then **Key-value store**):

- **`invalid_input`**: not a profile URL or username, for example a post link.
- **`not_found`**: the profile does not exist, was removed, or can only be seen when logged in (age-restricted and some country-restricted profiles).
- **`blocked`**: Instagram refused the profile every time. Run it again later. A few profiles are refused every time, which means Instagram does not show them to logged-out visitors.

#### Why are some fields empty?

Partial rows (`source` is `fallback`) don't have the category, contact method, business address, long videos or related profiles. See [Full rows and partial rows](#full-rows-and-partial-rows). Small accounts often have no related profiles even on full rows.

#### Do the image and video links last?

No. Instagram image and video links expire after a while. Download the media soon after the run if you need it.

#### Do I need to set up proxies?

No. There is nothing to configure.

### Related scrapers

- [Instagram Post Scraper](https://apify.com/keklik/instagram-post-scraper): go past the 12 latest posts and get as many posts per profile as you need, with carousel slides, co-authors and music.
- [Instagram Reels Scraper](https://apify.com/keklik/instagram-reels-scraper): export a profile's reels with plays, likes, comments and music.
- [Instagram Comments Scraper](https://apify.com/keklik/instagram-comments-scraper): collect the comments on the posts and reels you found here.

### Support

Found a bug or missing a field? Open an issue in the **Issues** tab and we'll look at it. Need a custom Instagram scraper or data in a different format? Contact us through Apify and we'll build it for you.

# Actor input Schema

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

Instagram profiles to scrape, one per line. A profile URL (https://www.instagram.com/leomessi/), @leomessi and leomessi all work. Post, reel and hashtag links are not profiles and are skipped.

## `discoveryMode` (type: `boolean`):

Also scrape the related profiles Instagram suggests for each profile in your list, one level deep. Each discovered row says which of your profiles it came from. Every discovered profile counts as a result, so set Max results to keep the run small.

## `maxResults` (type: `integer`):

Stop the run after this many profiles. Leave it empty for no limit. Most useful with Discovery mode, or to test a long list on a few profiles first.

## Actor input object example

```json
{
  "usernames": [
    "https://www.instagram.com/leomessi/"
  ],
  "discoveryMode": false,
  "maxResults": 50
}
```

# Actor output Schema

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

Dataset with one row per profile: counters, bio, links, category, latest posts and related profiles.

# 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": [
        "https://www.instagram.com/leomessi/"
    ],
    "maxResults": 50
};

// Run the Actor and wait for it to finish
const run = await client.actor("keklik/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": ["https://www.instagram.com/leomessi/"],
    "maxResults": 50,
}

# Run the Actor and wait for it to finish
run = client.actor("keklik/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": [
    "https://www.instagram.com/leomessi/"
  ],
  "maxResults": 50
}' |
apify call keklik/instagram-profile-scraper --silent --output-dataset

```

## MCP server setup

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