# Instagram Reels Scraper — Reels & Metrics from Public Profiles (`thirdwatch/instagram-reels-scraper`) Actor

Extract public Instagram Reels for any profile — video URLs, view/like/comment counts, captions, timestamps and thumbnails — via Instagram's own page payloads, no login. Clean JSON for trend tracking and social monitoring.

- **URL**: https://apify.com/thirdwatch/instagram-reels-scraper.md
- **Developed by:** [Thirdwatch](https://apify.com/thirdwatch) (community)
- **Categories:** Social media
- **Stats:** 2 total users, 1 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $8.00 / 1,000 results

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 Scraper — Posts, Reels, Comments & Profiles

> **Thirdwatch portfolio:** 8,800+ users across 140+ public Actors, 2M+ records delivered, >95% run success. [Explore all Thirdwatch Actors](https://apify.com/thirdwatch).

### What you get

> Five Instagram scrapers in one Actor, no login required. Profile posts, profile reels, single post/reel details, comments, and profile cards — captions, hashtags, mentions, like and comment counts, music, video URLs, carousels, tagged users, bios, follower counts, and external links.

### Modes

Set `mode`, or leave it on `auto` and the Actor reads each input: a post URL returns post details, a handle returns that handle's posts.

| Mode | Input | Returns | One dataset item per |
|------|-------|---------|----------------------|
| `profilePosts` | `@handle` or profile URL | The account's timeline — posts, reels and carousels | post |
| `profileReels` | `@handle` or profile URL | The account's timeline filtered to reels | reel |
| `postDetails` | `/p/…` or `/reel/…` URL | Full record for one post or reel | post |
| `comments` | `/p/…` or `/reel/…` URL | Comments on that post | comment |
| `profile` | `@handle` or profile URL | Profile card, optionally with recent posts attached | profile |
| `auto` (default) | anything | Routes each input by its shape | varies |

You can mix input shapes in one run on `auto`:

```json
{
  "queries": [
    "@natgeo",
    "https://www.instagram.com/p/Dc_g-YvhWhw/",
    "https://www.instagram.com/nasa/"
  ],
  "mode": "auto",
  "maxResults": 50
}
```

### Input parameters

| Parameter | Required | Description |
|-----------|----------|-------------|
| `queries` | Yes | Post/reel URLs, profile URLs, `@handles`, or `#hashtags`. |
| `mode` | No | `auto` (default), `profilePosts`, `profileReels`, `postDetails`, `comments`, `profile`. |
| `maxResults` | No | Max total dataset items across all queries. Default `10`. |
| `maxResultsPerQuery` | No | Per-query cap. `0` = no per-query cap. Default `0`. |
| `maxCommentsPerPost` | No | `comments` mode. Default `15`. Instagram serves only the first page to logged-out clients, so higher values do not return more. |
| `maxPostsPerProfile` | No | `profile` mode. Recent posts attached to each profile record. Default `12`, max `60`. |
| `searchType` | No | Legacy. Only consulted when `mode` is `auto`. Prefer `mode`. |

A bare word is treated as a hashtag on `auto`, as a handle under the profile modes, and as a shortcode under `postDetails`/`comments`. So `{"queries": ["nasa"], "mode": "profilePosts"}` scrapes `@nasa`.

### Output fields — posts and reels

| Field | Description |
|-------|-------------|
| `type` | `image`, `video`, `carousel`, or `reel` |
| `shortcode` / `url` | Post shortcode and canonical URL |
| `caption` | Full caption text |
| `hashtags` | Hashtags parsed from the caption |
| `mentions` | `@handles` parsed from the caption |
| `likeCount` | Likes (`null` when the account hides counts) |
| `commentCount` | Comments |
| `viewCount` | Plays/views — **`null` on public data**, see Limitations |
| `timestamp` | ISO 8601 publish time |
| `authorUsername` / `authorFullName` / `authorId` / `authorIsVerified` | Author |
| `videoUrl` | Direct MP4 URL for videos and reels |
| `imageUrl` / `thumbnailUrl` | Highest-resolution still |
| `music` | `{title, artist, audioAssetId, isOriginalAudio, isExplicit}` for reels |
| `carousel_media` | Every slide of a carousel with its own image/video URL |
| `tagged_users` | Accounts tagged in the media |
| `coauthors` | Collab post co-authors |
| `location` | Location name, when tagged |
| `dimensions` | `{width, height}` |
| `productType` | Instagram's own type (`feed`, `clips`, `carousel_container`) |
| `isSponsored` | Paid-partnership flag |
| `commentsDisabled` / `likeAndViewCountsDisabled` | Creator-side visibility settings |
| `accessibility_caption` | Instagram's generated alt text |

### Output fields — comments

| Field | Description |
|-------|-------------|
| `text` | Comment body |
| `ownerUsername` / `ownerFullName` / `ownerId` / `ownerIsVerified` | Commenter |
| `ownerProfilePicUrl` | Commenter avatar |
| `likeCount` | Likes on the comment (`null` = Instagram did not disclose it) |
| `timestamp` | ISO 8601 |
| `isReply` / `parentCommentId` | Threading |
| `replyCount` | Replies (`null` = Instagram did not disclose it) |
| `postShortcode` / `postUrl` / `postOwnerUsername` / `postCaption` | Parent post |
| `totalCommentCount` | Total comments on the post |
| `moreCommentsAvailable` | `true` when Instagram holds more back behind a login |

### Output fields — profiles

| Field | Description |
|-------|-------------|
| `username` / `fullName` / `id` | Identity |
| `biography` | Bio text |
| `biographyMentions` / `biographyHashtags` | Parsed from the bio |
| `followerCount` / `followingCount` / `postCount` | Counts |
| `countsAreApproximate` | `true` when a count came from Instagram's rounded meta tag |
| `isVerified` / `isPrivate` | Status |
| `externalUrl` / `bio_links` | Links in the bio |
| `profilePicUrl` / `profileUrl` | Media and canonical URL |
| `pronouns` / `hasClips` | Extras |
| `category`, `businessEmail`, `businessPhoneNumber` | Business contact fields — see Limitations |
| `recentPosts` | Recent posts, when `maxPostsPerProfile > 0` |

### Example output

```json
{
  "type": "reel",
  "shortcode": "Dc_g-YvhWhw",
  "url": "https://www.instagram.com/reel/Dc_g-YvhWhw/",
  "caption": "Again and again, this young humpback whale burst from the waters off Baja California…",
  "hashtags": [],
  "mentions": ["mywildlive"],
  "likeCount": 8869,
  "commentCount": 73,
  "viewCount": null,
  "authorUsername": "natgeo",
  "timestamp": "2026-09-07T16:16:24+00:00",
  "videoUrl": "https://instagram.fblr22-1.fna.fbcdn.net/o1/v/t2/f2/…",
  "music": {
    "title": "Original audio",
    "artist": "natgeo",
    "audioAssetId": "28139527835659346",
    "isOriginalAudio": true
  },
  "dimensions": { "width": 1080, "height": 1920 },
  "productType": "clips"
}
```

### Use cases

- **Influencer vetting** — `profile` for reach, then `profilePosts` for real engagement per post rather than a follower count alone.
- **Reels/short-form research** — `profileReels` to isolate short-form output, with `music` to see which audio a creator rides.
- **Competitor content tracking** — `profilePosts` on a competitor set to measure cadence, format mix, and hashtag strategy.
- **Audience and sentiment analysis** — `comments` across a campaign's posts for verbatim customer language.
- **Campaign reporting** — `postDetails` on a list of sponsored post URLs for exact like/comment counts at a point in time.
- **Creative asset collection** — `videoUrl` and `carousel_media` for downloading a creator's public media.
- **CRM enrichment** — attach follower counts, bio links, and verification to creator records.

### Limitations

These are properties of Instagram's public web, not of this Actor. Every one of them is reported honestly in the output rather than silently zero-filled.

- **View/play counts are not public.** Instagram stopped serving `play_count` to logged-out clients. `viewCount` is `null`, never a fabricated `0`.
- **Comments are capped at roughly the first page** (~15). Instagram gates comment pagination behind a login. `moreCommentsAvailable: true` tells you when more exist.
- **Comment replies are rarely exposed.** `replyCount` is `null` when Instagram does not disclose it.
- **`category`, `businessEmail` and `businessPhoneNumber` require a login.** They are returned as `null`/empty, and `categoryAvailable: false` marks the difference between "no category" and "not public".
- **`postCount` can be approximate.** Instagram leaves the exact field null and only publishes a rounded count ("32K Posts") for large accounts. `countsAreApproximate: true` flags it.
- **Private profiles return no posts.** The profile record still comes back with `isPrivate: true` — the account exists, its posts are not public.
- **Hashtag pages require a login.** Hashtag queries fall back to public-index discovery and then enrich each hit from Instagram. Check `dataQuality`; indexed rows may omit engagement and media. When that discovery cannot run at all the query is reported as blocked, never as "no results".
- **Stories and the "For You" reels feed require authentication** and are not supported.

A run that never reaches Instagram fails with a clear status message. A run that *did* reach Instagram and found nothing succeeds with a status message saying so — a deleted handle, a private account, or a term with no public posts. An empty dataset is never left unexplained.

### Compared to alternatives

- **vs. single-purpose Instagram Actors**: competitors split posts, reels, comments, transcripts, and profiles across separate Actors with separate billing. This one covers five modes on one schema and one price, so a pipeline that needs profile posts *and* their comments runs against one integration.
- **vs. apify/instagram-scraper** ($0.0027/result on FREE, from $0.0015 at high volume): Thirdwatch starts at $0.0012/result and drops to $0.0006.
- **vs. apidojo/instagram-scraper** (from $0.00047/post): Apidojo's lowest advertised high-volume rate is lower. Thirdwatch's FREE rate is transparent at $0.0012 and covers comments and reels in the same Actor.

Pairs well with [TikTok Scraper](https://apify.com/thirdwatch/tiktok-scraper?fpr=9m2cd6) and [YouTube Scraper](https://apify.com/thirdwatch/youtube-scraper?fpr=9m2cd6) for cross-platform creator research.

### Use cases & recipes

Step-by-step guides on [thirdwatch.dev/blog](https://thirdwatch.dev/blog):

- [Monitor Brand Instagram Engagement (2026 Guide)](https://thirdwatch.dev/blog/monitor-brand-instagram-engagement)
- [Research Instagram Hashtag Performance (2026 Guide)](https://thirdwatch.dev/blog/research-instagram-hashtag-performance)
- [Scrape Instagram Profiles and Posts at Scale (2026)](https://thirdwatch.dev/blog/scrape-instagram-profiles-and-posts)
- [Track Influencer Follower Growth on Instagram (2026)](https://thirdwatch.dev/blog/track-influencer-follower-growth-on-instagram)

### FAQ

**Can I scrape one post by URL?**
Yes — pass the `/p/…` or `/reel/…` URL. On `auto` it returns post details; set `mode: "comments"` for its comments instead.

**How do I get only a creator's reels?**
`mode: "profileReels"` with the handle in `queries`.

**Why is `viewCount` null?**
Instagram no longer serves play counts to logged-out clients. Reporting `null` keeps "not available" distinct from "zero views".

**Why did I only get 15 comments on a post with thousands?**
Instagram serves one page of comments without a login. `moreCommentsAvailable: true` marks it.

**Do I need an Instagram account or API key?**
No. The Actor works entirely against publicly accessible pages.

**Will it scrape Stories?**
No. Stories require a login.

Last verified: 2026-09

More scrapers at [thirdwatch.dev](https://thirdwatch.dev).

# Actor input Schema

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

Instagram @usernames or profile URLs to pull reels from

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

What to return. 'Auto-detect' reads each entry: post/reel URLs return post details, handles return that handle's posts. The explicit modes force one behaviour for every entry.

## `maxResults` (type: `integer`):

Maximum total number of dataset items across all queries.

## `maxResultsPerQuery` (type: `integer`):

Cap per individual query. 0 means no per-query cap (only Max results applies).

## `maxCommentsPerPost` (type: `integer`):

Comments mode only. Instagram serves roughly the first 15 comments of a post to logged-out clients and requires a login for the rest, so values above ~15 will not return more.

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

Profile mode only. Attach this many recent posts to each profile record for engagement analytics. Set 0 to return the profile card alone.

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

Kept for backward compatibility with older runs and saved tasks. Only consulted when Mode is 'auto': 'posts' returns media, 'profiles' returns profile records. Prefer Mode instead.

## Actor input object example

```json
{
  "queries": [
    "@natgeo"
  ],
  "mode": "profileReels",
  "maxResults": 10,
  "maxResultsPerQuery": 0,
  "maxCommentsPerPost": 15,
  "maxPostsPerProfile": 12,
  "searchType": "posts"
}
```

# Actor output Schema

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

No description

# 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 = {
    "queries": [
        "@natgeo"
    ],
    "mode": "profileReels",
    "maxResults": 10,
    "maxCommentsPerPost": 15,
    "maxPostsPerProfile": 12
};

// Run the Actor and wait for it to finish
const run = await client.actor("thirdwatch/instagram-reels-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 = {
    "queries": ["@natgeo"],
    "mode": "profileReels",
    "maxResults": 10,
    "maxCommentsPerPost": 15,
    "maxPostsPerProfile": 12,
}

# Run the Actor and wait for it to finish
run = client.actor("thirdwatch/instagram-reels-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 '{
  "queries": [
    "@natgeo"
  ],
  "mode": "profileReels",
  "maxResults": 10,
  "maxCommentsPerPost": 15,
  "maxPostsPerProfile": 12
}' |
apify call thirdwatch/instagram-reels-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thirdwatch/instagram-reels-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/vHCh6Shr09dcwjb6I/builds/PDgiLsWUdk1UVyTO7/openapi.json
