# Instagram Reel Scraper — All Reels by Profile, Play Counts (`memo23/instagram-reel-scraper`) Actor

Scrape every reel on any public Instagram profile, newest first, with play counts that are actually populated. Caption, likes, comments, duration, audio, co-authors, paid-partnership flag and video URL on one row. Date cut-off and per-profile limit. No login, no cookies, no browser

- **URL**: https://apify.com/memo23/instagram-reel-scraper.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Social media, AI, Agents
- **Stats:** 20 total users, 18 monthly users, 86.4% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 reels

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?

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 Reel Scraper

<p align="center">
  <img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/instagram-reel-logo.png" alt="Instagram Reel Scraper" width="180" height="180">
</p>

Every reel on any public Instagram profile, newest first, with **play counts that are actually populated**. Give it a handle, get back caption, likes, comments, play count, duration, audio, co-authors, paid-partnership flag, tagged accounts and the video URL — one row per reel. No login, no cookies, no browser.

### Why Use This Scraper?

- **Play counts on every row.** Measured on `@nasa`, 2026-08-26: 25 of 25 reels returned a populated `playCount`, from 73,766 to 14,480,933.
- **The limit is the limit.** Ask for 25 and the run pages until it has 25, then stops. Three upstream pages, 11.7 seconds, 25 unique reels, no duplicates.
- **Correct author on collab reels.** A profile's reel feed is not uniformly its own work — those same 25 `@nasa` reels carried **11 distinct owner accounts**, because a collab reel belongs to the partner and merely credits the profile you asked for. Every row is enriched with its own owner's follower count.
- **Stop at a date.** `onlyPostsNewerThan` halts paging the moment a reel falls outside your window, so you are never charged for history you did not ask for.
- **Audio, co-authors and sponsorship.** `musicTitle`, `musicArtist`, `musicIsOriginalAudio`, `coauthors`, `sponsors` and `isPaidPartnership` on every row.
- **One request per 12 reels.** Profiles resolve once and authors are memoized per run, so 200 reels from one account do not cost 200 lookups.

### Switching From Another Instagram Reel Scraper?

| What you need | How this Actor answers it |
|---|---|
| Your pipeline is keyed on `videoPlayCount` / `videoViewCount` | Both ship as aliases of `playCount` / `viewCount`, same values. Nothing to rewrite. |
| Play counts come back null or zero | `playCount` was populated on every reel measured. `countsHidden` is `true` when the creator turned counts off, so an absent number is explained rather than guessed at. |
| View counts look far lower than the app | Instagram serves `view_count` as a literal `0` on this route. Reporting it would read as "no views", so it is nulled and `playCount` is the number that matches the app. |
| A run that stops early or returns a random count | `resultsLimit` is honoured exactly, per profile. The log states how many reels came back, from how many pages, and why it stopped. |
| Follower counts that are wrong on collab reels | Each row carries the follower count of the reel's actual owner. |
| Reel audio is missing | `musicId`, `musicTitle`, `musicArtist`, `musicIsOriginalAudio`, `musicUrl`. |
| `paidPartnership` is not returned | `isPaidPartnership`, plus `sponsors[]` and `coauthors[]`. |

### Overview

The output is **reel-shaped**: one row per reel, newest first. Ask for 25 reels across two profiles and you get 50 rows, with `inputPost` on each so they stay attributable.

### Supported Inputs

| Input | Example | What you get |
|---|---|---|
| Bare handle | `nasa` | That profile's reels, newest first |
| Profile URL | `https://www.instagram.com/nasa/` | Same |
| Many at once | `["nasa", "natgeo"]` | `resultsLimit` reels **per profile** |

Private accounts and handles that do not exist return an explanatory row rather than failing the run, so one bad handle in a list of fifty does not cost you the other forty-nine.

### Use Cases

- **Creator and competitor tracking** — pull a rival's last 100 reels and watch play counts move week over week.
- **Influencer vetting** — engagement per reel against the owner's real follower count, including on collabs.
- **Sponsorship monitoring** — `isPaidPartnership` and `sponsors[]` show who is running paid campaigns.
- **Audio trend research** — `musicTitle` and `musicIsOriginalAudio` across a set of accounts.
- **Content archiving** — `videoUrl` and `thumbnailUrl` for reels published since a chosen date.

### How It Works

Each handle resolves to an account id once, then the reel feed is paged 12 at a time until your `resultsLimit` is met, the profile runs out, or a reel falls outside `onlyPostsNewerThan`. Every reel is enriched with its own owner's profile, memoized so a repeated owner costs one lookup rather than one per row.

Pure HTTP against Instagram's own JSON, no browser and no login. A profile that is private, deleted or has no reels produces an explanatory row instead of an exception, and a run that produces nothing at all fails loudly rather than delivering an empty dataset.

### Input Configuration

| Field | Type | Default | Notes |
|---|---|---|---|
| `usernames` | array | required | Handles or profile URLs. Duplicates are dropped before anything is looked up, so you are not billed twice. |
| `resultsLimit` | integer | `30` | Max reels **per profile**, newest first. |
| `onlyPostsNewerThan` | string | — | `YYYY-MM-DD`. Paging stops at the first reel older than this. |
| `skipPinnedPosts` | boolean | `false` | Skip reels pinned to the top of the profile. Pinned reels are often old, which can make newest-first ordering look wrong. |
| `includeMediaUrls` | boolean | `true` | Video, thumbnail and audio URLs. Signed Instagram CDN links, valid roughly 24–36 hours after the run. |
| `includeAuthorStats` | boolean | `true` | Owner follower / following / post counts, bio, category, public business email and phone. Memoized per run. |
| `includeHashtagsMentions` | boolean | `true` | Hashtags and @-mentions parsed from the caption. |
| `includeTaggedUsers` | boolean | `true` | Tagged accounts, co-authors and paid-partnership sponsors. |

#### Example input

```json
{
  "usernames": ["nasa"],
  "resultsLimit": 25,
  "onlyPostsNewerThan": "2026-06-01",
  "skipPinnedPosts": false
}
```

### Output Overview

One flat row per reel, 55 fields with the default toggles on. No nested arrays to flatten except `coauthors`, `sponsors`, `hashtags`, `mentions` and `taggedUsers`.

Instagram withholds the usertag list on video, so reels used to come back with an empty `taggedUsers` even when accounts were visibly tagged in them. They are now filled from a separate lookup, batched ten reels per request.

### Output Samples

A real row from `@nasa`, trimmed to the fields most runs care about:

```json
{
  "postId": "3971730051816042598",
  "shortcode": "Dcea3BiPTBm",
  "postUrl": "https://www.instagram.com/reel/Dcea3BiPTBm/",
  "postType": "reel",
  "caption": "Teamwork makes the dream work! High fives and cheers rang out both in space and on E…",
  "createdAt": "2026-08-25T19:55:51.000Z",
  "likeCount": 40868,
  "commentCount": 379,
  "playCount": 3066548,
  "viewCount": null,
  "videoPlayCount": 3066548,
  "videoViewCount": null,
  "durationSeconds": 41.05099868774414,
  "countsHidden": false,
  "isPaidPartnership": false,
  "authorUsername": "nasajohnson",
  "authorFullName": "NASA’s Johnson Space Center",
  "authorFollowerCount": 1557735,
  "coauthors": [
    "astro_annimal",
    "iss",
    "nasa"
  ],
  "hashtags": [],
  "musicTitle": "Original audio",
  "musicIsOriginalAudio": true,
  "thumbnailUrl": "https://scontent-lhr6-2.cdninstagram.com/v/t51.82787-15/784389248_18617945356026724_6029818964473376604_n.jpg?…",
  "videoUrl": "https://scontent-lhr11-1.cdninstagram.com/o1/v/t2/f2/m86/AQPY7jNyIzyetpKDGsbUOOsc_a6SxYqJzyHzDiFe9bNN5dUTFwCLyBasOsxb94eTAMiU-cFyqjqwJ5vkjEDU6JCZaWd7e_sNX85dcdI.mp4?…",
  "inputPost": "nasa"
}
```

### Key Output Fields

| Field | Notes |
|---|---|
| `playCount` | Times the reel was played. Populated on every reel measured. Mirrored as `videoPlayCount`. |
| `viewCount` | `null` by design — Instagram serves a literal `0` on this route, and `playCount` is the number that matches the app. Mirrored as `videoViewCount`. |
| `countsHidden` | `true` when the creator disabled like and view counts, so a missing number is explained rather than guessed at. |
| `authorUsername` / `authorFollowerCount` | The reel's **actual owner**, which on a collab reel is the partner account rather than the profile you requested. |
| `coauthors[]` | Joint owners credited on the reel, including the profile you asked for when it is a collab. |
| `isPaidPartnership` / `sponsors[]` | Sponsorship disclosure. |
| `musicTitle` / `musicArtist` / `musicIsOriginalAudio` | Licensed track, or the creator's own audio. |
| `durationSeconds` | Reel length in seconds. |
| `videoUrl` / `thumbnailUrl` | Signed Instagram CDN links, valid roughly 24–36 hours after the run. |
| `inputPost` | The handle you supplied, so rows from a multi-profile run stay attributable. |

### FAQ

**Does it get every reel on a profile?**
It pages newest-first until your `resultsLimit` is met or the profile runs out. Raise `resultsLimit` to go deeper; the log tells you which of the two stopped the run.

**Why do some rows show a different author than the profile I asked for?**
Collab reels are owned by the partner account and merely credit the profile. Measured on `@nasa`, 25 reels carried 11 distinct owners. Each row is enriched with its own owner's stats, and `coauthors[]` shows the credited accounts.

**Why is `viewCount` null when `playCount` has a number?**
Instagram does not populate `view_count` on this route — it returns a literal `0`. Reporting `0` would read as "no views", so it is nulled. `playCount` is the real metric.

**Do I need to log in or provide cookies?**
No. Only public profiles are read, and no account is used.

**Does it work on private profiles?**
No. A private profile returns an explanatory row rather than failing the run, so one private handle in a long list does not cost you the rest.

**Am I charged twice if I list the same profile twice?**
No. Handles are de-duplicated before anything is looked up.

**Can I restrict it to recent reels?**
Yes. `onlyPostsNewerThan` takes `YYYY-MM-DD` and stops paging at the first reel older than that date.

**Why is a media URL not loading later?**
`videoUrl` and `thumbnailUrl` are signed Instagram CDN links that expire roughly 24–36 hours after the run. Download promptly, or use the Instagram Video Downloader actor for permanent copies.

### Support

Open an issue on the Actor's Issues tab. Bug reports with a run id get looked at first.

### Additional Services

Need a custom scraper, a scheduled feed, or this data delivered somewhere specific? Get in touch through the Apify Store profile.

### Explore More Scrapers

- **[Instagram Post Scraper](https://apify.com/memo23/instagram-post-scraper)** — any single post, reel or carousel by URL or shortcode
- **[Instagram Hashtag Scraper](https://apify.com/memo23/instagram-hashtag-scraper)** — top posts and reels for any hashtag
- **[Instagram Reels Search Scraper](https://apify.com/memo23/instagram-reels-search-scraper)** — find reels by keyword rather than by profile
- **[Instagram Video Downloader](https://apify.com/memo23/instagram-video-downloader)** — permanent re-hosted MP4 and cover images that never expire
- **[Instagram Transcript Scraper](https://apify.com/memo23/instagram-transcript-scraper)** — reels turned into text

### 🤖 For AI Agents & LLM Apps

**Purpose:** Return every reel on a public Instagram profile, newest first — caption, play count, engagement, the reel owner's follower stats, co-authors, sponsorship, hashtags, audio and media URLs.

**Minimal tested input:**

```json
{ "usernames": ["nasa"], "resultsLimit": 25 }
```

**Output:** array of flat objects, one per reel. Core fields: `postId`, `shortcode`, `postUrl`, `postType`, `caption`, `createdAt`, `likeCount`, `commentCount`, `playCount` (aliased `videoPlayCount`), `viewCount` (aliased `videoViewCount`, null by design), `durationSeconds`, `countsHidden`, `isPaidPartnership`, `authorUsername`, `authorFullName`, `authorFollowerCount`, `coauthors[]`, `sponsors[]`, `hashtags[]`, `mentions[]`, `taggedUsers[]`, `musicId`, `musicTitle`, `musicArtist`, `musicIsOriginalAudio`, `thumbnailUrl`, `videoUrl`, `musicUrl`, `inputPost`, `scrapedAt`.

**Billing:** per delivered row. `resultsLimit` is the per-profile cap and doubles as the spend control. A run that returns nothing charges for nothing.

**Agent-relevant behaviour:** `authorUsername` is the reel's owner, which on a collab reel differs from the requested profile — join on `inputPost` if you need the requested handle. `viewCount` is intentionally null; use `playCount`. Media URLs expire in roughly 24–36 hours.

### ⚠️ Disclaimer

This Actor reads only publicly available Instagram data — no login, no cookies, no private content. You are responsible for using the output lawfully, including under the GDPR, the CCPA and Instagram's terms where they apply to you. Nothing here is legal advice. Media URLs point at Instagram's own CDN and the underlying content remains the property of its creators.

### SEO Keywords

instagram reel scraper, scrape instagram reels, instagram reels by profile, instagram reel play count, instagram reels api, instagram video scraper, instagram engagement scraper, instagram stats scraper, instagram metadata extractor, instagram caption scraper, instagram hashtag extractor, instagram tagged users scraper, instagram influencer data, instagram reel metrics, instagram reels export, instagram reels json, instagram reels to csv, instagram content analysis, instagram collab reels, instagram paid partnership scraper, instagram audio scraper, apify instagram reel scraper

# Actor input Schema

## `usernames` (type: `array`):

Profiles whose reels you want. Accepts a bare handle (`nasa`), a profile URL (`https://www.instagram.com/nasa/`), or a mix. Reels come back newest first. Private accounts return an explanatory row rather than failing the run.

## `resultsLimit` (type: `integer`):

How many reels to return for EACH profile, newest first. The run pages until it has this many, the profile runs out, or your charge limit is reached — whichever comes first. Default 30. A profile with fewer reels returns what it has and says so in the log.

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

Optional cut-off date, `YYYY-MM-DD` (e.g. `2026-01-01`). Reels arrive newest first, so the run stops as soon as it reaches one older than this and you are not charged for anything past the cut-off. Leave empty for no date filter.

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

Skip reels the creator has pinned to the top of their profile. Pinned reels are often old, so leaving this off can make the newest-first ordering look wrong. Default false.

## `includeMediaUrls` (type: `boolean`):

Include the video, thumbnail, audio and per-slide carousel URLs on each row. These are signed Instagram CDN links that expire about 24-36 hours after the run — download them promptly, or use the Instagram Video Downloader actor to get permanent copies.

## `includeAuthorStats` (type: `boolean`):

Include the profile's follower / following / post counts, bio, category and external link on every reel row. The profile is looked up once per run, so 200 reels from one account cost one extra request, not 200.

## `includeHashtagsMentions` (type: `boolean`):

Include arrays of the hashtags and @-mentions parsed from the caption.

## `includeTaggedUsers` (type: `boolean`):

Include people tagged in the reel, its co-authors (joint owners, shown as collab posts) and any paid-partnership sponsors, each as a separate array.

## Actor input object example

```json
{
  "usernames": [
    "nasa"
  ],
  "resultsLimit": 30,
  "skipPinnedPosts": false,
  "includeMediaUrls": true,
  "includeAuthorStats": true,
  "includeHashtagsMentions": true,
  "includeTaggedUsers": true
}
```

# Actor output Schema

## `posts` (type: `string`):

All post rows (one per post, reel or carousel) in the default dataset.

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

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

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

```

## MCP server setup

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