# Instagram Post & Reel Scraper - Views & Engagement (`eiv/instagram-post-scraper`) Actor

Scrape Instagram posts and reels by profile, post URL or audio: exact likes, comments and views, captions, dates, engagement rate, collaborators, sponsors, tags, location, music and media URLs. Date-range and reels-only filters. No login. From $0.70 per 1,000 posts.

- **URL**: https://apify.com/eiv/instagram-post-scraper.md
- **Developed by:** [Eimantas V](https://apify.com/eiv) (community)
- **Stats:** 20 total users, 6 monthly users, 94.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.60 / 1,000 post scrapeds

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 Post & Reel Scraper** extracts public posts and reels from **Instagram**: captions, exact like, comment and view counts, publish dates, engagement rate, collaborators, paid-partnership sponsors, tagged users, location, music, image and video links, and optionally the latest comments. Paste usernames, profile or reels-tab URLs, post and reel URLs, or audio URLs, and get one row per post. No login, no cookies, no browser, from **$0.35 per 1,000 posts** ($1.00 on the Starter plan).

```json
{
  "url": "https://www.instagram.com/reel/DePpLegAuKI/",
  "type": "Video",
  "productType": "clips",
  "ownerUsername": "natgeo",
  "timestamp": "2026-10-08T19:05:31.000Z",
  "likesCount": 58205,
  "commentsCount": 203,
  "videoPlayCount": 1310882,
  "videoDuration": 9.258,
  "engagementRate": 0.0218,
  "musicInfo": { "songName": "Original audio", "artistName": "natgeo", "usesOriginalAudio": true }
}
```

**Measured on Apify (2026-10-09): 3,800 posts from 20 profiles in 92 seconds; 200 posts with their latest comments in 51 seconds.**

### What does Instagram Post & Reel Scraper do?

It reads the posts and reels Instagram shows a visitor who is not logged in, for as many profiles, posts and sounds as you list, and returns them as clean rows you can download as JSON, CSV or Excel. It adds what Instagram does not show in one place: the engagement rate of every post, who it was made with, which brand paid for it, and which sound a reel uses.

- **Every input form.** Usernames (`natgeo`), @handles, profile URLs, the reels tab (`instagram.com/natgeo/reels/`), numeric user IDs, post and reel URLs in every shape Instagram shares (`/p/`, `/reel/`, `/reels/`, `/tv/`, `/<user>/p/`), and audio pages (`instagram.com/reels/audio/<id>/`) for every reel that uses a sound.
- **Exact numbers.** Likes, comments and views (plays) as exact counts, not "1.3M", with video length and publish time to the second.
- **Date ranges that cost nothing extra.** "Posts newer than" stops at the first older post; "Posts older than" jumps straight to that date, so a quarter from two years ago costs a handful of requests, not thousands of skipped posts.
- **Brand and creator research.** Paid-partnership label and sponsor brands, collab co-authors, tagged users, mentions, hashtags, location with coordinates, and the song and artist of every reel.
- **Engagement rate per post.** (Likes + comments) / the profile's followers, with the exact follower count in each row.
- **Latest comments at no extra charge.** Turn on "Add latest comments" for each post's newest comments (about 14) and Instagram's own description of the image.
- **Only pay for results.** Private, empty or missing profiles, posts your filters leave out and duplicates are never charged.
- **Built for automation.** Run it on a schedule, call it from the API, or connect it to Make, Zapier, n8n, Google Sheets or an AI agent through Apify's MCP server.

### Why it is fast and cheap

There is no browser and no login. The Actor reads Instagram's own app feeds, the same data the Instagram app loads: one request returns 12 posts with every count, about 5 KB per post. Profiles are scraped ten at a time from Apify's own addresses, and the Actor switches to fresh IPs by itself if Instagram ever refuses one, so there is no proxy to set up and a large list does not stall.

### What data can you extract from Instagram?

| Field | Example | What it is |
|---|---|---|
| `url`, `shortCode`, `id` | `https://www.instagram.com/reel/DePpLegAuKI/` | Link, code and numeric media ID |
| `type`, `productType` | `Video`, `clips` | Image, Video or Sidecar (carousel); `clips` = a reel |
| `caption`, `hashtags`, `mentions` | `Many orphaned giant anteater pups…` | Full caption, plus the hashtags and @mentions in it |
| `likesCount`, `commentsCount` | `58205`, `203` | Exact counts |
| `videoPlayCount`, `videoDuration` | `1310882`, `9.258` | Views (plays) and length in seconds of reels and videos |
| `timestamp` | `2026-10-08T19:05:31.000Z` | Publish time, UTC |
| `engagementRate`, `profileFollowersCount` | `0.0218`, `268420490` | (Likes + comments) / followers x 100, and the follower count used |
| `ownerUsername`, `ownerFullName`, `ownerId`, `ownerIsVerified` | `natgeo` | Who posted it |
| `coauthors` | `["rolex"]` | Collab co-authors |
| `isPaidPartnership`, `sponsors` | `true`, `["rolex"]` | "Paid partnership" label and the sponsoring brands |
| `taggedUsers` | `["nasa"]` | Accounts tagged in the photo or video |
| `locationName`, `locationId`, `locationLat`, `locationLng` | `International Space Station` | Tagged location with coordinates |
| `musicInfo` | `Don't Stop Me Now`, `Queen` | Song and artist, or the creator's original audio, with the audio page ID and file |
| `isPinned` | `false` | Pinned to the top of the profile |
| `displayUrl`, `images`, `videoUrl` | URLs | Cover image, every image of a carousel, the video file |
| `childPosts` | 3 slides | Each carousel slide with its image, video and size |
| `dimensionsWidth`, `dimensionsHeight`, `hasAudio` | `1080`, `1920`, `true` | Original size and sound |
| `latestComments` | 14 comments | Text, author, likes and time (with "Add latest comments") |
| `accessibilityCaption` | `Video by National Geographic…` | Alt text (with "Add latest comments", or when the owner wrote one) |

The dataset has five views: **Overview**, **Reels and music**, **Collabs, sponsors and tags**, **Media files** and **Latest comments**.

### How to scrape Instagram posts and reels

1. Click **Try for free** and paste usernames, profile, post, reel or audio URLs into **Instagram profiles, posts or audio**, one per line.
2. Set **Max posts per profile** (20 by default) and, if you like, a date range or **Reels only**.
3. Click **Start**. A typical list of a few profiles finishes in under ten seconds; thousands of posts take a minute or two.
4. Open the **Output** tab, or download the results as JSON, CSV, Excel or HTML.

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

You pay per post returned, and the price drops on higher Apify plans:

| Apify plan | Per 1,000 posts |
|---|---|
| Free | $1.20 |
| Starter | $1.00 |
| Scale | $0.80 |
| Business | $0.60 |

- The latest 50 posts of 20 competitor accounts (1,000 posts) on the Starter plan cost **$1.00**.
- 100,000 posts a month on the Business plan cost **$60**.
- Latest comments, views, music, sponsors and the engagement rate are included in that price.
- A run also costs **$0.00005** to start. A profile that fails, or matches nothing, costs nothing more.
- The Free plan's $5 monthly credit covers about **4,000 posts**.

### Input

```json
{
    "targets": [
        "natgeo",
        "https://www.instagram.com/nike/reels/",
        "https://www.instagram.com/p/DeJ28eTxo4s/",
        "https://www.instagram.com/reels/audio/1584203999231664/"
    ],
    "maxPostsPerProfile": 50,
    "onlyPostsNewerThan": "30 days",
    "skipPinnedPosts": true
}
```

| Field | Default | Notes |
|---|---|---|
| Instagram profiles, posts or audio | `nasa` (example) | Usernames, profile or reels-tab URLs, user IDs, post or reel URLs, audio URLs; one per line |
| URLs (for chaining Actors) | empty | The same in the URL-list shape other Actors output |
| Max posts per profile | 20 | Per profile or audio page, newest first, after filters |
| Max posts in total | 100,000 | Your cost cap for the run |
| What to take from profiles | Posts and reels | Or **Reels only** (the reels tab) or **Photos and carousels only** |
| Posts newer than / older than | empty | `2025-01-31`, or relative such as `7 days`, `3 months`, `1 year`; together they make a date range |
| Skip pinned posts | off | Leave out the posts pinned to the top of a profile |
| Add latest comments | off | Newest comments and alt text per post; free, one extra request per post |
| Concurrency, timeout, retries | 10, 30 s, 2 | Tuned already; IP addresses are managed for you |

Inputs written for other Instagram post scrapers (`username`, `directUrls`, `resultsLimit`) also work as they are.

### Output

Each post or reel is one row in the dataset (shortened here; the full row has every field in the table above):

```json
{
  "recordType": "post",
  "input": "https://www.instagram.com/natgeo/reels/",
  "id": "4003599702326174344",
  "shortCode": "DePpLegAuKI",
  "url": "https://www.instagram.com/reel/DePpLegAuKI/",
  "type": "Video",
  "productType": "clips",
  "caption": "Many orphaned giant anteater pups in Brazil are still nursing when their mothers are killed…",
  "hashtags": [],
  "mentions": ["fernando.faciole"],
  "likesCount": 58205,
  "commentsCount": 203,
  "videoPlayCount": 1310882,
  "videoDuration": 9.258,
  "timestamp": "2026-10-08T19:05:31.000Z",
  "engagementRate": 0.0218,
  "profileFollowersCount": 268420490,
  "ownerUsername": "natgeo",
  "ownerFullName": "National Geographic",
  "ownerId": "787132",
  "ownerIsVerified": true,
  "coauthors": [],
  "taggedUsers": [],
  "isPinned": false,
  "isPaidPartnership": false,
  "sponsors": [],
  "locationName": null,
  "musicInfo": {
    "audioId": "28892386943719393",
    "songName": "Original audio",
    "artistName": "natgeo",
    "usesOriginalAudio": true,
    "isExplicit": false,
    "durationSecs": 9.258,
    "audioUrl": null
  },
  "latestComments": [
    { "id": "18135469879651603", "text": "😢❤️", "ownerUsername": "a_viewer", "ownerIsVerified": false, "likesCount": 0, "repliesCount": null, "timestamp": "2026-10-09T07:18:27.000Z" }
  ],
  "displayUrl": "https://scontent-iad3-1.cdninstagram.com/v/t51.82787-15/…",
  "videoUrl": "https://scontent-iad6-1.cdninstagram.com/o1/v/t2/f2/m86/…",
  "dimensionsWidth": 1080,
  "dimensionsHeight": 1920,
  "accessibilityCaption": "Video by National Geographic on October 08, 2026. May be an image of …",
  "hasAudio": true,
  "dataLevel": "full",
  "scrapedAt": "2026-10-09T07:21:13.193Z"
}
```

A target that cannot be read becomes a row with `"recordType": "error"` and an `errorCode` instead of failing the whole run:

| `errorCode` | Meaning |
|---|---|
| `NOT_FOUND` | No such profile, post or sound, or the account is deactivated or restricted |
| `PRIVATE` | A private account: only its followers can see its posts |
| `NO_POSTS` | The profile is public but has no posts (or no reels) |
| `BLOCKED` / `RATE_LIMITED` | Instagram refused every address for this target; run it again later |
| `PARSE_FAILED` | Instagram answered in an unexpected shape; please report it |

Error rows are never charged.

### Tips and limits

- **Views are plays.** `videoPlayCount` is the number Instagram shows as views on a reel or video. Photos and carousels have no public view count, so it is empty for them.
- **Collabs appear on every co-author's profile.** A profile's grid includes posts it made together with other accounts: `ownerUsername` says who posted it and `coauthors` who else is on it, so filter on `ownerUsername` if you want only the profile's own posts.
- **Grid or reels tab.** "Posts and reels" reads the profile grid. Creators can hide a reel from the grid; those appear only with **Reels only**, which reads the reels tab. With "Posts older than", reels come from the grid, because the reels tab cannot jump to a date.
- **Pinned posts come first.** Instagram puts up to three pinned posts on top of a profile, whatever their age. They are flagged `isPinned`, kept out of the date cut-off, and can be skipped.
- **Links expire.** Instagram's image, video and audio links stop working after a few days; download the media you want to keep.
- **Not available without a login:** share counts, more than the newest ~14 comments, reel transcripts, the "tagged" tab of a profile, and hashtag or location searches.
- **A post URL Instagram hides from its owner's feed** is still returned from the public post page, marked `"dataLevel": "partial"`: everything except views, video length, sponsors and the pinned flag.
- **Hit your spending limit?** The run stops cleanly at your maximum cost per run and keeps everything it collected. Raise the limit in the run options to get more.

### FAQ

#### Is it legal to scrape Instagram?

This Actor collects only data that Instagram shows publicly, without logging in. Results can still contain personal data, which laws such as the GDPR protect. Scrape personal data only for a legitimate purpose, and ask a lawyer if you are unsure. Videos, images and music belong to their creators. Instagram is a trademark of its owner; this Actor is not affiliated with or endorsed by Instagram or Meta.

#### Can I use it through the API or with Make, Zapier and n8n?

Yes. Every run can be started through the [Apify API](https://docs.apify.com/api/v2) and returns the dataset as JSON, CSV or Excel. Schedules, webhooks and integrations for Make, Zapier, n8n and Google Sheets are on the **Integrations** tab. A daily schedule with "Posts newer than" set to `1 day` returns each day's new posts.

#### Can AI agents use it?

Yes. Agents connected to [Apify's MCP server](https://mcp.apify.com) can find and run this Actor as a tool, with the same per-post pricing. Give it usernames or post URLs and read back counts, captions and engagement.

#### How is the engagement rate calculated?

Likes plus comments of the post, divided by the followers of the profile it was scraped from (for a post URL: its owner), times 100. It is left empty when the owner hides like counts, and for audio pages, whose reels come from many different accounts.

#### Why did I get fewer results than I asked for?

The profile has fewer posts than your limit or in your date range, some targets do not exist or are private (they return error rows), the run reached your maximum cost per run, or it reached its timeout. The log says which, and nothing collected before that is lost.

### Related scrapers

- [Instagram Profile Scraper - Followers, Posts & Emails](https://apify.com/eiv/instagram-profile-scraper): follower counts, bios, emails and engagement for the same accounts.
- [TikTok Video Scraper - Views, Likes & Hashtags](https://apify.com/eiv/tiktok-video-scraper): the same post metrics for TikTok videos.
- [YouTube Shorts Scraper - Views, Likes & Channel Data](https://apify.com/eiv/youtube-shorts-scraper): short-form video performance on YouTube.
- [Threads Scraper - Posts, Likes & Replies by Profile](https://apify.com/eiv/threads-profile-scraper): what the same accounts post on Threads.

### Support

Missing a field, or found a profile or post that does not work? Open an issue on the **Issues** tab with the input you used, and it will be looked at quickly.

# Actor input Schema

## `targets` (type: `array`):

One per line, in any form: username (natgeo), @handle, profile URL (instagram.com/natgeo/), the reels tab (instagram.com/natgeo/reels/) for that profile's reels only, a numeric user ID, a post or reel URL (instagram.com/p/..., instagram.com/reel/...), or an audio URL (instagram.com/reels/audio/...) for the reels that use that sound. Duplicates are scraped once.

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

The same profiles, posts or audio pages in the URL-list shape other Actors output (for example the profiles found by Instagram Profile Scraper), so their results can be fed straight in. Use this or the field above.

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

How many posts to take from each profile or audio page, newest first, after your filters. A post or reel URL is always one row. You pay per post, so this is also your cost cap per profile.

## `maxItems` (type: `integer`):

Stop the whole run after this many posts: your cost cap for the run.

## `contentType` (type: `string`):

"Posts and reels" reads the profile grid: photos, carousels and reels. "Reels only" reads the profile's reels tab, which also has reels the creator hid from the grid. "Photos and carousels only" leaves out videos and reels.

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

Only posts published on or after this date: 2025-01-31 (UTC), or relative such as "7 days", "2 weeks" or "3 months". The scan stops at the first older post, so this also saves time.

## `onlyPostsOlderThan` (type: `string`):

Only posts published before this date: 2024-12-31 (UTC), or relative such as "1 year". The scraper jumps straight to the date, so an old period costs no extra requests. Use both date fields for a date range.

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

Leave out the posts a profile pinned to the top of its grid (or reels tab). They are usually much older than the rest.

## `includeLatestComments` (type: `boolean`):

Adds each post's newest comments as latestComments (about 14 per post: text, author, likes, time) and Instagram's image description as accessibilityCaption. No extra charge, but one extra request per post, so the run takes longer.

## `maxConcurrency` (type: `integer`):

How many profiles, posts or audio pages are scraped at the same time. The default is tuned for speed without tripping Instagram's rate limits.

## `requestTimeoutSecs` (type: `integer`):

How long to wait for one response from Instagram before giving up on it.

## `maxRetries` (type: `integer`):

Retries for failed connections and server errors. Rate limits are handled separately, by switching IP address.

## Actor input object example

```json
{
  "targets": [
    "nasa"
  ],
  "maxPostsPerProfile": 20,
  "maxItems": 100000,
  "contentType": "all",
  "skipPinnedPosts": false,
  "includeLatestComments": false,
  "maxConcurrency": 10,
  "requestTimeoutSecs": 30,
  "maxRetries": 2
}
```

# Actor output Schema

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

One row per post or reel (recordType "post"), plus one uncharged row per target that could not be read (recordType "error").

## `reels` (type: `string`):

Views, likes, comments, duration, sound (song and artist, or original audio) and the video file of every reel.

## `brands` (type: `string`):

Paid partnership label, sponsors, collab co-authors, tagged users, mentions, hashtags and location per post.

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

Image and video URLs, carousel slides, dimensions and alt text per post.

## `summary` (type: `string`):

Totals for the run: targets, posts, failures, why it stopped, requests and which IP types answered them.

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

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

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

```

## MCP server setup

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