# Instagram Post Scraper - Reel Views, Likes and Comments (`s-r/instagram-post-scraper`) Actor

Paste Instagram post or reel URLs and get caption, likes, comment count, views, hashtags, mentions, music track, video URL and owner stats. Optionally pull the comments. No login required.

- **URL**: https://apify.com/s-r/instagram-post-scraper.md
- **Developed by:** [SR](https://apify.com/s-r) (community)
- **Categories:** Social media, Marketing
- **Features:** Limited permissions
- **Stats:** 8 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$1.00 / 1,000 post returneds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

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 and Comments by URL

This Instagram post scraper turns post or reel URLs into structured rows: caption, likes, comments, reel views, hashtags, music and owner stats, ready for campaign reports and content analysis. No Instagram login or Instagram API key is required: the actor reads publicly available post data.

This is a single-purpose Instagram post scraper. It does one thing, takes a handful of inputs and returns one clean row per post.

### What you get

- `caption`, `hashtags` and `mentions` - full caption text with tags and handles already parsed out
- `likes`, `comments_count` and `views` - engagement, as numbers rather than display strings
- `owner_username`, `owner_followers` and `owner_is_verified` - who posted it and how big they are
- `music_title` and `music_artist` - the audio track for reels
- `video_url`, `image_url`, `thumbnail_url` and `duration_seconds` - media URLs and length
- `comments` - the visible comments, when you switch them on

### Why scrape this from Instagram

A post URL is the unit people actually work in. Someone sends you a link and the question is how it performed, who posted it and what audio it used. Getting that from the Graph API requires owning the account; getting it from the page requires parsing a render that changes shape regularly.

This actor takes the URL exactly as copied from the app or browser and returns the post as a row. Post, reel and TV URLs all work, including the canonical form with the username in the path. Hashtags and mentions come out as arrays rather than leaving you to regex the caption.

### Input

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `search` | array | yes | No default | Instagram post, reel or TV URLs, one per line. |
| `includeComments` | boolean | no | `False` | Also return the visible comments on each post. |
| `maxComments` | integer | no | `20` | Only used when comments are included. |

### Instagram Post Scraper input example

This input was used for a successful run with two public National Geographic posts. Counts and visible comments can change between runs.

```json
{
  "search": [
    "https://www.instagram.com/reel/DdG4RIxIPyf/",
    "https://www.instagram.com/p/Dd8u0tIFz1F/"
  ],
  "includeComments": true,
  "maxComments": 100
}
```

The `search` field also accepts public profile URLs and `@handles`, keywords and location URLs. A profile returns its public profile record and, by default, up to twelve timeline posts. `maxPostsPerProfile: 0` requests only the profile. The optional `maxReelsPerProfile` requests additional posts from the profile's reels tab and defaults to zero. A keyword returns posts that Instagram associates with that keyword; not every phrase has a public keyword page. If there is no matching page, the run completes without results or charges for that term.

Existing saved tasks can continue using the advanced fields `queries`, `profiles` and `locationIds`. The actor combines those entries with `search` and removes duplicate post shortcodes. `enrichReels` and `includeCreatorStats` default to true; disabling them can leave some engagement, audio or creator fields empty. `maxReels` controls keyword results and defaults to 200. Public data availability remains the limit even when a larger number is requested.

### Output

One row per post, plus public profile or location records when those inputs are requested. Existing output fields remain available. The additional `source`, `platform`, `fetched_at` and `_type` fields identify the origin, collection time and record type. Post rows also expose `post_url`, `post_id`, `author_handle`, `author_id` and `text`; profile rows expose `profile_url`, `handle`, `name`, `bio` and `emails` alongside the existing names. Unavailable values are null or an empty list as appropriate, rather than estimated engagement.

| Field | Description |
|---|---|
| `shortcode` | Post shortcode from the URL |
| `url` | Public Instagram URL for this record |
| `caption` | Post caption text |
| `likes` | Like count |
| `comments_count` | Comment count |
| `views` | View count for video posts |
| `posted_at` | Publication timestamp |
| `is_video` | Whether the post is a video |
| `video_url` | Direct video URL when available |
| `image_url` | Full size image URL |
| `thumbnail_url` | Thumbnail URL |
| `hashtags` | Hashtags found in the caption |
| `mentions` | Accounts mentioned in the caption |
| `owner_username` | Handle that published the post |
| `owner_followers` | Follower count of the publishing account |
| `owner_is_verified` | Whether the publisher is verified |
| `music_title` | Audio track title |
| `music_artist` | Audio track artist |
| `duration_seconds` | Video length in seconds |
| `comments` | Comment records when comments are requested |
| `record_type` | Which kind of row this is |

### Instagram Post Scraper output example

A selection of fields from a real row, returned for the first URL of a two-URL run on 2 October 2026. The full row also carries media URLs, IDs and the other fields listed below.

```json
{
  "record_type": "reel",
  "shortcode": "DbIdlf0j6uA",
  "url": "https://www.instagram.com/reel/DbIdlf0j6uA/",
  "owner_username": "natgeo",
  "owner_followers": 268480747,
  "owner_is_verified": true,
  "caption": "Describe Pompeii: Out of Time in 3 words? It's Now Streaming.\n\n#PompeiiOutOfTime with @twhiddleston is now streaming on @DisneyPlus and @hulu.",
  "hashtags": ["pompeiioutoftime"],
  "mentions": ["twhiddleston", "disneyplus", "hulu"],
  "likes": 27958,
  "comments_count": 316,
  "views": 72795,
  "posted_at": "2026-07-23T13:00:03Z",
  "is_video": true,
  "duration_seconds": 36.202,
  "music_title": "Original audio",
  "music_artist": "natgeo",
  "engagement_rate": 0.0104
}
```

### Use cases

**Campaign reporting on creator posts.** When creators deliver links rather than analytics screenshots, this turns a list of URLs into a performance table. `owner_followers` alongside `likes` gives an engagement rate per post, which is the number that survives scrutiny in a wrap report.

**Competitive content teardowns.** Collect a competitor's best-performing posts and pull them in one run. Caption structure, hashtag sets and audio choices become comparable across dozens of posts at once, which is where content patterns actually become visible.

**Audio and trend tracking for reels.** `music_title` and `music_artist` on every reel let you see which tracks are attached to the posts that performed. Audio choice is one of the strongest reach levers on reels and one of the least documented.

**Compliance and disclosure auditing.** For regulated categories, the caption and its parsed hashtags are the evidence trail for whether required disclosure was present. Running a creator's delivered links through this produces a dated, structured record.

### How this Instagram scraper compares

**Instagram Graph API.** The official API only returns insights for accounts you own or manage. To look at a creator's or competitor's post you need their permission. This actor works from the public post URL, so any public post or reel is in scope.

**Copying numbers by hand.** Likes, comment counts and reel views are shown on the page, but copying them for fifty creator posts is slow and error-prone, and hashtags and mentions have to be picked out of the caption. Here each URL becomes one row with every count as a number and tags already split into arrays.

**Profile-feed scrapers.** Many Instagram scrapers in the Store start from a profile and walk its feed. That is the right tool when you want everything an account posted. When you already have the exact links, for example a creator's campaign deliverables, a URL-first Instagram post scraper avoids paying for posts you did not ask for. Profile URLs, keywords and locations are still accepted when you do want discovery.

### Pricing

$0.0010 per post returned, which is $1.00 per 1,000 rows. All pricing is pay-per-event - you only pay for results you receive. There is no actor-start event. Deleted posts and unavailable results are free. Public profile and location records count as results when returned.

### Limits and gotchas

- Public posts only. Private accounts do not resolve.
- Comments are the visible set, not the complete thread. Very large comment counts are truncated by Instagram before this actor sees them.
- View counts exist for video posts only. Image posts return no view figure, which is Instagram's behaviour rather than a gap here.
- Media URLs are time-limited by Instagram's CDN. Fetch them promptly or re-run.
- Free Apify plans are capped at 10 rows per run. Paid plans have no cap.
- Deleted posts keep a result row with `unavailable: true` and a reason. The row is free. Empty source failures are reported without charging for missing data.

### FAQ

**Can I scrape an Instagram post without logging in?**

Yes. This actor reads the public post surface logged out, so no Instagram account is needed. Instagram can still restrict requests or return only some public fields.

**Does it work on reels as well as posts?**

Yes. Post, reel and TV URLs are all accepted, including the canonical form with the username in the path. The type is detected from the URL.

**Can I get the comments?**

Yes, switch on include comments and set how many per post. It is off by default because most reporting use cases only need the count.

**Does it return video files?**

It returns the video URL Instagram serves, plus the thumbnail and image URLs. It does not re-host or download the media.

**What if the post is from a private account?**

It will not resolve. Private posts have no public surface, and this actor does not authenticate.

**Is this an Instagram scraper API I can call from code?**

Yes. Like every Apify actor it can be started through the Apify API or the Python and JavaScript clients, and the rows come back as JSON, CSV or Excel from the dataset. Pass the same `search` array you would enter in the console.

### Related Actors

- [Instagram Profile Scraper](https://apify.com/s-r/instagram-profile-scraper)
- [Instagram Keyword Scraper](https://apify.com/s-r/instagram-keyword-scraper)
- [Instagram Trending Scraper](https://apify.com/s-r/instagram-trending-scraper)

# Actor input Schema

## `search` (type: `array`):

Instagram post/reel URLs, profile URLs or @handles, keywords or location ids.

## `queries` (type: `array`):

Legacy additional search entries.

## `profiles` (type: `array`):

Legacy additional usernames or profile URLs.

## `locationIds` (type: `array`):

Legacy additional numeric location ids.

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

Maximum visible comments per post; Instagram may return fewer.

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

Maximum timeline posts per profile; zero returns only the profile.

## `maxReelsPerProfile` (type: `integer`):

Additional posts from the reels tab.

## `maxReels` (type: `integer`):

Maximum posts collected from keyword pages.

## `maxKeywords` (type: `integer`):

Maximum keyword pages, including related pages.

## `expandRelated` (type: `integer`):

Depth of the related-keyword graph.

## `maxSeedTerms` (type: `integer`):

Maximum seeds from the trending page.

## `concurrency` (type: `integer`):

Requested parallelism; each request handles at most four pages at once.

## `includeComments` (type: `boolean`):

Include visible comments from each public post page.

## `enrichReels` (type: `boolean`):

Fetch post pages for exact engagement and optional comments.

## `includeCreatorStats` (type: `boolean`):

Fetch embed pages for followers, music and duration.

## `expandRelatedTopics` (type: `boolean`):

Follow related topic pills when expanding keywords.

## `includeTrending` (type: `boolean`):

Append public trending topics, creators and reels.

## `seedFromTrending` (type: `boolean`):

Seed the keyword crawl with public trending topics.

## `mode` (type: `string`):

Legacy field; this actor always detects URLs and returns posts.

## `searchType` (type: `string`):

Legacy field; this actor always detects URLs and returns posts.

## `cursor` (type: `string`):

Continuation position returned as next_cursor.

## `crawl_state` (type: `object`):

Opaque continuation state returned by the previous call; preserve it unchanged.

## `continuation` (type: `string`):

Opaque continuation marker used by the gateway.

## Actor input object example

```json
{
  "search": [
    "https://www.instagram.com/reel/DdG4RIxIPyf/",
    "https://www.instagram.com/p/Dd8u0tIFz1F/"
  ],
  "maxComments": 20,
  "maxPostsPerProfile": 12,
  "maxReelsPerProfile": 0,
  "maxReels": 200,
  "maxKeywords": 50,
  "expandRelated": 0,
  "maxSeedTerms": 10,
  "concurrency": 6,
  "includeComments": false,
  "enrichReels": true,
  "includeCreatorStats": true,
  "expandRelatedTopics": true,
  "includeTrending": false,
  "seedFromTrending": false,
  "cursor": "0"
}
```

# Actor output Schema

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

Paste Instagram post or reel URLs and get caption, likes, comment count, views, hashtags, mentions, music track, video URL and owner stats. Optionally pull the comments. No login required.

## `output` (type: `string`):

OUTPUT record with the run's counts and status flags.

## `errors` (type: `string`):

Failures with a code and a redacted message. Absent when the run had none.

# 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 = {
    "search": [
        "https://www.instagram.com/reel/DdG4RIxIPyf/",
        "https://www.instagram.com/p/Dd8u0tIFz1F/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("s-r/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 = { "search": [
        "https://www.instagram.com/reel/DdG4RIxIPyf/",
        "https://www.instagram.com/p/Dd8u0tIFz1F/",
    ] }

# Run the Actor and wait for it to finish
run = client.actor("s-r/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 '{
  "search": [
    "https://www.instagram.com/reel/DdG4RIxIPyf/",
    "https://www.instagram.com/p/Dd8u0tIFz1F/"
  ]
}' |
apify call s-r/instagram-post-scraper --silent --output-dataset

```

## MCP server setup

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