# Instagram Post Engagement Scraper – Commenters & Engagement (`automation_nerd/instagram-post-engagement-actor`) Actor

Analyze who engaged with a set of Instagram posts: extract every comment (id, username, text, likes, timestamp) and report like/comment counts. Public data only by default, no login.
Optional Instagram cookies also resolve who liked - which is a unique feature!

- **URL**: https://apify.com/automation\_nerd/instagram-post-engagement-actor.md
- **Developed by:** [Egon Maier](https://apify.com/automation_nerd) (community)
- **Categories:** Social media, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.06 / 1,000 comments and commenter for a post extracteds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.

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 Comments & Likers Scraper – Post Engagement

**See exactly who comments on — and who likes — any set of Instagram posts.**

Give this actor a list of Instagram post (or reel) URLs and it returns, for each
one, **every comment** (comment id, username, text, comment likes and timestamp)
and the post's **like and comment counts**. Perfect for analyzing engagement on
your own — or competitors' — content.

Works on **public data without any login** by default. **Optionally**, paste
your own Instagram cookies and the actor **also returns the likers of each
post** — the list of users who actually liked it, which Instagram hides from
anonymous requests.

### Why this scraper

- 🔓 **No login needed for comments** — most tools force a cookie just to read
  comments. This one pulls comments + counts fully anonymously.
- ❤️ **Reveals who *liked* a post** — add your `sessionid` and get the likers,
  data Instagram hides from the public. (Only the sessionid — nothing else.)
- 🧩 **Rich per-comment data** — comment ID, author, text, comment-likes,
  timestamp and reply detection, ready for analysis or exports.
- ⏱️ **Date filter** — `onlyDataAfter` returns only comments after a date and
  reports how many older ones were skipped.
- ⚡ **Fast & cheap** — pure HTTP (no browser), so it's a fraction of the cost and
  runs in seconds per post.

### Use it to

- **Find your most engaged followers** — who comments most across your posts
- **See exactly who liked a post** (with your cookies) — not just the count
- **Competitor & campaign analysis** — who's engaging with a brand's content
- **Giveaway / contest checking** — export everyone who commented (and liked) a post
- **Community research** — surface the people talking under a topic's posts

### Input

| Field                | Type             | Description                                                                                                                                                                 |
| -------------------- | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `posts`              | array            | Post/reel URLs (`https://www.instagram.com/p/SHORTCODE/`) or bare shortcodes.                                                                                               |
| `maxComments`        | integer          | Max comments to fetch per post (default 200).                                                                                                                               |
| `includeReplies`     | boolean          | Reserved (top-level comments only for now).                                                                                                                                 |
| `onlyDataAfter`      | string, optional | Keep only comments posted after this date/time (older ones are skipped and counted). Comments only — likers have no timestamp.                                              |
| `cookies`            | string, optional | Your Instagram login (secret) to **also get the likers** of each post. Accepts a Cookie-Editor JSON export, a cookie string, or just your `sessionid`. Empty = public-only. |
| `commentsDocId`      | string, optional | Advanced. Override the GraphQL comments `doc_id` if Instagram rotates it (see "Reliability").                                                                               |
| `proxyConfiguration` | object           | Apify proxy — Residential recommended (Instagram blocks datacenter IPs).                                                                                                    |
| `maxConcurrency`     | integer          | How many posts to scrape in parallel (default 3).                                                                                                                           |
| `maxRequestRetries`  | integer          | Retries per post on a transient block/error (default 3).                                                                                                                    |
| `debug`              | boolean          | Log every request URL + response status (or run with `APIFY_LOG_LEVEL=DEBUG`).                                                                                              |

Example:

```json
{
  "posts": ["https://www.instagram.com/p/Bt3gFWMhoO2/"],
  "maxComments": 300,
  "includeReplies": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": ["RESIDENTIAL"]
  }
}
```

### Getting the likers (optional, needs your Instagram cookies)

Instagram does **not** serve the list of users who liked a post to anonymous
requests — publicly you only get the like *count*. To resolve **who** liked each
post, put your Instagram login into the **`cookies`** field (see the
step-by-step guide below). The field accepts a **Cookie-Editor JSON export**, a
cookie string, or just your **`sessionid`** — the actor only needs the sessionid
and derives the rest.

With cookies, each item gains a `likers` array (`{ position, username, userId,
fullName, isVerified, isPrivate }`). Instagram's web likers endpoint returns a
single, capped list (~100, not full pagination) — `likersFetchedCount` tells you
how many were resolved, `likeCount` remains the true total. All requests then run
through your account on **one pinned proxy IP** (an account should not hop IPs).

### Output

One dataset item per post:

| Field                                                    | Description                                                                                                                      |
| -------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| `postUrl`, `shortcode`                                   | The analyzed post.                                                                                                               |
| `success`, `error`, `attempts`                           | Outcome and how many tries it took.                                                                                              |
| `ownerUsername`                                          | Who posted it.                                                                                                                   |
| `likeCount`, `commentCount`                              | Engagement totals reported by Instagram.                                                                                         |
| `fetchedCommentCount`                                    | How many comments were actually returned (after any `onlyDataAfter` filter).                                                     |
| `skippedCommentCount`                                    | How many comments were skipped for being older than `onlyDataAfter` (0 when the filter is unset).                                |
| `uniqueCommenterCount`                                   | Number of distinct commenters across the fetched comments.                                                                       |
| `comments`                                               | List of `{ id` (comment id)`, username, userId, fullName, text, likeCount, timestamp, isReply, replyToId }`.                     |
| `likersAvailable`                                        | `true` only when likers were actually resolved with a valid cookie.                                                              |
| `likersFetchedCount`, `likers`                           | Number of likers resolved and the list `{ position, username, userId, fullName, isVerified, isPrivate }`. `null` in public mode. |
| `likersError`                                            | Why likers couldn't be fetched (e.g. cookie invalid/expired, or Instagram restricts this post's likers). `null` on success.      |
| `caption`, `takenAt`                                     | Post caption and publish time.                                                                                                   |
| `responseTimeMs`, `postIndex`, `totalPosts`, `timestamp` | Run metadata.                                                                                                                    |

### What "engagement" this actor can and cannot see

- ✅ **Commenters are public** — returned in full (up to Instagram's practical cap
  of ~500 top-level comments per post).
- ✅ **Like and comment counts are public** — `likeCount` / `commentCount`.
- 🔑 **Likers (who liked) require a session cookie** — paste your `sessionid` and
  each post gains a `likers` list. Without it, `likers` is `null` and you only
  get the like count. Notes:
  - You only need the **`sessionid`** value — nothing else. The cookie is used
    **only** for the likers request; comments and counts always come from the
    public path.
  - Instagram returns a **capped list (~100 likers per post)**, not every liker —
    that's a platform limit, not a bug.
  - If the cookie is invalid/expired, or Instagram restricts a post's likers, you
    get a clear `likersError` and the rest of the data is unaffected.

### How to get your Instagram cookies (for likers)

You only need this if you want the **likers** list. It takes about a minute.
Put the result into the actor's **`cookies`** field.

#### Easiest: the Cookie-Editor extension (recommended)

Install **[Cookie-Editor](https://cookie-editor.com/)** — a free, open-source
extension for Chrome, Edge and Firefox that shows a page's cookies in one click,
no developer tools needed.

1. Install Cookie-Editor and **log in to [instagram.com](https://www.instagram.com)**
   (ideally a **secondary/throwaway account**).
2. While on instagram.com, click the **Cookie-Editor** icon in your toolbar.
3. Click **Export** (top of the popup) → **Export as JSON** — this copies all
   instagram.com cookies to your clipboard.
4. Paste that JSON straight into the actor's **`cookies`** field. Done — the actor
   picks out what it needs (`sessionid`, and derives the rest).

> Prefer the JSON export: it includes `sessionid` (which is `httpOnly`, so
> `document.cookie` can't see it) plus everything else in one paste.
> Only install reputable extensions — a cookie extension can read all your
> cookies. Cookie-Editor is widely used and open source.

#### Manual: browser developer tools (no extension)

1. Open **[instagram.com](https://www.instagram.com)** and **log in**.
2. Open developer tools: **F12**, or right-click the page → **Inspect**.
3. Go to the **Application** tab (Chrome/Edge) or **Storage** tab (Firefox). In
   the left sidebar open **Cookies → `https://www.instagram.com`**.
4. Copy the value of **`sessionid`** (a long string like `12345%3Aabcd...`).
5. Paste it into the actor's **`cookies`** field — the bare `sessionid` value is
   enough.

**Good to know**

- 🔒 The field is **secret** — Apify stores it encrypted and never shows it in the
  run input, logs or output.
- 🔑 This cookie can act as your account, like a password. **Keep it private**; to
  revoke it, log out of that browser session or change your password.
- 🌍 In cookie mode the actor sends all requests over **one fixed Residential IP**
  (no IP hopping) so the session isn't flagged. Residential proxy is recommended.
- ⏳ The cookie expires when you log out or after a while — if `likers` suddenly
  come back empty, grab a fresh `sessionid`.

### Pricing

**Pay per event** — you pay per result, so cost scales with what you get:

- **`post-comments-analyzed`** — charged **per returned comment** (minimum 1 per
  successfully analyzed post). A post with 200 comments costs more than one with 5. Always applies.
- **`post-likes-analyzed`** — charged **per returned liker** (minimum 1), only
  when you provide `cookies` and likers come back. No cookie, or likers
  unavailable → not charged.

Failed or unavailable posts are never charged. Apify platform usage (compute +
Residential proxy traffic) is billed separately by the platform.

### Notes & reliability

- **How comments are fetched:** the actor loads the public post page, which
  already contains the like/comment counts, the owner, **and the first page of
  comments** — so the basics work with no special query. To fetch *more* than the
  first page it pages through Instagram's logged-out GraphQL endpoint. No browser
  — fast and cheap.
- **Each comment includes its `id`** (the Instagram comment id) plus `username`,
  `userId`, `text`, `likeCount`, `timestamp`, and reply info (`isReply`,
  `replyToId`).
- **The GraphQL `doc_id` rotates** every few weeks and is only used for paging
  *beyond* the first page. If deep pagination stops working (you get roughly the
  first 15 comments while the total is higher), grab a fresh one: open a public
  post in a logged-out browser, find the Network request whose
  `x-fb-friendly-name` is `PolarisLoggedOutDesktopWWWPostCommentsPaginationQuery`,
  copy its `doc_id`, and set the `commentsDocId` input. The counts and first page
  keep working regardless.
- Scraping a protected UI is a cat-and-mouse game: Instagram rate-limits and can
  block requests. Retries + proxy rotation are built in; occasional failures are
  expected. Use Residential proxies for volume.
- Only public accounts/posts can be analyzed. Private accounts return an error.
- Turn on `debug` (or `APIFY_LOG_LEVEL=DEBUG`) to see every request URL and its
  response status — handy for spotting exactly where a block happens.

### Legal

Scraping publicly available data is widely considered permissible, but this
usage runs against Instagram's Terms of Service and reliability is not
guaranteed. Respect applicable law (e.g. GDPR) and only process data you have a
lawful basis to process. You are responsible for how you use the output.

# Actor input Schema

## `posts` (type: `array`):

Instagram posts to analyze. Paste full post/reel URLs (https://www.instagram.com/p/SHORTCODE/) or bare shortcodes. Each post is analyzed independently and produces one dataset item.

## `maxComments` (type: `integer`):

Upper bound on how many comments to fetch per post (pagination stops there). Lower = faster and cheaper. Instagram itself caps public comment access at roughly 500 top-level comments per post.

## `includeReplies` (type: `boolean`):

Also fetch the replies under each top-level comment. More thorough for engagement analysis, but slower and uses more requests.

## `onlyDataAfter` (type: `string`):

Optional. Keep only comments posted AFTER this moment; older ones are skipped and counted in 'skippedCommentCount'. Accepts a date (2026-07-01), an ISO datetime (2026-07-01T14:30:00Z) or a Unix timestamp. Note: applies to COMMENTS only — Instagram's likers list has no timestamp, so likers can't be date-filtered.

## `cookies` (type: `string`):

OPTIONAL. Leave empty for public scraping (comments + like/comment counts). Provide your Instagram login to ALSO get the LIKERS of each post (the users who liked it), which Instagram hides from anonymous requests. Three accepted formats: (1) the JSON export from the Cookie-Editor browser extension while on instagram.com \[recommended — one click 'Export']; (2) a cookie header string like 'sessionid=...; csrftoken=...; ds\_user\_id=...'; (3) just your 'sessionid' value. The actor needs sessionid (ds\_user\_id is derived from it automatically). Secret field: Apify stores it encrypted and never shows it in the log, input or dataset. Use an account you control; in authenticated mode all requests run on a single pinned proxy IP.

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

Instagram blocks datacenter IPs. Use Apify Residential proxies (default). You can pick a country to match your audience.

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

How many posts to scrape in parallel. Higher = faster, but a higher chance of hitting Instagram rate limits. Each post uses its own rotating proxy IP.

## `maxRequestRetries` (type: `integer`):

How often to retry a post on a transient error (rate limit / 5xx / connection / block). Reported per item as 'attempts'.

## `commentsDocId` (type: `string`):

Advanced/optional. The actor fetches comments via Instagram's logged-out GraphQL query, which uses a numeric doc\_id that Instagram rotates every few weeks. Leave empty to use the built-in default. If comments stop coming back, open a public post in a logged-out browser, find the Network request with x-fb-friendly-name = PolarisLoggedOutDesktopWWWPostCommentsPaginationQuery, and paste its doc\_id here.

## `debug` (type: `boolean`):

Log every Instagram API request URL and its response status (→ GET … / ← 302 …). Useful to inspect exactly what is called and where a block happens. Same as running with APIFY\_LOG\_LEVEL=DEBUG.

## Actor input object example

```json
{
  "posts": [
    "https://www.instagram.com/p/Bt3gFWMhoO2/"
  ],
  "maxComments": 200,
  "includeReplies": false,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "maxConcurrency": 3,
  "maxRequestRetries": 3,
  "debug": false
}
```

# Actor output Schema

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

All results as JSON (one item per post: comments, commenters, likeCount, commentCount, …)

## `run` (type: `string`):

API endpoint of this run (status, stats, storages)

# 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 = {
    "posts": [
        "https://www.instagram.com/p/Bt3gFWMhoO2/"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_nerd/instagram-post-engagement-actor").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 = {
    "posts": ["https://www.instagram.com/p/Bt3gFWMhoO2/"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("automation_nerd/instagram-post-engagement-actor").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 '{
  "posts": [
    "https://www.instagram.com/p/Bt3gFWMhoO2/"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call automation_nerd/instagram-post-engagement-actor --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "command": "npx",
            "args": [
                "mcp-remote",
                "https://mcp.apify.com/?tools=automation_nerd/instagram-post-engagement-actor",
                "--header",
                "Authorization: Bearer <YOUR_API_TOKEN>"
            ]
        }
    }
}

```

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/acts/YtsfrjOaEwP4n6Xoy/builds/iylvpk1xfOqrOIWM1/openapi.json
