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

Scrape public Instagram profiles and optional posts with exact audience metrics, engagement, media, canonical URLs, and typed exports.

- **URL**: https://apify.com/happy\_b/instagram-profile-scraper.md
- **Developed by:** [Happy B](https://apify.com/happy_b) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.49 / 1,000 results

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

### What is Instagram Profile Scraper?

Instagram Profile Scraper turns public Instagram profiles into clean, typed data for creator research, competitive analysis, monitoring, and reporting. Submit usernames, `@handles`, or profile URLs to collect stable profile IDs, exact audience counts, bios, account classification, canonical URLs, and optional public posts.

Every successful profile is saved as a `profile` row. When **Include posts** is enabled, each public post is saved as a separate `post` row with engagement metrics, media URLs, publication time, and embedded profile context. The Profiles and Posts dataset views make the same records easy to use in Apify Console, API responses, JSON, and CSV.

### What Instagram data can you collect?

Profile rows include:

- Stable Instagram ID and username
- Full name, biography, category, and structured bio links
- Exact follower, following, and media counts
- Verified, private, and business flags
- Account type code and readable account type
- Standard and HD profile-picture URLs
- Canonical profile URL and public external URL
- Input position, dataset position, and scrape timestamp

Optional post rows include:

- Stable post ID, shortcode, and canonical post URL
- Caption and publication time in Unix and ISO 8601 formats
- Likes, comments, plays, and views when available
- Photo or video URL, dimensions, and media type
- Typed carousel slides with their positions, media URLs, and dimensions
- Author identity and the parent profile’s public context
- Input position, post position, dataset position, and scrape timestamp

Numeric zero is kept as `0`. A value that was not available is returned as `null`, so missing information is never confused with an observed zero.

### Use cases

- **Influencer research:** compare exact follower counts, account categories, verification, bios, and public posting activity before shortlisting creators.
- **Competitive monitoring:** schedule repeat runs and compare audience size, profile positioning, and content engagement over time.
- **Creator analytics:** calculate post-level engagement from likes, comments, plays, and views without parsing abbreviated numbers.
- **Lead enrichment:** add public profile URLs, biographies, websites, and structured bio links to an existing CRM or research table.
- **Content audits:** export a profile’s public photos, videos, and carousels for format and performance analysis.
- **Data pipelines:** load stable IDs, canonical URLs, typed values, and timestamps into a warehouse without cleaning undocumented fields.

### Input

| Parameter | Type | Default | Description |
|---|---|---:|---|
| `profileUrls` | string\[] | required | One to 50 Instagram usernames, `@handles`, or profile URLs. Case-insensitive duplicates are removed. |
| `includePosts` | boolean | `false` | Save public posts as additional dataset rows. |
| `maxPostsPerProfile` | integer | `50` | Maximum unique post rows per profile when posts are enabled. Range: 1–5,000. |

Profile URLs must point directly to an Instagram profile. Post, Reel, Story, and hashtag URLs are not profile inputs.

#### Sample input

```json
{
  "profileUrls": [
    "https://www.instagram.com/nasa/",
    "@natgeo"
  ],
  "includePosts": true,
  "maxPostsPerProfile": 25
}
```

### Output

All result rows use a closed, documented schema. Operational request fields, authentication values, and pagination state are not part of the dataset.

#### Schema-valid profile row

```json
{
  "recordType": "profile",
  "position": 1,
  "inputPosition": 1,
  "pk": "528817151",
  "username": "nasa",
  "fullName": "NASA",
  "biography": "Exploring Earth and the universe.",
  "profilePicUrl": "https://images.example/nasa-profile.jpg",
  "hdProfilePicUrl": "https://images.example/nasa-profile-hd.jpg",
  "profileUrl": "https://www.instagram.com/nasa/",
  "externalUrl": "https://www.nasa.gov/",
  "followerCount": 104300000,
  "followingCount": 91,
  "mediaCount": 4849,
  "isVerified": true,
  "isPrivate": false,
  "isBusiness": true,
  "category": "Government organization",
  "accountType": 2,
  "accountTypeName": "business",
  "bioLinks": [
    {
      "title": "NASA",
      "url": "https://www.nasa.gov/",
      "linkType": "external"
    }
  ],
  "scrapeTimestamp": "2026-08-30T12:00:00.000Z"
}
```

#### Schema-valid post row

```json
{
  "recordType": "post",
  "position": 2,
  "inputPosition": 1,
  "postPosition": 1,
  "pk": "3712345678901234567",
  "code": "DNasaExample",
  "postUrl": "https://www.instagram.com/p/DNasaExample/",
  "mediaType": 8,
  "mediaTypeName": "carousel",
  "caption": "A new view of our home planet.",
  "takenAt": 1788091200,
  "takenAtIso": "2026-08-30T12:00:00.000Z",
  "likeCount": 245000,
  "commentCount": 1850,
  "playCount": 0,
  "viewCount": 0,
  "imageUrl": "https://images.example/nasa-post.jpg",
  "videoUrl": null,
  "imageWidth": 1080,
  "imageHeight": 1080,
  "carouselMedia": [
    {
      "position": 1,
      "imageUrl": "https://images.example/nasa-slide-1.jpg",
      "videoUrl": null,
      "mediaType": 1,
      "mediaTypeName": "photo",
      "width": 1080,
      "height": 1080
    }
  ],
  "authorPk": "528817151",
  "authorUsername": "nasa",
  "profilePk": "528817151",
  "profileUsername": "nasa",
  "profileFullName": "NASA",
  "profileBiography": "Exploring Earth and the universe.",
  "profilePicUrl": "https://images.example/nasa-profile.jpg",
  "profileUrl": "https://www.instagram.com/nasa/",
  "profileExternalUrl": "https://www.nasa.gov/",
  "profileFollowerCount": 104300000,
  "profileFollowingCount": 91,
  "profileMediaCount": 4849,
  "profileIsVerified": true,
  "profileIsPrivate": false,
  "profileIsBusiness": true,
  "profileCategory": "Government organization",
  "profileAccountType": 2,
  "profileAccountTypeName": "business",
  "scrapeTimestamp": "2026-08-30T12:00:00.000Z"
}
```

Download the default dataset as JSON, CSV, Excel, XML, or HTML, or read it through the Apify API. The run key-value store also contains `METADATA`, which reports `COMPLETE`, `PARTIAL`, or `FAILED`, delivered row totals, spending-limit state, and customer-safe error summaries.

### Pricing

You pay once when a run starts and once for each successful row delivered to the default dataset. Profile and post rows have the same result price. Unavailable profiles, rejected rows, duplicates, and results that are not stored do not create a result charge.

| Apify tier | Per result | Per 1,000 results |
|---|---:|---:|
| Free | $0.00349 | $3.49 |
| Bronze | $0.00349 | $3.49 |
| Silver | $0.00349 | $3.49 |
| Gold | $0.00349 | $3.49 |
| Platinum | $0.00349 | $3.49 |
| Diamond | $0.00349 | $3.49 |

The Actor Start event is $0.001 per run. There is no minimum total charge and no premium add-on event.

| Example | Approximate event cost |
|---|---:|
| 10 profiles, no posts | $0.0409 |
| 1 profile and 50 posts | $0.2045 |
| 10 profiles and 50 posts each | $2.0359 |

Set `maxPostsPerProfile` and Apify’s maximum total charge to keep exploratory runs bounded.

### Run status and reliability

The Actor saves progress between pages and validates every row before storage. It removes duplicate profiles and overlapping posts deterministically. If a run is interrupted, migrated, or resurrected, it reconciles already stored rows before continuing so the same result is not stored or charged twice.

`METADATA.status` means:

- `COMPLETE`: every requested profile reached a terminal result and no spending boundary stopped the run.
- `PARTIAL`: some data was delivered, but a spending boundary or retryable failure prevented full delivery.
- `FAILED`: no requested data was delivered.

An empty post feed does not erase the profile row. A run never reports success merely because the process exited normally.

### API example

Start a run and return its dataset items with Apify’s synchronous endpoint:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/happy_b~instagram-profile-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "profileUrls": ["nasa", "https://www.instagram.com/natgeo/"],
    "includePosts": false,
    "maxPostsPerProfile": 50
  }'
```

For longer runs, start the Actor asynchronously and retrieve items from the run’s default dataset. See the [Apify API documentation](https://docs.apify.com/api/v2) for JavaScript, Python, and HTTP clients.

### Integrations

Use [Apify integrations](https://docs.apify.com/platform/integrations) to send results to Google Drive, Make, Zapier, Slack, webhooks, or your own data pipeline. Stable string IDs and canonical URLs are suitable for database keys; `scrapeTimestamp` makes repeated runs suitable for change tracking.

### Limitations

- Only information available from public Instagram surfaces at scrape time can be returned.
- Private or unavailable accounts may expose limited profile information and do not expose private posts.
- Instagram can omit engagement or media values; unavailable optional values are `null`.
- Media URLs can expire. Download permitted media promptly if your workflow requires durable files.
- Posts are returned in the order made available during the run; the requested maximum is a ceiling, not a guarantee.
- Stories, comments, follower lists, following lists, and private analytics are not supported.

### Responsible use

Public profile data can still be personal data. Use the Actor only for a lawful purpose, minimize what you retain, honor deletion and access obligations, and comply with applicable privacy laws and Instagram’s terms.

### Related Actor

Use [Instagram Search Scraper](https://apify.com/happy_b/instagram-search-scraper) to discover public users, hashtags, and posts by keyword, then send discovered usernames here for complete profile rows and optional post history.

### Support

If a run behaves unexpectedly, open an issue from the Actor page and include the run ID, a secret-free input example, the expected result, and the observed `METADATA.status`.

# Actor input Schema

## `profileUrls` (type: `array`):

Instagram profile URLs, @handles, or usernames. Duplicates are removed case-insensitively.

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

Also return public posts with engagement stats, media URLs, and embedded profile context. Each stored post is a charged row.

## `maxPostsPerProfile` (type: `integer`):

Maximum number of posts to fetch per profile (only used when Include Posts is on)

## Actor input object example

```json
{
  "profileUrls": [
    "https://www.instagram.com/instagram/"
  ],
  "includePosts": false,
  "maxPostsPerProfile": 50
}
```

# Actor output Schema

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

One profile row per resolved input and optional post rows with embedded profile context.

## `metadata` (type: `string`):

COMPLETE, PARTIAL, or FAILED status, exact counts, spending-limit state, and sanitized errors.

# 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 = {
    "profileUrls": [
        "https://www.instagram.com/instagram/"
    ]
};

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

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

```

## MCP server setup

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