# Instagram Story & Highlight Saver (`thenetaji/instagram-story-highlight-saver`) Actor

Save a public Instagram account's currently-active stories and highlight media as permanent files, not just direct links that expire in about a day. Give it one or more usernames; get back every active story frame plus every highlight item, downloaded and stored. No login or cookies.

- **URL**: https://apify.com/thenetaji/instagram-story-highlight-saver.md
- **Developed by:** [The Netaji](https://apify.com/thenetaji) (community)
- **Categories:** Social media, For creators, Videos
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $2.80 / 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?

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 Story & Highlight Saver

Save a public Instagram account's currently-active stories and its highlight media as permanent files. Give it one or more usernames and get back every story frame that's live right now, plus every photo and video pinned in that account's highlights — downloaded once, stored, and given a link that doesn't expire. No login, no cookie, no session.

Stories vanish in 24 hours. Highlights are the durable half — the reason this Actor is still worth running on any given day, story or no story.

### Input

| Field | Type | Default | What it does |
|---|---|---|---|
| `profiles` | array | — | **Required.** Instagram accounts to check. |
| `saveMedia` | boolean | `true` | Downloads each item and stores it permanently. Turn off to get only Instagram's direct CDN URL instead — free, but it stops working in about 34 hours. |
| `limit` | integer | `100` | Highlights processed per account (`0` = the whole tray). Doesn't limit stories — an account's active story set is always small. |

```json
{
  "profiles": ["nasa", "natgeo"],
  "saveMedia": true,
  "limit": 100
}
```

Every account is checked for both stories and highlights in the same run — there's no mode switch. Most accounts won't have an active story most of the time; that's normal, not a failure, and the run still succeeds with whatever highlight media it found.

### Output

| Field | What it holds |
|---|---|
| `kind` | `"story"` or `"highlight"` |
| `pk` | Instagram's internal media ID |
| `media_type` | 1 = photo, 2 = video |
| `taken_at` | When the item was posted |
| `title` | Highlight name, on highlight items |
| `highlightId` | Which highlight this item came from, on highlight items |
| `expiresAt` | When this story stops being visible on Instagram, on story items |
| `width` / `height` | Resolution of the file actually saved |
| `savedFile` | Stored file: `url`, `bytes`, `sizeMb`, `contentType` — present when `saveMedia` is on |
| `directUrl` / `directUrlExpiresAt` | Instagram's own CDN link and its rough expiry — present only when `saveMedia` is off |
| `source_username` | Which account this row came from |

```json
{
  "kind": "highlight",
  "pk": "3412987456123456789",
  "media_type": 2,
  "taken_at": 1785312000,
  "title": "Artemis III",
  "highlightId": "highlight:18123023338592759",
  "width": 720,
  "height": 1280,
  "savedFile": {
    "url": "https://api.apify.com/v2/key-value-stores/.../records/3412987456123456789-1280p.mp4",
    "bytes": 5680112,
    "sizeMb": 5.418,
    "contentType": "video/mp4"
  },
  "source_username": "nasa"
}
```

### Questions

**Why are stories and highlights in one Actor?**
A story-only Actor would come back empty on most runs — stories are live for 24 hours and most accounts don't have one at any given moment. Highlights are what an account has chosen to keep permanently, so pairing the two means a run against an active account almost always returns something, and a quiet day for stories doesn't mean a quiet run.

**Does a run fail when an account has no active story?**
No. Checking an account and finding no active story is a normal, successful result — it's the single most common outcome, not an error. The run only fails when nothing could be checked at all, or when every lookup itself broke (timed out, or came back an error) with nothing to show for it. A quiet account and a broken run are different things, and this Actor never confuses one for the other.

**Does it save photos, or only video?**
Both. Some stories and highlight items are plain photos with no video attached — skipping those would mean silently dropping content, which reads as broken. Every item is saved at its best available quality, video or photo, whichever it actually is.

**What counts as one billed item?**
Every story frame and every highlight item that gets saved (or, with `saveMedia` off, returned as a direct link) is one row and one charge. A saved file adds a small per-megabyte charge on top, rounded up to the next whole MB — that part pays for the bandwidth the download uses, and `saveMedia` off skips it entirely. A run against ten accounts with no active stories and modest highlight trays might return 40 rows; a run against accounts with big highlight collections costs more because there's more to save, not because of a per-run fee.

**Can `highlight_id` in my own systems be plugged straight in?**
You don't need to — this Actor walks the tray and fetches every highlight's media itself. `highlightId` on the output is Instagram's own id, in its native `highlight:<digits>` form, there for reference and deduplication, not something you need to supply.

**Can I get a private account's stories or highlights?**
No. Public accounts only. There's no login or cookie input, and there won't be one — a signed-in session is a banned or rate-limited account waiting to happen, and this Actor doesn't take that risk with your data.

**Does a run ever finish "successful" with nothing in it?**
Only when every account it checked genuinely has nothing right now — no active story and no highlights — and every one of those checks itself succeeded. If a lookup breaks instead of coming back empty, the run fails instead of quietly reporting zero results.

### Other Instagram Actors

| Actor | Use when |
|---|---|
| [Instagram Video Downloader](https://apify.com/thenetaji/instagram-video-downloader) | You want a specific post or reel, not stories or highlights |
| [Instagram Posts & Reels Scraper](https://apify.com/thenetaji/instagram-profile-content-scraper) | You want the highlight tray as lightweight metadata (id/title/cover) instead of downloaded media |
| [Instagram Post Scraper](https://apify.com/thenetaji/instagram-post-scraper) | You want a post's engagement details, not files |

# Actor input Schema

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

Instagram accounts to pull the list from

## `saveMedia` (type: `boolean`):

Store each story and highlight photo or video as a permanent file and return its download URL. Turn off to get only Instagram's direct CDN URL, which expires roughly 34 hours after it's issued.

## `limit` (type: `integer`):

Stop after this many highlights per account (0 = process the whole tray). Doesn't limit stories — an account's active story set is always small enough to fetch in full.

## Actor input object example

```json
{
  "profiles": [
    "nasa"
  ],
  "saveMedia": true,
  "limit": 100
}
```

# Actor output Schema

## `dataset` (type: `string`):

All records scraped by this run

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

Files generated by this run

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

// Run the Actor and wait for it to finish
const run = await client.actor("thenetaji/instagram-story-highlight-saver").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 = { "profiles": ["nasa"] }

# Run the Actor and wait for it to finish
run = client.actor("thenetaji/instagram-story-highlight-saver").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 '{
  "profiles": [
    "nasa"
  ]
}' |
apify call thenetaji/instagram-story-highlight-saver --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,thenetaji/instagram-story-highlight-saver"
        }
    }
}

```

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/gui7wIhoySk1v2s3M/builds/JtqcJoA06NjtI2M5d/openapi.json
