# Instagram Video Downloader - Reels & Posts, No Login (`benthepythondev/instagram-video-downloader`) Actor

Returns direct MP4 links for public Instagram reels, video posts and carousels: the file with sound, every video-only quality up to 1080p, the audio track, thumbnail, length, caption, author, date and likes. On request each file is stored under a link that does not expire. No login, no cookies.

- **URL**: https://apify.com/benthepythondev/instagram-video-downloader.md
- **Developed by:** [Ben](https://apify.com/benthepythondev) (community)
- **Categories:** Social media, Videos, Automation
- **Stats:** 22 total users, 15 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.70 / 1,000 post with videos

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

Returns the video files behind public Instagram links, without a login or cookies. Paste links to reels, posts or /tv/ videos and get one row per link: the MP4 with sound, every quality up to 1080p, the sound alone, the thumbnail, the length, and the post's caption, author, date and likes. A carousel gives one entry per video. On request each file is copied into the run's storage, where its link no longer depends on Instagram's.

**Price:** $2.00 per 1,000 posts with video on the Apify Free plan, down to $1.70 from the Gold plan up, counted per post and not per video in a carousel. A link without a video, or one that is not public, comes back with the reason and costs nothing. Storing files is optional and costs $0.0004 per megabyte stored, down to $0.00034. Export to JSON, CSV or Excel, run on a schedule, call via API, or connect to Make, Zapier or n8n.

### 🔎 What is the Instagram Video Downloader?

Instagram's page for a post loads everything about it in one request. This Actor makes that request the way a visitor's browser does, once per link, and reads the file links out of the answer. No browser is started: a run needs 512 MB of memory.

What Instagram hands a visitor for a video, as measured on October 6, 2026:

- **One MP4 with sound.** H.264 video with AAC sound, 720 pixels on the short side in all 25 files we checked. This is `videoUrl`.
- **Up to eight renditions without sound,** from 240p to 1080p, each a file of its own with its size in bytes. 21 of 24 reels in our test had a 1080p rendition. These are `qualities`.
- **The sound alone,** as `audioUrl`. A 1080p rendition and the sound join into one file with `ffmpeg -i video.mp4 -i audio.mp4 -c copy joined.mp4` (tested with ffmpeg 7.1).
- **Links that expire.** Each link names its own end. For the MP4 with sound it was 32 to 36 hours ahead in our test of 24 reels; the row gives it as `expiresAt`.

#### What data does it extract?

- **Files:** `videoUrl`, `audioUrl`, `thumbnailUrl`, `expiresAt`, and per video `qualities` (label, width, height, bitrate, bytes, link)
- **Video:** `durationSeconds`, `originalWidth`, `originalHeight`, `hasAudio`, `slide` (its place in a carousel)
- **Post:** `shortCode`, `postUrl`, `postType` (reel, video, carousel or image), `caption`, `takenAt`, `likes`, `comments`, `videoCount`
- **Author:** `ownerUsername`, `ownerFullName`, `isVerified`
- **Stored copy** (with `saveFiles`): `savedUrl`, `savedBytes`, `storedMegabytes`
- **Outcome:** `status` and, when there is no video or a file was not stored, `statusReason`

#### What users of Instagram downloaders report, and what this Actor does

The issue pages and listings of the three most used Instagram video downloaders on Apify were read on October 6, 2026. The issue pages are short; the listings name the rest themselves.

| Reported or stated there | Here |
|---|---|
| "Degenerate run, no taken_at, no likes" | All 30 rows with video in our tests carried the date, likes, comments, caption, author, length and thumbnail. A post Instagram does not show comes back as `not_found`, not as an empty row |
| "Rate limit on first run?" | 24 links were read in 9 seconds on Apify without a refusal. A refused request is repeated through a fresh visitor up to five times; a link that still gets no answer is a `failed` row without a charge |
| Instagram's links stop working after hours or a day | `expiresAt` says when. With `saveFiles` the file is copied into the run's key-value store and `savedUrl` points there |
| One file link per video | Every rendition Instagram lists is in the row, with its size, next to the file with sound and the sound alone |
| A stored file is charged per file, whatever its size | Stored megabytes are charged, and `storedMegabytes` shows the number for each row. The reels in our test ranged from 0.6 to 96 MB |

### ⬇️ Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `postUrls` | array | | Links to reels, posts or /tv/ videos (`/reel/…`, `/p/…`, `/tv/…`), or bare shortcodes |
| `saveFiles` | boolean | false | Copies each video's MP4 with sound into the run's key-value store and adds its link as `savedUrl` |

A post named twice is read once. An empty input reads nothing and costs nothing.

#### Example input

Three links, links only:

```json
{
  "postUrls": [
    "https://www.instagram.com/reel/DeC12b5uha9/",
    "https://www.instagram.com/p/Dd1e6WyCCLZ/",
    "DeCPVhERA8e"
  ]
}
```

The same with stored files:

```json
{
  "postUrls": ["https://www.instagram.com/reel/DeC12b5uha9/"],
  "saveFiles": true
}
```

#### Coming from another downloader?

The link fields `instagram_urls`, `posts`, `reelUrls`, `urls` and `startUrls` are read like `postUrls`, and `storeFiles` like `saveFiles`. Storing is off here unless one of the two is set to true.

### ⬆️ Output

A reel (links and the caption are shortened here, and six of the eight renditions are left out):

```json
{
  "status": "ok",
  "statusReason": null,
  "input": "https://www.instagram.com/reel/DeC12b5uha9/",
  "shortCode": "DeC12b5uha9",
  "postUrl": "https://www.instagram.com/reel/DeC12b5uha9/",
  "postType": "reel",
  "ownerUsername": "ted",
  "ownerFullName": "TED Talks",
  "isVerified": true,
  "caption": "Life doesn’t work in straight lines — and according to Grammy-winning musician @JacobCollier, neither does music. …",
  "takenAt": "2026-10-03T19:45:06+00:00",
  "likes": 22034,
  "comments": 177,
  "videoCount": 1,
  "videoUrl": "https://scontent-fra3-1.cdninstagram.com/…",
  "audioUrl": "https://scontent-fra3-2.cdninstagram.com/…",
  "thumbnailUrl": "https://scontent-fra3-1.cdninstagram.com/…",
  "durationSeconds": 45.21,
  "expiresAt": "2026-10-08T01:36:31+00:00",
  "savedUrl": null,
  "storedMegabytes": 0,
  "videos": [
    {
      "slide": 1,
      "videoUrl": "https://scontent-fra3-1.cdninstagram.com/…",
      "audioUrl": "https://scontent-fra3-2.cdninstagram.com/…",
      "thumbnailUrl": "https://scontent-fra3-1.cdninstagram.com/…",
      "durationSeconds": 45.21,
      "originalWidth": 1080,
      "originalHeight": 1920,
      "hasAudio": true,
      "expiresAt": "2026-10-08T01:36:31+00:00",
      "qualities": [
        { "label": "1080p", "width": 1080, "height": 1920, "bitrate": 996263, "bytes": 5628887, "url": "https://scontent-fra3-1.cdninstagram.com/…" },
        { "label": "720p", "width": 720, "height": 1280, "bitrate": 721339, "bytes": 4075569, "url": "https://scontent-fra3-1.cdninstagram.com/…" }
      ],
      "savedUrl": null,
      "savedBytes": null
    }
  ],
  "scrapedAt": "2026-10-06T17:08:07.585631+00:00"
}
```

The columns `videoUrl`, `audioUrl`, `thumbnailUrl`, `durationSeconds`, `expiresAt` and `savedUrl` are those of the post's first video, which is all a reel has. `videos` lists every video of the post: a carousel of nine videos gave nine entries with `slide` 1 to 9, and a carousel of two photos and a video one entry.

A link that leads nowhere:

```json
{
  "status": "not_found",
  "statusReason": "Not public: it does not exist, was deleted, is private, or Instagram shows it to logged-in users only.",
  "input": "AAAAAAAAAAA",
  "shortCode": "AAAAAAAAAAA",
  "postUrl": "https://www.instagram.com/p/AAAAAAAAAAA/",
  "videoCount": 0,
  "videoUrl": null,
  "videos": []
}
```

The other statuses without a charge are `not_video` (a photo or a carousel of photos; the row still carries the post's caption, author and picture), `invalid_link` (no post link and no shortcode, for example a profile link) and `failed` (Instagram did not answer). The run also writes a `SUMMARY` record with the number of rows per status.

### 💰 What a run costs

| Apify plan | Per 1,000 posts with video | Per megabyte stored (only with `saveFiles`) |
|---|---|---|
| Free | $2.00 | $0.0004 |
| Bronze | $1.90 | $0.00038 |
| Silver | $1.80 | $0.00036 |
| Gold, Platinum, Diamond | $1.70 | $0.00034 |

Apify's standard start event ($0.00005 per GB of memory) is the only other charge; proxies are included. A megabyte is 1,000,000 bytes, and each stored file is rounded up to a full one: the 6.4 MB reel above is 7 megabytes, $0.0028 on the Free plan, on top of its row. The median reel in our test was 9.7 MB. Set the run's maximum charge and the Actor stops at it with the rows it has saved: with a limit of $0.0101 a test run delivered two reels with their files and left the third, which no longer fitted, out.

### 💾 Stored files

With `saveFiles` the MP4 with sound of every video is fetched during the run and written to the run's default key-value store, as `<shortCode>.mp4`, or `<shortCode>_<slide>.mp4` when a post has several videos. `savedUrl` is the link of that record.

- **How long it lasts:** as long as the run's storage is kept. Apify removes a run's unnamed storages after the data retention time of your plan; the files count towards your storage like any other record.
- **Size limit:** a file larger than an eighth of the run's memory is not stored: 64 MB at the default 512 MB, 512 MB at 4 GB. Its row keeps Instagram's links and `statusReason` says so. A 96 MB reel was stored in a run started with 1 GB.
- **What is stored:** the MP4 with sound. Thumbnails and the renditions without sound are returned as links only.

### ⏱️ Measured (October 6, 2026)

Runs on Apify at the default 512 MB, connecting directly, from start to finish. Every run ended as succeeded and charged exactly the rows with a video and the megabytes it stored.

| Run | Rows | Time |
|---|---|---|
| One reel link (the default input) | 1 | 3.6 s |
| 9 mixed entries: six reels, a dead link, a link to another site, one reel twice | 8 (6 with video) | 6.6 s |
| 24 reel links | 24 | 8.9 s |
| 3 links with `saveFiles`: 3 files, 35 MB | 3 | 6.7 s |

A run of 8 links with `saveFiles` that was aborted after five seconds, with seven rows saved, and started again continued behind them: 8 rows at the end, none twice, every file complete, 77 MB stored and charged once.

### 🤖 For AI agents

Smallest useful call:

```json
{"postUrls": ["https://www.instagram.com/reel/DeC12b5uha9/"]}
```

Each row is one link. `status` is `ok` when the post has a video; then `videoUrl` is an MP4 with sound that can be fetched without headers until `expiresAt`, `durationSeconds` is its length and `caption`, `ownerUsername`, `takenAt` and `likes` describe the post. For a carousel read `videos`. Add `"saveFiles": true` when the file is needed later than a day from now and read `savedUrl`. Any other `status` means no video; `statusReason` says why and nothing is charged. No credentials are needed.

### 💡 Use cases

- 🎬 **Repurposing and editing:** pull your own or licensed reels in the best quality Instagram keeps.
- 🗂️ **Archives:** store campaign videos with their caption, date and numbers before they are edited or deleted.
- 🧠 **Datasets for models:** video and audio files of public posts with their metadata; the sound alone for speech work.
- 🔁 **Automation:** hand `videoUrl` or `savedUrl` to a transcription, captioning or publishing step in Make, Zapier or n8n.

### ⚠️ Limits, stated plainly

- **Public posts only.** A private, deleted or age-restricted post is a `not_found` row.
- **Links only as input.** No profiles, stories, highlights or hashtags. The [Instagram Reels Scraper](https://apify.com/benthepythondev/instagram-reels-scraper) lists an account's reels.
- **No play counts.** Instagram shows a visitor the plays on an account's reels tab, not on the single post; the Reels Scraper returns them.
- **The file with sound is 720 pixels on its short side.** Higher resolutions come without sound and have to be joined with `audioUrl`.
- **Some reels are silent for visitors.** Instagram mutes reels with certain licensed music for anyone who is not logged in: `hasAudio` is false, `audioUrl` is empty and the MP4 has no sound. That was 4 of 24 reels in our test.
- **Instagram's links expire.** The file with sound named an end 32 to 36 hours ahead in our test, the renditions without sound and the thumbnail about four days. We read the time from the link and did not wait for it.
- **Photos are not downloaded.** A photo post is a `not_video` row.
- **No comments.** The [Instagram Comments Scraper](https://apify.com/benthepythondev/instagram-comments-scraper) reads them.
- **Rows can be large.** A reel's row is about 12 KB because of its links; the nine-video carousel was 76 KB.
- **A run that reads mostly links without video stops itself:** after 50 such rows plus four for every row with video.

### ❓ FAQ

**Do I need an Instagram account or cookies?** No. The Actor reads what Instagram shows a visitor who is not logged in.

**Which links work?** Reels (`/reel/…`, `/reels/…`), posts (`/p/…`), /tv/ videos, with or without the account name in the link, and bare shortcodes.

**How do I get 1080p with sound?** Take the first entry of `qualities` and `audioUrl`, and join them: `ffmpeg -i video.mp4 -i audio.mp4 -c copy joined.mp4`. The file under `videoUrl` already has sound, at 720 pixels.

**How long do the links work?** `expiresAt` names the end of `videoUrl`, about a day and a half after the run in our test. Fetch the file before that, or turn on `saveFiles`.

**What does `saveFiles` cost?** $0.0004 per megabyte on the Free plan, so about $0.004 for a 10 MB reel, on top of the $0.002 for its row. `storedMegabytes` in each row is the number that was charged.

**Why is a link not charged?** Because it gave no video: the post is a photo, it is not public, the entry is no post link, or Instagram did not answer. The row says which.

**What does a carousel cost?** One post, whatever the number of videos in it. With `saveFiles` each of its video files is stored and its megabytes are charged.

**How do I call it from code?** With the Apify API or the Python and JavaScript clients; every run returns a dataset you can fetch as JSON or CSV. It also works as a tool through Apify's MCP server.

**Is it legal to download Instagram videos?** The Actor reads only what Instagram shows publicly to any visitor and does not log in. The videos belong to their creators: download what you own or have the right to use, and mind that captions and account names can be personal data under GDPR, CCPA and similar rules. Instagram's terms apply to you as well. If in doubt, ask a lawyer.

### 🔗 You might also like

- [Instagram Reels Scraper](https://apify.com/benthepythondev/instagram-reels-scraper): an account's reels with plays, likes and captions
- [Instagram Posts Scraper](https://apify.com/benthepythondev/instagram-posts-scraper): an account's posts, newest first
- [Instagram Post Details Scraper](https://apify.com/benthepythondev/instagram-post-details-scraper): full data of single posts by link
- [Instagram Comments Scraper](https://apify.com/benthepythondev/instagram-comments-scraper): comments under posts and reels
- [Instagram Profile Scraper](https://apify.com/benthepythondev/instagram-profile-scraper): followers, bio and links of accounts

**Keywords:** instagram video downloader, instagram reel downloader, download instagram reels, instagram mp4 link, instagram video url, instagram reels api, instagram carousel video downloader, instagram audio extractor, instagram thumbnail, instagram video without login, save instagram video, instagram video 1080p, instagram reel to mp4, bulk instagram downloader, instagram downloader api

# Actor input Schema

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

Links to Instagram reels, posts or /tv/ videos (instagram.com/reel/…, /p/…, /tv/…) or bare shortcodes. Every link gives one row: with the video file links when the post has a video, one entry per video for a carousel; with the reason when it has no video or is not public, and then without a charge. Profiles, stories and hashtag pages are not read.

## `saveFiles` (type: `boolean`):

Copies each video's file with sound into the run's key-value store and adds its link as savedUrl. Instagram's own links expire after about a day; the stored link works as long as the run's storage is kept. Charged per megabyte stored, and slower. A file larger than an eighth of the run's memory (64 MB at 512 MB) is not stored; its row says so and keeps Instagram's links.

## Actor input object example

```json
{
  "postUrls": [
    "https://www.instagram.com/reel/DeC12b5uha9/"
  ],
  "saveFiles": false
}
```

# Actor output Schema

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

No description

## `files` (type: `string`):

No description

## `summary` (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 = {
    "postUrls": [
        "https://www.instagram.com/reel/DeC12b5uha9/"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("benthepythondev/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 = { "postUrls": ["https://www.instagram.com/reel/DeC12b5uha9/"] }

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

```

## MCP server setup

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