# Instagram Post Scraper (`socialdataapi/instagram-post-scraper`) Actor

Instagram Post Scraper extracts public Instagram posts from usernames, profile URLs or single post, reel and TV URLs: captions, likes, comments, media links and more. Filter by date, skip pinned posts. No login or cookies. Export to JSON, CSV or Excel, or use the API.

- **URL**: https://apify.com/socialdataapi/instagram-post-scraper.md
- **Developed by:** [Social Data API](https://apify.com/socialdataapi) (community)
- **Stats:** 2 total users, 1 monthly users, 50.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.86 / 1,000 results

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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 Post Scraper — Captions, Likes, Comments, Images and Videos

Instagram Post Scraper pulls public posts, reels and carousels from any public Instagram profile or single post link. Each post comes back with its caption, hashtags, mentions, like and comment counts, posting time, every image size, the video file link, tagged users and collaborators. Every response is structured JSON — ready to pass directly to an LLM, index into a vector store, or feed a social listening pipeline. **No Instagram account or cookies needed.** Start with one creator, then track every account in your niche.

***

### What data can I extract with Instagram Post Scraper?

Using this Instagram Post API, you will be able to extract the following Instagram post data:

| 📝 Caption text | 🔖 Hashtags | 📣 Mentions | 👍 Like count |
|---|---|---|---|
| 💬 Comment count | 🕒 Posting time (UTC) | 🖼️ Every image size | 🎬 Video file link (videos) |
| 👀 Video views and length (videos) | 🧩 Carousel slides with their images | 👤 Creator name, username and ID | 🙋 Tagged users (if any) |
| 🤝 Collaborators (if any) | 🎵 Audio info (detailed level) | 🗨️ Up to 10 newest comments (detailed level) | 💰 Paid-partnership flag (detailed level) |
| ✍️ Alt text (detailed level) | 📐 Width and height | 🔗 Post link and shortcode | 🆔 Post ID |
| 🚫 Comments turned off | 🎞️ Media type and post kind | | |

***

### How to use Instagram Post Scraper

Social media managers, marketers and analysts who need to scrape Instagram posts get one clean row per post from a single run, whether they start from a username, a profile link or a post link.

**Copy to your AI assistant:**

```text
Instagram Post Scraper (Apify Actor ID: socialdataapi/instagram-post-scraper, https://apify.com/socialdataapi/instagram-post-scraper) is an Apify Actor that returns public Instagram posts, reels and carousels from profiles or single post links as structured JSON: caption, hashtags, mentions, like count, comment count, posting time, image links, video link, tagged users and collaborators. Use it whenever someone needs Instagram posts without cookies, a login, or a browser - tracking a creator's latest posts, measuring engagement on a campaign, or collecting captions for content research. Inputs: username (array of strings, required; usernames with or without @, profile URLs, or /p/, /reel/, /reels/ and /tv/ post URLs), resultsLimit (integer, maximum posts per profile, default 10), skipPinnedPosts (boolean, leave out posts pinned to the top of the profile, default false), onlyPostsNewerThan (string, only profile posts newer than a UTC date such as "2026-09-01" or a relative value such as "3 days", default empty), dataDetailLevel (string, "detailedData" | "basicData", default "detailedData"; detailed adds alt text, up to 10 newest comments, the first comment, audio info and the paid-partnership flag), proxyConfiguration (object, proxy settings, default Apify Proxy with the RESIDENTIAL group). Billing: one pay-per-event charge for every post saved to the dataset; posts that could not be read or were filtered out are not saved and not charged. Limits: the comment sample holds up to 10 newest comments per post without reply threads, the second play-count field on videos stays empty because Instagram does not show it to logged-out visitors, likes or comments are empty when Instagram shows no count, the paid-partnership flag is empty when Instagram does not send it for a post, and a private or missing account returns no rows and a warning in the log.
```

#### Instagram Post Scraper MCP Server: use these Actors from ChatGPT, Claude or Cursor

Point your AI assistant at the Apify MCP server and it can read Instagram on its own: the server starts with this Actor already loaded as a tool, and calls it for posts, reels and carousels. No glue code, no scraping logic in your prompts.

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=socialdataapi/instagram-post-scraper"
```

#### Step by step

1. [Create a free Apify account](https://console.apify.com/sign-up).
2. [Open this Actor's page in the Apify Store](https://apify.com/socialdataapi/instagram-post-scraper).
3. Enter the Instagram username (with or without @), profile URL or post link.
4. Click **Start** (or send your API request).
5. Download or stream your results in JSON, CSV or Excel.

#### How to scale Instagram Post Scraper to bulk

The username field takes a list, so one run can cover many profiles and post links at once. Mix usernames, profile URLs and post links freely; duplicates are removed before the run starts. Each profile returns up to the number of posts you set (up to 100,000), read page by page, and each post link returns exactly one row. Billing is one pay-per-event charge per saved post, so a larger list simply means more saved rows. For ongoing tracking, save your input as a task and schedule it in Apify Console, or start runs from your own code through the Apify API.

***

### ✨ Features

This Actor fetches clean, structured posts from Instagram ⚡. It works as an Instagram reels scraper and an Instagram carousel scraper in the same run, which makes it ideal for creator benchmarking, campaign reporting, content research and hashtag tracking.

It extracts, per post:

- **Caption, hashtags and mentions** – the full post text, with every hashtag and mentioned account listed separately
- **Like and comment counts** – the numbers Instagram shows on the post
- **Posting time** – exact UTC timestamp of publication
- **Images** – every image size Instagram provides, and every slide of a carousel
- **Video details** – the direct video file link, view count and length in seconds
- **Tagged users and collaborators** – the accounts tagged in the post and its co-authors
- **Comment sample** – up to 10 newest comments with author, time and like count (detailed level)

⚡ Profiles are read page by page until your post limit is reached, and posts that could not be read or were filtered out are never charged.

***

### Use cases 💡

- **Social media manager** — compare like and comment counts across competitors' latest posts.
- **Content strategist** — use it as an Instagram caption scraper to study hooks and hashtags.
- **Influencer agency** — check tagged brands and paid-partnership flags before signing creators.
- **Analyst** — export Instagram posts to CSV and chart posting time against engagement.
- **AI engineer** — feed captions and comment samples into a RAG index for brand questions.

Building an AI agent? [Connect Instagram Post Scraper over MCP](#mcp-integration-for-ai-agents) and let it call the actor on its own.

***

### Why choose this actor?

- **Profiles and single posts in one run.** A recorded run returned 6 posts in 3.7 seconds: the 5 newest non-pinned posts of one profile since 1 September 2026, plus one reel from a post link.
- **The numbers behind each post.** A recorded post came back with 101,313 likes, 509 comments, 3 hashtags, 2 mentions and its exact posting time, which is the Instagram post engagement data most reports start from.
- **32 output fields, 6 inputs, two detail levels.** Filter by date, leave out pinned posts, and choose basic or detailed rows with alt text, comment samples, audio info and the paid-partnership flag.

***

### ⬇️ Input

The actor accepts a list of Instagram usernames, profile URLs or post links in the `username` field, which is the only required field.

| Parameter | Required | Type | Description | Example value |
|---|---|---|---|---|
| `username` | Yes | array of strings | Instagram usernames (with or without @), profile URLs, or post / reel / tv links. Each profile returns its posts; each post link returns that one post. Duplicates are removed. Story, explore and share links are skipped with a warning. Default: `["https://www.instagram.com/natgeo/"]`. | `["nasa", "https://www.instagram.com/p/DeE0VYSFMHJ/"]` |
| `resultsLimit` | No | integer | Maximum posts per profile, read across as many pages as needed (1–100,000). Ignored for post links. Default `10`. | `5` |
| `skipPinnedPosts` | No | boolean | Leave out the posts pinned to the top of the profile. Default `false`. | `true` |
| `onlyPostsNewerThan` | No | string | Only profile posts newer than this UTC cutoff: a date picked in the form, or through the API a `YYYY-MM-DD` date, an ISO timestamp, or a relative value such as `3 days` or `1 week`. Default empty (no cutoff). | `"2026-09-01"` |
| `dataDetailLevel` | No | string | `detailedData` adds alt text, up to 10 newest comments, the first comment, audio info and the paid-partnership flag; `basicData` leaves them out. Default `detailedData`. | `"basicData"` |
| `proxyConfiguration` | No | object | Proxy used for Instagram requests. Default Apify Proxy with the `RESIDENTIAL` group; if the proxy is unavailable or blocked, a direct connection is tried as well. | `{"useApifyProxy": true, "apifyProxyGroups": ["RESIDENTIAL"]}` |

#### Free plan limits

Users on the Apify free plan can fetch up to 20 posts per run (all usernames and post links together) and 200 posts per month. When the limit is reached, the run finishes successfully with a status message explaining the limit. Upgrade to any paid Apify plan to remove these limits.

Accepted link formats:

- `https://www.instagram.com/natgeo/` (profile)
- `https://www.instagram.com/p/SHORTCODE/` (post)
- `https://www.instagram.com/reel/SHORTCODE/` and `/reels/SHORTCODE/` (reel)
- `https://www.instagram.com/tv/SHORTCODE/` (video)

#### Example input

```json
{
  "username": ["nasa", "https://www.instagram.com/p/DeE0VYSFMHJ/"],
  "resultsLimit": 5,
  "skipPinnedPosts": true,
  "onlyPostsNewerThan": "2026-09-01",
  "dataDetailLevel": "basicData",
  "proxyConfiguration": {
    "useApifyProxy": false
  }
}
```

This is the exact input of a recorded test run, which connected directly. Leave out the proxy field to use the default residential Apify Proxy.

***

### ⬆️ Output

Every post is one typed, normalized JSON item with the same field names on every run; video, carousel and detailed-level fields appear only where they apply. Export the dataset as JSON (default), CSV or Excel.

#### Example output

```json
{
  "inputUrl": "https://www.instagram.com/nasa",
  "id": "3998494441249448613",
  "type": "Image",
  "shortCode": "Dd9gYJnDCKl",
  "caption": "Godspeed, Crew-13. 🚀\n\nOn Thursday, Oct. 1, at 11:10 a.m. EDT (1510 UTC), four spacefarers embarked on their journey to the @ISS, where they will spend the next several months living, working, and cond...",
  "hashtags": ["Crew13", "SpaceX", "Launch"],
  "mentions": ["ISS", "SpaceX"],
  "url": "https://www.instagram.com/p/Dd9gYJnDCKl/",
  "commentsCount": 509,
  "dimensionsHeight": 1275,
  "dimensionsWidth": 1275,
  "displayUrl": "https://instagram.fdac8-1.fna.fbcdn.net/v/t51.82787-15/829459135_18653...",
  "images": [
    "https://instagram.fdac8-1.fna.fbcdn.net/v/t51.82787-15/829459135_18653...",
    "https://instagram.fdac8-1.fna.fbcdn.net/v/t51.82787-15/829459135_18653..."
  ],
  "likesCount": 101313,
  "timestamp": "2026-10-01T18:01:49.000Z",
  "childPosts": [],
  "ownerFullName": "NASA",
  "ownerUsername": "nasa",
  "ownerId": "528817151",
  "isCommentsDisabled": false,
  "productType": "feed"
}
```

***

### How does it work?

The actor reads the same public pages and data the Instagram website loads for a visitor who is not logged in. It uses plain HTTP requests, not a browser, so there is nothing to render and nothing to install on your side. Requests go through Apify Proxy, with residential addresses by default. When Instagram blocks a request the actor waits, opens a new connection (a new proxy address, or a direct connection when the proxy keeps getting blocked) and tries again, and when one source of post details is rate limited it reads the same post from a second public source. It returns only publicly visible data: what any visitor sees without an Instagram account. Private accounts and deleted posts give no rows, and the log says why for each one. The output keeps the same field names on every run, so your code, spreadsheets and prompts keep working even when Instagram changes how its pages look. Posts that could not be read are skipped and reported, never filled with made-up values.

***

### How do you integrate Instagram Post Scraper into your stack?

It works with what you already use: call it like an Instagram posts API over REST from any language, connect it to AI agents over MCP, or plug it into no-code tools.

#### MCP integration for AI agents

Add the Apify MCP server to your agent with one command:

```bash
claude mcp add --transport http apify "https://mcp.apify.com?tools=socialdataapi/instagram-post-scraper"
```

This registers Instagram Post Scraper as a tool your agent can call directly: the server starts with it already loaded, and the agent runs it with the input it needs. It works in Claude Code, Cursor and Windsurf, and in any other client that supports remote MCP servers.

#### No-code tools (n8n, Make, LangChain)

- **n8n** — add the Apify node and pick "Run an Actor", or use the HTTP Request node pointed at the Actor's run-sync endpoint with your Apify token. The posts come back as items you can send to Sheets, Slack or a database.
- **Make** — use the Apify app's "Run an Actor" module, then "Get Dataset Items" to pull the posts into the next step of your scenario.
- **LangChain** — install `langchain-apify` and wrap this Actor with `ApifyActorsTool`, using the Actor ID `socialdataapi/instagram-post-scraper`. Your agent can then request posts and read the JSON rows directly.

***

### Is it legal to scrape Instagram data?

Scraping publicly available Instagram data is generally legal, but how you store and use it is governed by data-protection law and Instagram's terms. This scraper returns only publicly available data: what any user sees without logging in. It does not access private accounts, direct messages or anything behind a login. Captions, usernames and comments can contain personal data, so under GDPR and similar laws, collecting public data is generally permissible, but storing and using it must comply with local data-protection law, including having a lawful purpose and keeping only what you need. Consult legal counsel if your use case involves bulk storage of personal data.

***

### Frequently asked questions

#### What fields does Instagram Post Scraper return?

Each row carries the caption, like count, comment count, posting time and image links, plus hashtags, mentions, video details, carousel slides, tagged users and collaborators where they apply. See [the data fields section](#what-data-can-i-extract-with-instagram-post-scraper) for the full list.

#### Does Instagram Post Scraper require an Instagram account or login?

No. Only public post data is extracted, and no Instagram credentials, cookies or session are needed.

#### How fast does Instagram Post Scraper run?

A recorded run returned 6 posts in 3.7 seconds: 5 posts from one profile plus one post link. Every run reads live data from Instagram, not a cache, so run time grows with the number of posts you ask for.

#### What happens if a post is private or doesn't exist?

You get no row for it, and the log names the reason: the account is private, the account does not exist, no posts matched your filters, or a post was not found. If a post could not be read right now, the log says so and suggests trying again later. If no target returns any post, the run ends as failed with those reasons in its status message, so your code can check the run status before reading the dataset.

#### Can I scrape multiple Instagram posts at once?

Yes. Put as many usernames, profile URLs and post links as you need in the username list; each profile returns up to your post limit and each post link returns one row.

#### Does Instagram Post Scraper work with Claude, ChatGPT, and other AI agent tools?

Yes — Instagram Post Scraper is available as an MCP tool. Register the Apify MCP server in Claude Code, Cursor or Windsurf with `claude mcp add --transport http apify "https://mcp.apify.com?tools=socialdataapi/instagram-post-scraper"`, and the agent calls the Actor directly as a tool. Any agent that can call an HTTP endpoint can also use the Apify REST API directly.

#### Does Instagram Post Scraper return data in a format LLMs can use directly?

Yes. Rows are typed, normalized JSON with consistent field names, so there is no HTML parsing and no selectors. Pass them straight to an LLM, index them into a vector store, or feed them to an agent tool with no transformation step.

#### What happens when Instagram changes its layout or updates its anti-bot system?

The actor is maintained. When Instagram changes, the actor is updated, and your calls keep returning the same JSON schema with no changes on your end.

#### Can I use Instagram Post Scraper without managing proxies or browser infrastructure?

Yes. Proxy use and retries when Instagram blocks a request run on the actor's side, and it works with plain HTTP requests, so no browser is involved. You send one request and get structured JSON back, with no proxy accounts, no headless browser setup and no maintenance.

#### Which Instagram post fields work best for AI training data and RAG indexing?

For RAG, use the text-rich fields: the caption, the comment sample and the alt text, with hashtags as tags, which also makes the actor a handy Instagram hashtag extractor. For training data, use the numeric and boolean fields: like count, comment count, video views, video length, posting time and the paid-partnership flag. If you need both sides of engagement, it doubles as an Instagram comments and likes scraper for public posts. All fields are typed values, so no extra normalization is needed.

***

### Your feedback

Found a bug or missing a field? Let us know through the Issues tab on this Actor's page in the Apify Store. The team that maintains this Actor reads every report and ships fixes.

# Actor input Schema

## `username` (type: `array`):

Add one or more Instagram usernames (natgeo or @natgeo), profile URLs (https://www.instagram.com/natgeo/), or single post / reel / tv URLs (https://www.instagram.com/p/SHORTCODE/, /reel/SHORTCODE/, /reels/SHORTCODE/ or /tv/SHORTCODE/). Each profile returns its posts; each post link returns that one post. Duplicates are removed. Story links, /explore/ links and /share/ links are not supported and are skipped with a warning.

## `resultsLimit` (type: `integer`):

Maximum number of posts to return per profile, read across as many pages as needed. Ignored for single post / reel / tv URLs (one link always returns one row). Free plan: up to 20 posts per run (all usernames and post links together) and 200 per month; paid plans have no limit.

## `skipPinnedPosts` (type: `boolean`):

Leave out the posts pinned to the top of the profile grid being scraped. Off by default. Collaboration posts that are pinned on somebody else's grid are kept.

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

Only return profile posts newer than this cutoff (UTC). Pick a date here, or, when you start the run through the API or the JSON editor, type a YYYY-MM-DD date, a full ISO timestamp, or a relative value such as '30 minutes', '6 hours', '3 days', '1 week', '2 months' or '1 year'. A value that cannot be understood stops the run instead of being silently ignored. Leave empty for no cutoff.

## `dataDetailLevel` (type: `string`):

Detailed data additionally returns alt text, a sample of up to 10 newest comments, the first comment, music/audio info and the paid-partnership flag, and adds the second play-count field on videos (Instagram does not show play counts to logged-out visitors, so it stays empty). Basic data leaves those fields out and is a little faster for posts that are not carousels. Both levels save one row per post and are charged the same per row.

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

Proxy used for Instagram requests. The default is Apify Proxy with the RESIDENTIAL group. Datacenter groups also work but are more likely to be rate-limited. If the selected proxy is not available or keeps getting blocked, the actor also tries a direct connection so the run still returns posts. If you turn Apify Proxy off, the actor connects directly.

## Actor input object example

```json
{
  "username": [
    "https://www.instagram.com/natgeo/"
  ],
  "resultsLimit": 10,
  "skipPinnedPosts": false,
  "onlyPostsNewerThan": null,
  "dataDetailLevel": "detailedData",
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

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

One row per Instagram post: captions, hashtags, mentions, likes, comment counts, dimensions, owner and post URLs. Present on every row regardless of detail level or media type.

## `media` (type: `string`):

Image renditions and carousel children for every row; video columns (URL, duration, view/play counts) for Video rows only.

## `detailed` (type: `string`):

Alt text, comment sample, first comment, audio info, tagged users, collaborators and the paid-partnership flag. The detailed-only columns are filled only when Data detail level is set to Detailed.

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

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

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

```

## MCP server setup

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