# Instagram Video Downloader: Reels, Carousels · No Expiry (`memo23/instagram-video-downloader`) Actor

Download Instagram reels, videos, carousels and photos in bulk. Returns re-hosted MP4, cover, audio and every carousel slide as permanent URLs needing no headers, unlike Instagram's own CDN links, which expire within about a day. Post URLs or shortcodes. No login. Per-file size cap

- **URL**: https://apify.com/memo23/instagram-video-downloader.md
- **Developed by:** [Muhamed Didovic](https://apify.com/memo23) (community)
- **Categories:** Social media, Videos, AI
- **Stats:** 18 total users, 16 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: 5.00 out of 5 stars

## Pricing

from $2.00 / 1,000 posts

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 Video Downloader

<p align="center">
  <img src="https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/instagram-downloader-logo.png" alt="Instagram Video Downloader" width="240" />
</p>

Download **Instagram reels, videos, carousels and photos in bulk** — and get links that still work next month. Every file is fetched during the run and re-hosted, so you get a plain URL that needs no special headers and carries no expiry. Instagram's own links go dead in about a day. No login, no cookies, no browser.

![How it works](https://raw.githubusercontent.com/muhamed-didovic/muhamed-didovic.github.io/main/assets/how-it-works-instagram-downloader.png)

### Why Use This Scraper?

- **Links that don't expire** — Instagram signs every CDN URL with a deadline. A reel measured on 2026-08-19 expired 31 hours later. This Actor stores the actual bytes, so your URL lives as long as your Apify data retention.
- **No headers, no fuss** — the returned URL opens in a browser, in a spreadsheet, in `curl`, in your ETL job. Nothing to sign, nothing to replay.
- **Every post type** — reels and video posts return MP4; carousels return every slide, including any per-slide videos; photos return the full-resolution image.
- **Highest resolution served** — Instagram lists video and image renditions out of order, so files are picked by pixel height, not by array position.
- **Audio too** — reels using a licensed track can return the track as a separate MP3.
- **You choose the tradeoff** — leave re-hosting on for permanent files, or turn it off to get Instagram's raw links instantly and for free, with their expiry timestamp stated in the row.
- **Nothing fails silently** — a file that was too big, blocked or already gone writes the reason into `notes` rather than leaving an unexplained empty field.

### Overview

This Actor takes a list of Instagram posts, downloads their media, and returns one row per post carrying permanent URLs for each file.

Files are stored in **your own run's key-value store** — your account, your retention, your data. Nothing is kept on our side.

### Supported Inputs

| Input form | Example |
|---|---|
| Reel URL | `https://www.instagram.com/reel/DcBx_I1iHZW/` |
| Post URL | `https://www.instagram.com/p/DcCUKZoAS8h/` |
| IGTV URL | `https://www.instagram.com/tv/DcBx_I1iHZW/` |
| Bare shortcode | `DcBx_I1iHZW` |

All forms can be mixed freely in the `posts` list.

**Not supported:** profile URLs, story links, hashtag pages and explore URLs. A profile URL returns an error item telling you to paste a post URL. For stories see the sibling Actor below.

### Use Cases

| Audience | What they use it for |
|---|---|
| Content teams | Archive owned or licensed posts before they are edited or deleted |
| Agencies | Deliver client campaign assets as stable links, not expiring ones |
| Media & research | Preserve reels as evidence with a URL that still resolves later |
| AI / ML teams | Build video and image datasets from public posts |
| Creators | Retrieve your own reels and carousels in full resolution |
| Automation | Feed permanent file URLs into editing, captioning or storage pipelines |

### How It Works

1. **Resolve** — every input is normalized to a shortcode, and duplicates collapse so the same reel pasted twice is downloaded once.
2. **Locate** — one request returns the post's media: the video renditions, cover, audio track and every carousel slide.
3. **Fetch** — the bytes are pulled inside the run, largest rendition first, with a per-file size cap you control.
4. **Re-host** — each file is written to your run's key-value store and the row carries its permanent URL, alongside Instagram's original link and the exact timestamp that one expires.

### Input Configuration

| Field | Type | Default | Description |
|---|---|---|---|
| `posts` | array | — (required) | Instagram post, reel or IGTV URLs, or bare shortcodes. |
| `downloadVideo` | boolean | `true` | Download the MP4 for reels, IGTV and video posts. |
| `downloadCover` | boolean | `true` | Download the post's cover / thumbnail image. |
| `downloadCarouselImages` | boolean | `true` | Download every carousel slide, images and any per-slide videos. |
| `downloadMusic` | boolean | `false` | Download the licensed audio track, for reels that use one. |
| `storeFiles` | boolean | `true` | Re-host the media. Turn off to receive only Instagram's expiring links. |
| `maxFileSizeMb` | integer | `100` | Skip any single file larger than this. Skipped files are explained in `notes`. |

Example input:

```json
{
    "posts": [
        "https://www.instagram.com/reel/DcBx_I1iHZW/",
        "https://www.instagram.com/p/DcCUKZoAS8h/"
    ],
    "downloadVideo": true,
    "downloadCover": true,
    "downloadCarouselImages": true,
    "maxFileSizeMb": 100
}
```

Links only — no bytes fetched, fastest and cheapest, but the URLs expire:

```json
{
    "posts": ["https://www.instagram.com/reel/DcBx_I1iHZW/"],
    "storeFiles": false
}
```

### Output Overview

One row per post, carrying a permanent URL and a byte count for each file stored. Posts that cannot be delivered (private, deleted, age-restricted, or not a post URL) produce a single error item with a `message` explaining why — the run itself still succeeds.

### Output Samples

Reel row (real row, trimmed):

```json
{
    "postId": "3963668990156895830",
    "shortcode": "DcBx_I1iHZW",
    "postUrl": "https://www.instagram.com/reel/DcBx_I1iHZW/",
    "postType": "reel",
    "caption": "Check out the eclipse from 50,000 feet in the air! …",
    "createdAt": "2026-08-14T16:50:37.000Z",
    "durationSeconds": 92.94,
    "authorUsername": "nasa",
    "authorFullName": "NASA",
    "videoUrl": "https://api.apify.com/v2/key-value-stores/9a840473-…/records/DcBx_I1iHZW_video.mp4",
    "videoBytes": 8162771,
    "coverUrl": "https://api.apify.com/v2/key-value-stores/9a840473-…/records/DcBx_I1iHZW_cover.jpg",
    "coverBytes": 111471,
    "audioUrl": null,
    "slides": [],
    "slideCount": 0,
    "sourceVideoUrl": "https://scontent-lax3-2.cdninstagram.com/…",
    "sourceUrlsExpireAt": "2026-08-20T21:27:40.000Z",
    "filesStored": true,
    "notes": null,
    "scrapedAt": "2026-08-19T12:10:12.781Z"
}
```

Carousel row — the `slides` array (trimmed to two of twenty):

```json
{
    "shortcode": "DcCUKZoAS8h",
    "postType": "carousel",
    "slideCount": 20,
    "slides": [
        { "index": 1, "type": "image", "imageUrl": "https://api.apify.com/v2/key-value-stores/…/records/DcCUKZoAS8h_slide1.jpg", "imageBytes": 72830, "videoUrl": null },
        { "index": 2, "type": "image", "imageUrl": "https://api.apify.com/v2/key-value-stores/…/records/DcCUKZoAS8h_slide2.jpg", "imageBytes": 70770, "videoUrl": null }
    ]
}
```

Row where a file exceeded the size cap — the cover still arrives, and `notes` says what happened:

```json
{
    "shortcode": "DcBx_I1iHZW",
    "videoUrl": null,
    "coverUrl": "https://api.apify.com/v2/key-value-stores/…/records/DcBx_I1iHZW_cover.jpg",
    "notes": ["The video exceeded the 1 MB per-file limit and was skipped — raise \"Max file size\" to include it."]
}
```

Error item (deleted post):

```json
{
    "post": "https://www.instagram.com/p/ZZZZnotreal99/",
    "error": "post_unavailable",
    "message": "Post ZZZZnotreal99 is not available — it is private, deleted, or age-restricted."
}
```

### Key Output Fields

| Field | Meaning |
|---|---|
| `videoUrl` / `videoBytes` | Permanent re-hosted MP4 and its size. Null on photo posts. |
| `coverUrl` / `coverBytes` | Permanent re-hosted cover image. |
| `audioUrl` / `audioBytes` | Permanent re-hosted audio track, when the reel uses a licensed one and `downloadMusic` is on. |
| `slides[]` | One entry per carousel slide: `index`, `type`, `imageUrl`, `imageBytes`, `videoUrl`, `videoBytes`, plus the original source URLs. |
| `sourceVideoUrl` / `sourceCoverUrl` / `sourceMusicUrl` | Instagram's own links, kept for reference. **These expire.** |
| `sourceUrlsExpireAt` | The exact moment those source links stop working, decoded from Instagram's own signature. |
| `filesStored` | Whether re-hosting ran for this row. |
| `notes` | Why a file is missing — oversize, no longer served, blocked, or a network failure. Null when everything arrived. |
| `postType` | `reel`, `carousel`, `image`, `video` or `igtv`. |

### FAQ

**Do I need to log in or provide cookies?**
No. The Actor never touches your Instagram account and only reads public posts.

**Why re-host at all — Instagram's links work fine?**
They work *today*. Every Instagram CDN URL is signed with an expiry: the reel tested for this README expired 31 hours after it was fetched, and returns 403 afterwards. Video and image links expire on different clocks, and `sourceUrlsExpireAt` reports the earlier one. If you only need the file right now, set `storeFiles: false` and skip the download entirely.

**How long do the re-hosted files last?**
As long as your Apify data retention — they live in your own run's key-value store, under your account. They are not deleted on our side because they were never on our side.

**Does it handle carousels?**
Yes. Every slide is downloaded, images and per-slide videos alike. A 20-slide carousel produces 21 files including the cover. Turn `downloadCarouselImages` off if you only want the cover.

**Why is there no audio file for my reel?**
Reels using original audio have no separate licensed track — the audio is already inside the MP4. `audioUrl` fills only for reels using a track from Instagram's music library, and only when `downloadMusic` is on.

**What if a video is huge?**
Anything over `maxFileSizeMb` (100 MB by default) is skipped and the reason is written to `notes`. The rest of the post still downloads. Raise the limit to include it.

**Do I pay twice if the same post appears twice in my input?**
No. Inputs are de-duplicated by shortcode before anything is fetched.

**What happens with a private or deleted post?**
It returns an error item explaining why, and the run continues with your other posts.

**Can I get the post's engagement stats too?**
This Actor focuses on the files. For full metadata — likes, comments, plays, tagged accounts, location — see the [Instagram Post Scraper](https://apify.com/memo23/instagram-post-scraper).

**What does it cost?**
Pay per result: one charge per post delivered, plus a small per-run start fee. No subscription.

### Support

Found a bug or need a field added? Open an issue on the Actor's **Issues** tab in Apify Console, or email <muhamed.didovic@gmail.com>.

### Additional Services

Need a custom Instagram or social-media scraper, media pipeline, or a private version of this Actor? Custom builds available — reach out at <muhamed.didovic@gmail.com>.

### Explore More Scrapers

- **[Instagram Post Scraper](https://apify.com/memo23/instagram-post-scraper)** — full metadata for any post, reel or carousel
- **[Instagram Stories & Highlights Scraper](https://apify.com/memo23/instagram-stories-highlights-scraper)** — stories and highlights, with download
- **[Instagram Transcript Scraper](https://apify.com/memo23/instagram-transcript-scraper)** — reels, posts and IGTV turned into text
- **[Instagram Reels Search Scraper](https://apify.com/memo23/instagram-reels-search-scraper)** — find viral reels by keyword
- **[Instagram Hashtag Scraper](https://apify.com/memo23/instagram-hashtag-scraper)** — top posts and reels under any hashtag
- **[TikTok Video Downloader](https://apify.com/memo23/tiktok-video-downloader)** — the same idea for TikTok, watermark-free

Browse the full portfolio: [muhamed-didovic.github.io](https://muhamed-didovic.github.io/)

### 🤖 For AI Agents & LLM Apps

**Purpose:** Download Instagram reels, videos, carousels and photos and return permanent, header-free URLs for each file, plus Instagram's original links and their expiry.

**Minimal tested input:**

```json
{ "posts": ["https://www.instagram.com/reel/DcBx_I1iHZW/"] }
```

**Output:** array of flat objects, one per post. Fields: `postId`, `shortcode`, `postUrl`, `postType`, `caption`, `createdAt`, `durationSeconds`, `authorUsername`, `authorFullName`, `videoUrl`, `videoBytes`, `coverUrl`, `coverBytes`, `audioUrl`, `audioBytes`, `slides[]` (`index`, `type`, `imageUrl`, `imageBytes`, `videoUrl`, `videoBytes`, `sourceImageUrl`, `sourceVideoUrl`), `slideCount`, `musicTitle`, `musicArtist`, `sourceVideoUrl`, `sourceCoverUrl`, `sourceMusicUrl`, `sourceUrlsExpireAt`, `filesStored`, `notes`, `inputPost`, `scrapedAt`.

**Behavior & billing:** Pay-per-event — one charge per post delivered, regardless of file count. Duplicate inputs are dropped before billing. Re-hosted URLs need no headers and do not expire; `source*Url` fields DO expire at `sourceUrlsExpireAt`. Set `storeFiles: false` to skip downloading entirely. Files over `maxFileSizeMb` are skipped with a reason in `notes`. Private, deleted and non-post URLs yield one error item each (`error`, `message`) instead of failing the run. No login or cookies required.

### ⚠️ Disclaimer

This Actor accesses publicly available data on Instagram for legitimate research, archival, and business-analysis purposes. It does not log in, bypass authentication, or access private content. Use of this Actor must comply with Instagram's Terms of Service and all applicable laws, including data-protection regulations (GDPR, CCPA, etc.). The authors are not responsible for any misuse. Users must:

- Respect rate limits and avoid overloading Instagram's infrastructure
- Not use downloaded media to violate user privacy or platform terms
- Only download content they own, have licensed, or are otherwise permitted to use
- Not republish downloaded content in violation of copyright

We do not store downloaded media; files are written directly to your own Apify key-value store for your authorized use. Instagram is a trademark of Meta Platforms, Inc.; this Actor is not affiliated with or endorsed by Instagram or Meta.

### SEO Keywords

instagram video downloader, instagram reel downloader, download instagram video, instagram media downloader, instagram downloader api, bulk instagram downloader, instagram carousel downloader, instagram photo downloader, instagram mp4 download, instagram reels download api, download instagram reels bulk, instagram video url extractor, instagram content archiving, instagram media archive, instagram video scraper, instagram igtv downloader, instagram audio downloader, instagram cover image download, instagram media export, instagram video backup, apify instagram downloader

# Actor input Schema

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

Posts, reels, IGTV or carousels to download. Accepts full URLs (`https://www.instagram.com/reel/CODE/`) or bare shortcodes — mix them freely.

## `downloadVideo` (type: `boolean`):

Download the MP4 for reels, IGTV and video posts, in the highest resolution Instagram serves.

## `downloadCover` (type: `boolean`):

Download the post's cover / thumbnail image (the still frame shown before a reel plays, or the first slide of a carousel). Returned as coverUrl plus coverBytes. Boolean, default true.

## `downloadCarouselImages` (type: `boolean`):

For carousel posts, download every slide — images and any per-slide videos. A 20-slide carousel produces 20 files, so turn this off if you only want the cover.

## `downloadMusic` (type: `boolean`):

Download the licensed audio track for reels that use one. Off by default — reels using original audio have no separate track, and the audio is already inside the MP4.

## `storeFiles` (type: `boolean`):

Fetch the media and store it, so each row carries a permanent URL that needs no special headers. Turn this OFF to get only Instagram's own links — which are faster and free, but expire roughly 24-36 hours after the run and then return 403.

## `maxFileSizeMb` (type: `integer`):

Skip any single file larger than this. Skipped files are reported in the row's `notes` field rather than silently dropped.

## Actor input object example

```json
{
  "posts": [
    "https://www.instagram.com/reel/DcBx_I1iHZW/"
  ],
  "downloadVideo": true,
  "downloadCover": true,
  "downloadCarouselImages": true,
  "downloadMusic": false,
  "storeFiles": true,
  "maxFileSizeMb": 100
}
```

# Actor output Schema

## `downloads` (type: `string`):

All download rows 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 = {
    "posts": [
        "https://www.instagram.com/reel/DcBx_I1iHZW/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("memo23/instagram-video-downloader").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/reel/DcBx_I1iHZW/"] }

# Run the Actor and wait for it to finish
run = client.actor("memo23/instagram-video-downloader").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 '{
  "posts": [
    "https://www.instagram.com/reel/DcBx_I1iHZW/"
  ]
}' |
apify call memo23/instagram-video-downloader --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,memo23/instagram-video-downloader"
        }
    }
}

```

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/piwPghZZql1jcdYcH/builds/FAeneqzdLlb9wH9ZM/openapi.json
