# Instagram Profile Posts Scraper (`automation-lab/instagram-profile-posts-scraper`) Actor

Collect typed public Instagram profile posts for creator, campaign, and competitor monitoring.

- **URL**: https://apify.com/automation-lab/instagram-profile-posts-scraper.md
- **Developed by:** [Stas Persiianenko](https://apify.com/automation-lab) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 80.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

Pay per event

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/platform/actors/running/actors-in-store#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

## Instagram Profile Posts Scraper

Collect typed public Instagram profile posts for creator research, campaign tracking, competitor monitoring, and data exports.

The Actor accepts usernames or public profile URLs and returns one dataset row per post.
Each row includes the shortcode, canonical URL, caption, timestamp, media metadata, author fields, visible engagement, hashtags, mentions, location, and carousel children.

It uses lightweight public Instagram data endpoints rather than downloading media or running a browser.
No Instagram login is required for supported public profiles.

### What can you do with this Instagram scraper?

- Export recent posts from known public profiles.
- Compare creator or competitor publishing activity across scheduled runs.
- Send post records to Google Sheets, a warehouse, or a reporting pipeline.
- Find captions, hashtags, mentions, and tagged locations for campaign analysis.
- Track visible likes, comments, views, and plays when Instagram exposes them.
- Preserve stable post IDs and shortcodes for deduplication between runs.

The Actor collects public profile posts only.
It does not scrape private profiles, log into Instagram, post content, download media files, or monitor comments.

### Who is this Actor for?

**Creator marketing teams** can export posts from a campaign roster and join them with internal campaign data.

**Competitive intelligence teams** can schedule the same input and compare stable post IDs to identify new posts.

**Social media analysts** can study captions, hashtags, mentions, media types, and visible engagement.

**Data engineers** can use typed JSON rows through the Apify API, SDK clients, webhooks, and integrations.

**Agencies** can collect the same fields across multiple public client or competitor profiles.

### Why use this Instagram profile posts scraper?

- Username and profile-URL inputs are normalized into one workflow.
- Pagination supports up to 500 accepted posts per profile.
- A date cutoff stops older-page collection early.
- Post IDs are deduplicated within each profile run.
- Partial profile failures are never hidden behind a successful empty run.
- Apify Proxy is enabled by default to avoid Instagram rate limits on shared direct IPs.
- The default datacenter proxy keeps a coherent session per profile; direct HTTP remains an explicit opt-out.
- Paid residential proxy traffic is never enabled silently.
- The default dataset is ready for JSON, CSV, Excel, XML, and integrations.

### What Instagram post data is extracted?

| Field | Meaning |
| --- | --- |
| `postId` | Stable Instagram post identifier |
| `shortcode` | Short code used in the public URL |
| `url` | Canonical post or reel URL |
| `type` | `image`, `video`, or `carousel` |
| `caption` | Visible post caption, when available |
| `timestamp` | Publication time in ISO 8601 format |
| `likesCount` | Visible likes, when available |
| `commentsCount` | Visible comments, when available |
| `videoViewCount` | Visible video views, when available |
| `videoPlayCount` | Visible video plays, when available |
| `displayUrl` | Primary image or thumbnail URL |
| `videoUrl` | Primary video URL, when exposed |
| `width`, `height` | Primary media dimensions |
| `accessibilityCaption` | Instagram accessibility text, when present |
| `hashtags` | Lower-cased hashtags parsed from the caption |
| `mentions` | Lower-cased account mentions parsed from the caption |
| `authorId` | Instagram author identifier |
| `authorUsername` | Author username |
| `authorFullName` | Author display name, when available |
| `authorProfileUrl` | Canonical public author profile URL |
| `authorIsVerified` | Visible verification status, when available |
| `locationName` | Tagged location name, when available |
| `childMedia` | Ordered image/video metadata for carousel children |
| `sourceProfileUrl` | Requested profile that produced the row |
| `scrapedAt` | Collection time in ISO 8601 format |

Instagram can hide individual engagement, author, media, or location fields.
Such fields are returned as `null` rather than guessed.

### How to scrape public Instagram profile posts

1. Open the Actor input page.
2. Add one or more usernames, such as `instagram` or `nasa`.
3. Alternatively, paste public profile URLs under **Instagram profile URLs**.
4. Choose the maximum number of posts per profile.
5. Optionally add an ISO 8601 date cutoff for recurring monitoring.
6. Keep the default Apify Proxy setting, or explicitly disable it only when your direct connection is known to work.
7. Run the Actor.
8. Open the **Instagram posts** dataset view.
9. Export results or connect an integration.

The prefilled input is intentionally small enough for a quick first run.

### Input parameters

#### `usernames`

An array of up to 50 public Instagram usernames.
The leading `@` is optional.
Values are lower-cased and deduplicated.

#### `startUrls`

An array of up to 50 public Instagram profile URLs.
Post, reel, story, explore, and account-management URLs are rejected as profile inputs.

#### `maxPostsPerProfile`

An integer from 1 to 500.
The limit applies independently to every requested profile.
The Actor stops scheduling additional feed pages after reaching the limit.

#### `onlyPostsNewerThan`

An optional ISO 8601 timestamp, for example:

```text
2026-01-01T00:00:00Z
```

When the first older post is reached, pagination for that profile stops.
A future cutoff can legitimately match no rows; the run then fails with a clear no-results message.

#### `proxyConfiguration`

Apify Proxy is enabled by default because Instagram commonly rate-limits shared direct IPs.
You can disable it when your direct connection is known to work, or select a country or proxy group when needed.
A configured proxy keeps one session identity for all requests belonging to a profile and rotates that identity after a temporary block.
Use a datacenter proxy before considering residential traffic.
If you choose residential, select a geography appropriate for your use case and account for proxy transfer cost.

### Example input

```json
{
  "usernames": ["nasa", "nike"],
  "maxPostsPerProfile": 15,
  "onlyPostsNewerThan": "2026-01-01T00:00:00Z",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

This input is suitable for a scheduled creator-and-competitor comparison.
Compare `postId` or `shortcode` against the prior dataset to identify new rows.

### Example output

```json
{
  "postId": "3953742040000000000",
  "shortcode": "Dbd3EBdnW_u",
  "url": "https://www.instagram.com/p/Dbd3EBdnW_u/",
  "type": "image",
  "caption": "A public post caption...",
  "timestamp": "2026-07-31T18:01:36.000Z",
  "likesCount": 587558,
  "commentsCount": 1195,
  "videoViewCount": null,
  "videoPlayCount": null,
  "displayUrl": "https://scontent.example-cdn.net/image.jpg",
  "videoUrl": null,
  "width": 1080,
  "height": 1350,
  "accessibilityCaption": "A spacecraft image against a dark background.",
  "hashtags": [],
  "mentions": [],
  "authorId": "528817151",
  "authorUsername": "nasa",
  "authorFullName": null,
  "authorProfileUrl": "https://www.instagram.com/nasa/",
  "authorIsVerified": null,
  "locationName": null,
  "childMedia": [],
  "sourceProfileUrl": "https://www.instagram.com/nasa/",
  "scrapedAt": "2026-08-02T05:10:00.000Z"
}
```

CDN URLs can be temporary.
Persist the dataset fields you need, and do not assume media URLs remain downloadable indefinitely.

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

The Actor uses pay-per-event pricing:

- one `start` event per run;
- one `post` event for every accepted dataset row.

The one-time start price is $0.00005 per run.
The BRONZE `post` price is $0.000472 per accepted post, with lower prices on higher Apify tiers.

At BRONZE pricing:

| Accepted posts | Estimated Actor event price |
| ---: | ---: |
| 10 | 10 × $0.000472 + $0.00005 start |
| 100 | 100 × $0.000472 + $0.00005 start |
| 1,000 | 1,000 × $0.000472 + $0.00005 start |

The final charge shown by Apify uses your subscription tier.
Optional proxy traffic, especially residential traffic, affects the developer infrastructure cost but does not create a separate customer charge event.
Failed, duplicate, filtered-out, and malformed records do not emit a `post` event.

### Scheduling profile-post monitoring

Create an Apify Schedule with the same set of profiles and a practical date cutoff.
Each run produces a new default dataset.
Use stable `postId` values to compare the latest dataset with the previous one.

A simple monitoring workflow is:

1. Run daily or weekly.
2. Export the latest rows.
3. Join on `postId`.
4. Treat unseen IDs as new posts.
5. Compare visible engagement snapshots only when the field is non-null.
6. Send new rows to Slack, email, a webhook, or your warehouse.

The Actor does not maintain cross-run state or claim that engagement changes are real-time.

### Exporting Instagram posts

Open the run dataset and choose JSON, CSV, Excel, XML, or HTML.
For spreadsheets, carousel details remain available as the nested `childMedia` value.
For warehouses, ingest JSON to preserve arrays and nullable fields.

Apify integrations can send results to:

- Google Sheets;
- Make;
- Zapier;
- webhooks;
- cloud storage;
- custom API consumers.

### Run with the Apify API

Replace `APIFY_TOKEN` with your token.

#### cURL

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/automation-lab~instagram-profile-posts-scraper/runs?token=APIFY_TOKEN&waitForFinish=300" \
  -H "Content-Type: application/json" \
  -d '{"usernames":["nasa"],"maxPostsPerProfile":10}'
```

Fetch dataset items using the `defaultDatasetId` returned by the run.

#### JavaScript

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

const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
const run = await client.actor('automation-lab/instagram-profile-posts-scraper').call({
  usernames: ['nasa'],
  maxPostsPerProfile: 10,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items);
```

#### Python

```python
import os
from apify_client import ApifyClient

client = ApifyClient(os.environ['APIFY_TOKEN'])
run = client.actor('automation-lab/instagram-profile-posts-scraper').call(
    run_input={'usernames': ['nasa'], 'maxPostsPerProfile': 10}
)
items = client.dataset(run['defaultDatasetId']).list_items().items
print(items)
```

### Use with Apify MCP

Add the Actor to Claude Code:

```bash
claude mcp add --transport http apify \
  "https://mcp.apify.com?tools=automation-lab/instagram-profile-posts-scraper"
```

#### Claude Desktop setup

Add this Actor-specific server to Claude Desktop's MCP configuration:

```json
{
  "mcpServers": {
    "apify": {
      "url": "https://mcp.apify.com?tools=automation-lab/instagram-profile-posts-scraper"
    }
  }
}
```

#### Cursor setup

Open **Settings → MCP servers**, add an HTTP server named `apify`, and use the same Actor-specific URL shown above.

#### VS Code setup

In an MCP-compatible VS Code assistant extension, add an HTTP server named `apify`, reconnect, and confirm the Instagram Profile Posts Scraper tool appears.

Example prompts:

- “Run Instagram Profile Posts Scraper for `nasa` and summarize the five newest captions.”
- “Collect 15 recent posts from these public creator usernames and return a table of likes and comments.”
- “Run the scraper for my competitor list and identify post IDs absent from yesterday's export.”

### Reliability, retries, and partial failures

Temporary network, rate-limit, and server responses receive bounded retries with backoff.
A temporary wait response can trigger one anonymous public-session bootstrap on the same proxy identity.

The Actor processes profiles sequentially to reduce source pressure.
If one profile fails after another succeeds, successful rows remain in the dataset, but the run is marked failed.
This makes missing profiles visible to automation consumers.

Common causes include:

- a private profile;
- a deleted or renamed profile;
- a temporary Instagram schema failure;
- rate limiting;
- an unsuitable proxy identity;
- a malformed profile URL.

### Limits and known source behavior

- Only public profile posts are supported.
- Instagram may change undocumented public response shapes.
- Some engagement counts are hidden or disabled.
- Display names and verification fields may be absent from feed-shaped rows.
- Video and CDN URLs can expire.
- Pinned posts can affect chronological ordering near the first page.
- The Actor does not scrape stories, comments, followers, hashtag feeds, or private data.
- `maxPostsPerProfile` is capped at 500.
- Inputs are capped at 50 unique profiles per run.

### Troubleshooting

#### Why did a public profile fail?

Confirm the profile opens publicly and is not private, renamed, restricted, or deleted.
Retry later after a temporary source error.
If you explicitly disabled Apify Proxy and direct access is rate-limited, restore the default datacenter proxy configuration first.

#### Why did the run return fewer posts than requested?

The profile may contain fewer public posts, the date cutoff may have been reached, or Instagram may not expose additional pages.
Check run logs for the stop reason.

#### Why are likes, comments, or views null?

Instagram does not expose every metric for every media type or account.
The Actor returns `null` rather than inventing a value.

#### Can this Actor use my Instagram login?

No.
The supported product is intentionally limited to public profile posts and does not accept login credentials or cookies.

### Responsible and legal use

Collect only public data you have a lawful purpose to process.
Follow applicable privacy, intellectual-property, database, employment, consumer-protection, and platform rules.
Do not use the Actor to harass individuals, create sensitive profiles, bypass access controls, or republish media without permission.

The user is responsible for input selection, retention, downstream use, and compliance.
This documentation is not legal advice.

### Related automation-lab Actors

- [Instagram Comments Scraper](https://apify.com/automation-lab/instagram-comments-scraper) for public discussion records.
- [Instagram Hashtag Posts Scraper](https://apify.com/automation-lab/instagram-hashtag-posts-scraper) for hashtag-based discovery.
- [Instagram Mentions & Tagged Posts Scraper](https://apify.com/automation-lab/instagram-mentions-tagged-posts-scraper) for mention and tagged-post workflows.

Use those Actors only when the separate record type is part of your job.
This Actor keeps its default dataset focused on profile posts.

### FAQ

#### Does it require an Instagram account?

No login is required for supported public profiles.

#### Does it download images and videos?

No.
It returns public media metadata and exposed CDN URLs, avoiding unnecessary transfer.

#### Can I scrape more than one profile?

Yes.
Provide up to 50 unique usernames and profile URLs in one run.

#### Can I run it repeatedly?

Yes.
Use Apify Schedules and compare stable post IDs between run datasets.

#### Does it charge for failed records?

No `post` event is emitted for failed, duplicate, malformed, or filtered-out records.
The one-time `start` event is emitted when a run begins.

#### Is the output suitable for a spreadsheet?

Yes.
CSV and Excel exports work directly, while JSON best preserves nested carousel media.

# Actor input Schema

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

Public profile usernames, with or without the @ prefix. You can combine these with profile URLs below.

## `startUrls` (type: `array`):

Public Instagram profile URLs such as https://www.instagram.com/instagram/.

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

Stop after this many accepted posts for each profile. Lower limits make monitoring runs faster.

## `onlyPostsNewerThan` (type: `string`):

Optional ISO 8601 cutoff. Older posts stop pagination, for example 2026-07-01T00:00:00Z.

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

Apify Proxy is enabled by default because Instagram commonly rate-limits shared direct IPs. Disable it only when your direct connection is known to work; you can optionally select a country or proxy group.

## Actor input object example

```json
{
  "usernames": [
    "instagram",
    "nasa"
  ],
  "startUrls": [],
  "maxPostsPerProfile": 20,
  "onlyPostsNewerThan": "",
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Dataset containing all accepted public profile posts.

# 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": [
        "instagram",
        "nasa"
    ],
    "maxPostsPerProfile": 20,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation-lab/instagram-profile-posts-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": [
        "instagram",
        "nasa",
    ],
    "maxPostsPerProfile": 20,
    "proxyConfiguration": { "useApifyProxy": True },
}

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

# Fetch and print Actor results from the run's dataset (if there are any)
print("💾 Check your data here: https://console.apify.com/storage/datasets/" + run["defaultDatasetId"])
for item in client.dataset(run["defaultDatasetId"]).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": [
    "instagram",
    "nasa"
  ],
  "maxPostsPerProfile": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call automation-lab/instagram-profile-posts-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation-lab/instagram-profile-posts-scraper",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/sNbuIZeNFh8RQnupd/builds/hbpPob0D8FJxnU5Il/openapi.json
