# Instagram Post Likers Scraper — Who Liked Any Public Post (`steadyfetch/instagram-post-likers-scraper`) Actor

Scrape the accounts that liked an Instagram post or reel — username, full name, user id, profile link, picture, verified and private flags. Paste links, codes or media ids. No login. About 1,000 likers per post per read, ~2,000 at most. Re-runs never charge a liker twice. From $0.40 per 1,000.

- **URL**: https://apify.com/steadyfetch/instagram-post-likers-scraper.md
- **Developed by:** [Steadyfetch Team](https://apify.com/steadyfetch) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 32 total users, 19 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.40 / 1,000 likers

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 Likers Scraper — Who Liked Any Public Post

**Instagram Post Likers Scraper: paste a post or reel link and get the accounts that liked it** — handle, full name, user id, profile link, picture, and the verified and private flags. No login, no cookies, no proxy to set up, nothing charged for starting a run, and a liker we could not deliver is never charged.

**Using an AI agent?** Pin this actor in Apify's MCP server with one link: `https://mcp.apify.com?tools=steadyfetch/instagram-post-likers-scraper`

- **Actor id:** `steadyfetch/instagram-post-likers-scraper`
- **Input:** `{ "postUrls": ["DcOX3hWFiey"] }` — the one field to set. A post, reel or IGTV link, its bare code as shown, or the post's 19-digit Instagram media id.
- **Cap the bill:** set `maxTotalChargeUsd` on the run (a run option, not Actor input), e.g. `0.50` — the run stops when it reaches it.
- **Price:** from **$0.40 per 1,000 likers** on Gold and above, $1.00 per 1,000 on the Apify free plan. Full table below.
- **How many you get:** up to ~2,000 likers per post. On a big post one read usually returns about 1,000, sometimes a few hundred more — ~2,000 is the most one read can give; the per-post status row tells you how many likes the post shows and how many likers you got.
- **Run it again later:** likers your account already received from the same post come back uncharged, so the same links tomorrow pay only for the new likers.

If it earned its keep, a rating helps other buyers find it, and saving the actor keeps it one click away.

**See a real run before you spend anything:** [sample dataset](https://api.apify.com/v2/datasets/vEKb1gdFyK4CvWfvH/items?clean=true\&format=json) — fifty likers of one public NASA post from one verified run with the per-post limit set to 50, unedited, and the run's own summary row last.

*Unofficial. Not affiliated with, endorsed by, or sponsored by Instagram or Meta Platforms, Inc.*

### What you get

One row per account that liked the post, in the order Instagram listed them:

| Column | What it holds |
|---|---|
| `username` · `fullName` · `userId` | who liked it, and Instagram's own numeric id for them |
| `profileUrl` · `profilePicUrl` | their profile link, and their picture |
| `isVerified` · `isPrivate` | their account flags, as Instagram reports them |
| `postShortcode` · `postUrl` | which of your posts they liked |
| `source` · `input` · `sourceIndex` · `scrapedAt` | always `instagram`, the exact value you typed, its place in your list, and when it was read |
| `repeat` · `charged` · `status` · `statusReason` | whether your account already had this liker, whether the row was billed, and why |

Each post that comes back short of your per-post limit also gets **one uncharged status row** with `likeCount` (the likes the post shows, empty when the owner hides them), `likersServed` (how many the read returned), `likersDelivered` (how many reached your dataset) and `likesHidden`.

Profile pictures are signed and time-limited by Instagram, so download them soon if you need them. The requesting network address is stripped out of every link before it reaches your dataset.

### Up to ~2,000 likers per post — what that means

Instagram serves a post's likers as one list, and this actor reads it in one go. That list tops out at about 2,000 accounts, and on a big post one read usually returns about 1,000. It can vary from read to read: a post showing 577,212 likes gave back 1,979 one day and 999 the next, while a post with 508 likes gave back 503. So:

- **A post with a few hundred likes:** you usually get close to all of them.
- **A big post:** you get the likers Instagram serves in that read, usually about 1,000 — not every account that ever liked it, and this page never claims otherwise.
- **More likers than one read gives:** one read returns the first ≈ 1,000; Instagram offers no further page, so a re-run on the same post returns about the same likers, not more (and the ones you already have come back uncharged).
- **The status row shows the gap on your own post**, so you never have to take our word for it: likes shown, likers served, likers delivered.

### Price

One charged event, `liker`, and it lands only on a liker that was actually delivered.

| Apify plan | Per liker | Per 1,000 likers |
|---|---|---|
| Free plan | $0.001 | $1.00 |
| Bronze | $0.0008 | $0.80 |
| Silver | $0.0006 | $0.60 |
| Gold and above | $0.0004 | **$0.40 per 1,000** |

Platform usage is included in that price. There is no separate compute bill, no start fee and no per-post fee. Set `maxTotalChargeUsd` on the run and it is a hard ceiling: the run stops cleanly under it and the last row says what is left.

### What you are never charged for

Every post that comes back short of your per-post limit closes with one uncharged status row saying why (a post that filled the limit you set needs none). None of these is billed:

- **`likers_list_end`** — Instagram's list for the post ended. You got what it shows.
- **`likers_capped`** — the post counts more likes than one read serves. The row gives both numbers.
- **`likes_hidden`** — the owner hides the like count. The likers the list served are still delivered (and charged); only the total is missing.
- **`no_likers`** — the post has no likes yet, or shows none.
- **`skipped.all_repeat`** — the read served only likers your account already has, and you switched **Include likers you already have** off.
- **`post_not_found`** — a wrong link, a private account, or a deleted post.
- **`stopped_at_limit`** — one of your limits, the run clock, your bill cap, or the Apify free plan's daily allowance stopped it. The row names which.
- **`vendor_unavailable`** — the read did not go through. Temporary, says nothing about your post, and a re-run is the fix.
- **`source_refused`** — Instagram refuses that link the same way every time, so a re-run cannot change it.
- **`unsupported_shape`** — Instagram answered in a shape this actor does not read yet. That is on us; tell us on the Issues tab which post it was.
- **`limit_reached`** — this run reached its limit. The row says whether a new run on the same links continues now.

The last row of every run is a receipt: likers delivered, posts read, what was skipped, what stopped it, and the charged-event totals. A time limit ends the collecting, never the delivering — likers already in hand are always written out.

### How often this data changes

A post keeps collecting likes for days after it goes up, and the busiest hours are the first few. So the useful pattern is the same links again tomorrow, not one run.

Every run remembers which likers it delivered to your account, per post, for 90 days, in a key-value store in your own Apify account. With **Include likers you already have** on (the default, `includeSeen`), a later run hands those back marked `repeat: true` and uncharged, so each run gives you the post's whole current list and you pay only for the likers that are new. Switch it off and they are skipped instead — no row, no charge — and the post's status row counts them. **Skip likers in this dataset** (`resumeFromDatasetId`) carries the same memory across Apify accounts.

**Run it on a schedule:** save your input as a Task (Actor page → Save as a new task), then add that task to an Apify Schedule (Console → Schedules → Create) with a cron such as `0 7 * * *` for daily. Each run rereads the same posts and charges only for new likers.

A run started with a scoped API token in restricted-access mode needs key-value store Read, Write and Create permission (or Actor runs set to Full access) to use that memory. Without it, the run says so on its status line and on an uncharged row, and cannot tell which likers you already have.

### Use it as an API endpoint (Standby)

You can also call this actor like an API: send one Instagram post and get the accounts that liked it back in the same response, with no run to start and no dataset to read. The address is on the actor's **Endpoints** tab, where you can also try it from the browser.

```bash
curl -H "Authorization: Bearer <YOUR_APIFY_TOKEN>" \
  "https://steadyfetch--instagram-post-likers-scraper.apify.actor/?postUrl=https://www.instagram.com/p/DcOX3hWFiey/&maxLikers=100"
```

| Setting | What it does |
|---|---|
| `postUrl` | The Instagram post, reel or IGTV link, its short code, or its 19-digit Instagram media id. One post in each request. |
| `maxLikers` | How many likers to return. 2,000 if you leave it out, which is also the most one request returns (100 on the Apify free plan). |

The answer is JSON: `likers` (each with the same fields as a row in a run's dataset), `delivered`, `charged`, `notes` for anything that was not returned, in plain words, and `summary`, the same receipt a run ends on. You are charged per liker returned, at the same per-liker price as a run. A request that returns no likers is not charged, and if the charge for a request cannot be completed, its likers are not sent and nothing is charged.

Good to know: the endpoint has no account memory, so each request returns and charges the likers it reads, even ones you collected before. For many posts at once, or to get likers you already have back uncharged, run the actor as usual.

### Limits and good manners

**Your settings are never refused for being too big.** `maxLikersPerPost` is per post and tops out at 2,000; `maxItems` caps the whole run; `maxRunSeconds` runs from 30 seconds to 1 hour (600 by default). Ask for more than a limit allows, or for a clock outside that range, and the run still starts: it continues at the nearest limit and leaves one uncharged row saying what you asked for and what bound it.

On the Apify free plan this actor reads at most 10 posts per account in any 24 hours, and accounts on that plan share one daily allowance on this actor. Past either, the run keeps everything it already delivered, ships one uncharged row saying when it resets (UTC), and charges nothing past it. Paid Apify plans carry no daily allowance.

Only public posts are read. This actor may stop working if Instagram changes how the data is served; if it does, failed reads are never charged.

### Reliability

There is nothing to log into and nothing to configure: no cookies, no account of yours, no proxy. When a read cannot go through, the run says so on an uncharged row and finishes successfully — a failed read is never billed and never dressed up as a post with no likers.

### Related actors

- The comments under the same posts: **Instagram Comments Scraper** — https://apify.com/steadyfetch/instagram-comments-scraper
- The people behind one account: **Instagram Followers Scraper** — https://apify.com/steadyfetch/instagram-followers-scraper
- One account's own posts, to feed this one links: **Instagram Profile Posts Scraper** — https://apify.com/steadyfetch/instagram-profile-posts

### Support

Something off, or a column you need that is not here? Open an issue on the Issues tab — we usually reply within a couple of hours.

# Changelog

This Actor's version history is a separate document: https://apify.com/steadyfetch/instagram-post-likers-scraper/changelog.md

# Actor input Schema

## `postUrls` (type: `array`):

Instagram post, reel or IGTV links, the bare code at the end of one, or the post's 19-digit Instagram media id, e.g. \["https://www.instagram.com/p/DcOX3hWFiey/", "DdG2ps5y5-l"]; "\_demo" is the sample switch, not a link. Never charged: a link that does not resolve, a deleted or private post, and a liker this account already has. A profile or hashtag link is refused with an uncharged row naming the actor that takes it. Leave it untouched and click Start for built-in sample rows, at no result fee.

## `maxLikersPerPost` (type: `integer`):

Hard cap on the likers delivered for EACH post, a whole number up to 2,000, e.g. 500 — three posts at 500 collect up to 1,500 in total. One read of a post's likers list serves about 1,000 accounts, sometimes a few hundred more, and 2,000 is the most this actor can deliver for one post: ask for more and the run continues at 2,000, with one uncharged row saying so, rather than being refused. A post that runs short leaves one uncharged row with the numbers.

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

Optional cap on the likers delivered across the WHOLE run, a whole number, e.g. 1000, on top of the per-post limit. Leave it empty for no run-wide cap. Posts the run did not reach because this cap was full each get one uncharged row saying so. Likers handed back from your account's memory count against it like any other row.

## `maxRunSeconds` (type: `integer`):

Max run seconds, a whole number from 30 to 3,600, e.g. 600 — the run stops cleanly before this many seconds and reports what is left, instead of being killed by a timeout. A time limit ends the collecting, never the delivering: likers already in hand are always written out. The clock runs between 30 seconds and 1 hour: set it outside that and the run continues at the nearest one, with one uncharged row saying so, rather than being refused.

## `includeSeen` (type: `boolean`):

A switch, true (default) or false. ON: a liker already delivered to your account for that post is delivered again, marked `repeat: true`, and NOT charged, so each run hands you the post's whole current list. OFF: those likers are skipped — no row, no charge — and the post's status row counts them. Likers older than 90 days in your account's memory count as new again either way.

## `resumeFromDatasetId` (type: `string`):

Dataset ID of a previous run of this actor, e.g. the 17-character ID on that run's Storage tab: likers already in it are never charged again, so a follow-up run pays only for new likers. It works even from a different Apify account. Selecting it here is what grants this run permission to read it.

## Actor input object example

```json
{
  "postUrls": [],
  "maxLikersPerPost": 2000,
  "maxRunSeconds": 600,
  "includeSeen": true
}
```

# Actor output Schema

## `likers` (type: `string`):

One row per liker delivered: the account that liked the post (username, full name, user id, profile link, picture, verified and private flags) and the post it liked (link, short code, media id). One charged event per liker delivered (`liker`) — there is no second event and no charge for starting a run. Every row carries `charged` and `status`, so the invoice reconciles from the dataset itself: only rows with charged = true were billed. A liker your account already had for that post is never charged again: with "Include likers you already have" ON (the default) it comes back marked `repeat: true`, uncharged; OFF, it is skipped. That check reads a key-value store in your own account, so a run on a scoped API token without key-value store permission cannot make it and says so on its status line and on an uncharged row.

## `misses` (type: `string`):

One uncharged row for every post that delivered fewer likers than it was asked for, with the like count the post shows (null when its owner hides it), the likers the read served and the likers delivered, saying which of these happened: `likers_capped` (the post counts more likes than one read of its likers list serves — about 1,000, never past ~2,000 — so that is the most this actor can collect for it), `likers_list_end` (Instagram's likers list for the post ended there), `likes_hidden` (the owner hides the like count; the list served is what there is), `no_likers` (Instagram lists nobody), `skipped.all_repeat` (the likers left were already in your account and skipped), `post_not_found` (the link or id is wrong, the account is private, or the post was deleted), `stopped_at_limit` (one of your own limits, the run clock, or the Apify free plan's daily allowance stopped it first), `vendor_unavailable` (the read failed and a re-run is the fix), `source_refused` (Instagram refused that post the same way every time), `unsupported_shape` (Instagram answered in a shape this actor does not read yet — on us), `limit_reached` (this run reached its limit — the row says whether a new run continues now). None of these is charged.

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

Likers delivered, what was asked for, likers your account already had, what stopped the run, the charged-event totals, and — when this run's token could not open the repeat memory — `repeatCheck: "unavailable_scope"`.

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

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

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

```

## MCP server setup

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