# Instagram Stories & Highlights Scraper — Links, Mentions, Music (`afanasenko/instagram-stories-highlights-scraper`) Actor

Scrape Instagram stories and highlights from any public account: every live story with link stickers, @mentions, hashtags, music and expiry time, plus highlights with their items. Batch hundreds of usernames per run; every account gets a status row (ok, no story, private, not found).

- **URL**: https://apify.com/afanasenko/instagram-stories-highlights-scraper.md
- **Developed by:** [Andrey Afanasenko](https://apify.com/afanasenko) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 accounts

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 Stories & Highlights Scraper — Links, Mentions, Music

> **Read the stories an Instagram account has live right now, and the highlights pinned to its profile.**
> Built for people who track brands and creators: paste hundreds of usernames, get one row per story item with the link stickers, @mentions, music, and the post each story is promoting.

> **🆓 Free to start:** 15 runs a month · up to 8 accounts per run · every column the paid plan returns, nothing held back · leave the form empty for a capped demo run — three accounts, under $0.10.

### 🎯 What it does

Instagram stories vanish after 24 hours. Highlights stay on the profile until the owner removes them. This actor reads both.

Give it usernames. It returns a row for every story item and every highlight item, plus a row for every account that had nothing to show — so a list of 200 accounts comes back as 200 answers, not a silence you have to explain.

**What you get on every story item**

- **The words on the picture.** Instagram publishes the stickers and the music as data, but not the caption the author typed over the photo. On 32 of 66 frames we measured, Instagram returned no text field at all while the picture carried a whole paragraph. This actor reads the picture and gives you that text, what the picture shows, and the brands visible in it. It is a switch you can turn off.
- **The post it promotes.** Two stories in five are a reshare of a reel or a post. You get the post's permanent link, and whether it belongs to this account or someone else. Most are someone else's — that is a map of who a brand amplifies.
- **Where a link sticker really goes.** Instagram publishes a redirector and a lowercased display copy. On short links the capitals matter, so the display copy can be dead. You get the working destination.
- **Whose sound it is.** Licensed track, or a sound the account recorded itself. You also get who first published an original sound, and where in the track the story starts.
- **Who the account is.** Display name, verified badge, and the size of the original upload — no second lookup needed.

**What you won't get**

- Views, viewers, replies and reactions. Instagram shows those to the account owner only.
- Anything from a private account, unless you follow it — and this actor does not log in.
- Stories that already expired. Nobody can read those; highlights are the durable copy.

### 📦 Output sample

**What's in a row**

- **The item** — `storyId`, `code`, `url`, `takenAt`, `expiringAt`, `mediaType`, `imageUrl`, `videoUrl`, `videoDurationSec`, `mediaWidth`, `mediaHeight`
- **What's on it** — `linkStickers`, `mentions`, `hashtags`, `locations`, `musicSource`, `musicTitle`, `musicArtist`, `musicOriginalOwner`, `musicStartSec`, `musicHidden`, `musicAudioId`
- **What it promotes** — `resharedPostUrl`, `resharedPostType`, `resharedFromOwnAccount`, `crossPostedToFacebook`
- **Read off the picture** — `frameText`, `frameDepicted`, `frameBrands`, `frameLanguage`, `analysisStatus`, `analysisSkipReason`
- **Who and where from** — `inputUsername`, `ownerUsername`, `ownerFullName`, `ownerIsVerified`, `ownerAccountType`, `ownerPk`, `highlightTitle`, `highlightId`, `highlightCreatedAt`, `highlightMediaCount`, `accountStatus`, `itemKind`, `whyNotScanned`, `retryable`

One real story row, exactly as the actor writes it:

```json
{
  "inputUsername": "unbiasedscipod",
  "accountStatus": "ok",
  "retryable": false,
  "itemKind": "story",
  "storyId": "3981742998870526203",
  "code": "DdB_ilKk4j7",
  "url": "https://www.instagram.com/stories/unbiasedscipod/3981742998870526203/",
  "takenAt": "2026-09-08T15:19:35.000Z",
  "expiringAt": "2026-09-09T15:19:35.000Z",
  "mediaType": "video",
  "imageUrl": "https://scontent-atl3-2.cdninstagram.com/v/t51.82787-15/800497595_18123260936310685_6202628969955906826_n.jpg",
  "videoUrl": "https://scontent-atl3-3.cdninstagram.com/o1/v/t2/f2/m78/AQN2457ef7963JwlLb1AOWSJ.mp4",
  "videoDurationSec": 15,
  "mediaWidth": 716,
  "mediaHeight": 1274,
  "frameText": "SUNSCREEN MISINFORMATION Sunscreen has been around since the 1930s, protecting skin from the sun's ultraviolet (UV) radiation. Decades of rigorous research back it up. A wave of scary and untrue social media posts would have you believe the opposite. Swipe for five sunscreen myths that refuse to die",
  "frameDepicted": "An informational graphic featuring a wooden Pinocchio puppet with sunscreen on its long nose and cheek, accompanied by text about sunscreen misinformation.",
  "frameBrands": ["UNBIASED SCIENCE", "@unbiasedscipod"],
  "frameLanguage": "en",
  "analysisStatus": "analyzed",
  "analysisSkipReason": null,
  "linkStickers": [],
  "mentions": [],
  "hashtags": [],
  "locations": [],
  "musicTitle": "Pocketful of Sunshine",
  "musicArtist": "Natasha Bedingfield",
  "musicAudioId": "184574178871541",
  "musicSource": "licensed",
  "musicOriginalOwner": null,
  "musicStartSec": 0,
  "musicHidden": true,
  "resharedPostUrl": "https://www.instagram.com/p/DdB-YuJloux/",
  "resharedPostType": "post",
  "resharedFromOwnAccount": true,
  "crossPostedToFacebook": true,
  "highlightId": null,
  "highlightTitle": null,
  "highlightCreatedAt": null,
  "highlightMediaCount": null,
  "ownerUsername": "unbiasedscipod",
  "ownerPk": "39150550684",
  "ownerFullName": "Dr. Jess Steier | Unbiased Science",
  "ownerIsVerified": true,
  "ownerAccountType": 3
}
```

An account with nothing live comes back too, as a short row: `itemKind` is `status`, `accountStatus` says what happened, and `whyNotScanned` says it in plain words.

### ⚡ Quick start

1. Open the actor and pick **Mode 1 — Capture live stories**.
2. Paste your usernames, one per line. `@` signs and profile links both work.
3. Press **Start**. Results appear row by row while the run is going.
4. Export as CSV, Excel or JSON, or read the dataset from the API.

Leave the accounts field empty and the run does a small demo on three well-known public accounts, capped, so you can see the shape of the output first. The results say it was a demo.

### ⭐ Choose your mode

| Mode | You give it | You get back | Lives for |
|---|---|---|---|
| **1 — Live stories** | Usernames | Every story up right now | 24 hours |
| **2 — Highlights** | Usernames | Pinned highlights, and their items | Until removed |
| **3 — By link** | A story or highlight link | That one item, in full | — |

#### 🎯 Mode 1: Capture live stories

Reads what each account has up right now. One read covers every story that account has live — one story or twenty, the price is the same.

Use it for daily tracking: run it on a schedule and you build a record of something that otherwise disappears.

#### 🎯 Mode 2: Capture highlights

Reads the highlights pinned to a profile. You get each highlight — cover, title, creation date, item count — and, if you ask, every item inside it.

Highlights do not expire, so this is the way to read a story an account published months ago.

#### 🎯 Mode 3: Fetch a story or highlight by link

Paste a story or highlight link you already have. Useful when you found one story and want its details, not a whole account.

### 🧭 When to use it

- **Competitor tracking.** See what a rival posts to stories daily, which reels they push, and which partners they tag.
- **Influencer vetting.** Check whether a creator's stories carry affiliate links, and whose posts they reshare.
- **Affiliate and merch research.** Link stickers are where the money is asked for. This actor gives you the working URL.
- **Sound and trend research.** Original sounds are how trends start. You get the owner, the track, and the moment the story enters it.
- **Archiving.** Stories are gone in 24 hours. A daily run keeps the record.

### 🛠 Input

| Field | What it does |
|---|---|
| **Operation Mode** | Which of the three jobs to run. Pick this first — the rest of the form changes with it. |
| **Accounts** | Usernames, one per line. `@name`, `name`, or a profile link. Used by modes 1 and 2. |
| **Max accounts to read** | A ceiling on how many accounts one run touches, so a long list cannot surprise you on cost. |
| **Open each highlight** | Mode 2 only. On, you get every item inside each highlight. Off, you get the highlight covers and titles only, and pay less. |
| **Max highlights per account** | Mode 2 only. Reads the newest highlights first. |
| **Story or Highlight Links** | Mode 3 only. Paste the links you already have. |
| **Read the text and the subject off each picture** | On by default. Fills in four columns no Instagram field carries. Charged per frame — turn it off and it never is. |
| **Max frames analyzed per account** | How many frames per account get read. Default 3, newest first. Frames past the ceiling still arrive, with the reason named. |
| **Skip private accounts** | On by default, and then a private account is skipped before any work and never charged. Turn it off and the run reads it like any other account — which means it is charged, even though it comes back empty. |

### 💰 How much will scraping Instagram stories cost?

You pay per **account read**, per **highlight opened**, and per **frame analyzed**. Nothing else.

| What | Price |
|---|---|
| One account read — covers every live story it has | $0.010 |
| One highlight opened, with its items | $0.0125 |
| One frame read off the picture | $0.0115 on a paid plan, dropping to $0.010 at higher volume ($0.0125 on the free plan) |

- 100 accounts in Mode 1, picture analysis **off** — **$1.00**, however many stories they have between them.
- 100 accounts in Mode 1, analysis **on** at the default 3 frames each — **$4.00 to $4.45**, depending on your plan.
- 20 accounts in Mode 2, 5 highlights each, analysis off — **$1.45**.
- An account that is private, misspelled, deleted, or skipped before the read — **$0.00**.

Picture analysis is the only part that scales with rows rather than accounts. If you are watching a long list and only need the metadata, turn it off — the other columns are unchanged.

**What is never charged**

| Situation | Why |
|---|---|
| Private account, with **Skip private accounts** on | It is skipped before any work is done. |
| Username misspelled or deleted | There was nothing to read. |
| Account skipped by a plan limit | It was skipped before the read. |
| The read failed on our side | You should not pay for our retry. |
| A highlight list read without opening it | Only opened highlights are charged. |
| A frame the analysis skipped, or could not read | You get the row without those four columns, and the reason in `analysisSkipReason`. |

An account with no story live right now still counts as one read. The read happened, and the answer "nothing is up" is a real answer — that is the point of tracking something that expires.

### 🆓 Free vs paid plan

| | Free | Paid |
|---|---|---|
| Runs per month | 15 | Unlimited |
| Accounts per run | 8 | Your own ceiling |
| Highlights per account | 2 | Your own ceiling (default 10) |
| Frames analyzed | 3 per run, in total | Up to 50 per account |
| Columns returned | All of them | All of them |

The free plan is a smaller run, not a thinner one. Every column above comes back on both plans — including the four read off the picture, on the three frames a free run analyzes. Every other frame arrives complete except for those four, and says so in `analysisSkipReason` rather than leaving you to guess.

⚠️ The frame allowance is **per run**, not per account — three frames across the whole run, whatever "Max frames analyzed per account" says.

When a limit trims your run, the results say so: you get a row for each account that was held back, naming it, so you never have to guess which part of your list was skipped.

### 🧪 Filter recipes

The actor returns everything and lets you filter in your own tool. A few that pay off:

- **Affiliate links only** — keep rows where `linkStickers` is not empty. About one story in thirteen carries one.
- **Who they amplify** — keep `resharedFromOwnAccount = false`. That is the collaboration map.
- **Reel pushes** — `resharedPostType = reel`. Two thirds of reshares are reels.
- **Trend-setters** — `musicSource = original`, then group by `musicOriginalOwner`.
- **Live now** — sort by `expiringAt`. The soonest to expire is the oldest story still up.
- **Accounts worth a closer look** — `accountStatus = ok` and `itemKind = story`, then count rows per `ownerUsername`.

### 📡 Live status & storage records

While a run is going, the key-value store holds a self-refreshing **Live Status** page showing progress.

When the run ends, five records are written:

| Key | What's in it |
|---|---|
| `RUN_SUMMARY` | Accounts requested, read, with stories, private, not found; items returned; what was charged, per event. |
| `USER_MESSAGE` | Plain-language explanation whenever a run returned no rows or stopped early. |
| `FREE_LIMITS_APPLIED` | Which free-plan ceilings this run hit, and how much each held back. |
| `SKIPPED_ACCOUNTS` | Every account that produced nothing, with the reason. |
| `API_USAGE` | Request count for this run, grouped by operation. |

### 🤖 Programmatic / API use

Start a run and read its dataset with the Apify API or any client library.

```bash
curl -X POST "https://api.apify.com/v2/acts/afanasenkoa~instagram-stories-highlights-scraper/runs?token=$APIFY_TOKEN" \
  -H 'Content-Type: application/json' \
  -d '{"operationMode":"storiesByUsername","usernames":["natgeo","nasa"],"maxAccounts":50}'
```

The actor is also reachable from AI agents through Apify's MCP server, so an assistant can call it directly.

### 💡 Tips & Best Practices

- **Run it on a schedule.** Stories expire in 24 hours. A daily run is the only way to build a record; a one-off run captures a single moment.
- **Expect empty answers, and read them.** Measured on 54 real accounts, only 42.6% had a story live at that minute. An account with nothing up is normal, not a failure.
- **Use Mode 2 for history.** Highlights are the archive. If an account keeps its stories in highlights, you can read months back.
- **Turn off "Open each highlight" for a survey.** Covers and titles alone tell you what an account keeps pinned, and cost far less.
- **Watch `expiringAt`, not `takenAt`, for what is still live.** Each story carries its own expiry.

### 🎥 Video walkthrough

New to Apify? These two short official videos cover everything this actor needs:

- [Schedule your Actor](https://www.youtube.com/watch?v=8FCPjHBjNbo) — set it to run daily, which is what stories require.
- [Integrations](https://www.youtube.com/watch?v=DwbnQhCcxaU) — push results straight into Google Sheets, Slack or your own webhook.

### ❓ FAQ

**How do I download Instagram stories in bulk?**
Paste your usernames into Mode 1 and run it. Each row carries `imageUrl` and `videoUrl` for the item, so your tool can fetch the files.

**Is there a free way to scrape Instagram stories?**
Yes. The free plan gives 15 runs a month, up to 8 accounts per run, with every column included. Leave the form empty for a demo run: three accounts, capped, under $0.10.

**Can I use the Instagram API instead?**
Instagram's own API returns stories for accounts you own or manage, not for accounts you follow or research. That is the gap this actor fills.

**What are the alternatives to this actor?**
Other Store actors return the story files. This one adds the reshared post behind each story, the working destination of link stickers, and who owns an original sound.

**Why did an account come back with no rows?**
Because it had no story live at that moment. Stories last 24 hours, so this is the common case. The row says so in `whyNotScanned`.

**Do you read private accounts?**
No. The actor does not log in, so a private account publishes nothing it can read. With **Skip private accounts** on — the default — it is skipped before any work and never charged. Turn that off and the account is read like any other, and charged like any other, even though it returns nothing.

**Why is a link sticker's URL different from what I see in the app?**
Instagram wraps every link in a redirector and publishes a lowercased display copy beside it. On short links the capitals matter, so the display copy can be a dead link. This actor decodes the real destination and removes Instagram's own click tracking. The wrapper is kept in `redirectUrl`.

**Why is `musicTitle` empty when `musicArtist` is filled?**
Because the sound is the account's own recording, not a licensed track. Instagram gives those no title. `musicSource` tells you which of the two you are holding, and `musicOriginalOwner` names who first published it.

**What is `ownerAccountType`?**
Instagram's own numeric code for the kind of account. It is passed through exactly as received. The code has more than two values and no published meaning, so translating it into words here would be a guess printed as a fact.

**How current is `expiringAt`?**
It is each item's own expiry, 24 hours after it was posted. Instagram also publishes a tray-level expiry for the whole account; that one is the last story's, so this actor does not use it for individual items.

**Can I run this on a schedule?**
Yes. Apify schedules run it daily, hourly, or on whatever cron you set, and results land in the same dataset format every time.

**Does a run stop if one account fails?**
No. Each account is handled on its own. A failure becomes a row with the reason and a `retryable` flag, and the rest of the list continues.

### 🔗 Other Instagram actors (same author)

| Actor | What it does |
|---|---|
| [Instagram Profile Scraper](https://apify.com/afanasenkoa/instagram-profile-scraper) | Full profile data with filters — bio, counts, contacts, quality signals. |
| [Instagram Email Scraper](https://apify.com/afanasenkoa/instagram-email-scraper) | Emails, phone numbers and websites accounts publish. |
| [Instagram Post Likers Scraper](https://apify.com/afanasenkoa/instagram-post-likers-scraper) | The accounts that liked or commented on a post. |
| [Instagram Followers Scraper](https://apify.com/afanasenkoa/instagram-followers-scraper) | Follower and following lists for any public account. |
| [Instagram Follower Tracker](https://apify.com/afanasenkoa/instagram-follower-tracker) | Watches an account and reports who joined and who left. |
| [Instagram Reel Transcript](https://apify.com/afanasenkoa/instagram-reel-script-extractor) | On-screen text, hooks and transcripts from reels. |
| [Instagram Related Profiles](https://apify.com/afanasenkoa/instagram-related-profiles-scraper) | The accounts Instagram suggests next to a profile. |
| [Instagram Influencer Search](https://apify.com/afanasenkoa/instagram-influencer-search) | Finds creators by niche, size and engagement. |

### 🛟 Support & feedback

1. **Something wrong with a run?** Open an issue on this actor's page and paste the run ID. Every run writes a `USER_MESSAGE` record explaining what happened — quoting it helps.
2. **Need a column that isn't here?** Ask. Several columns in this actor exist because someone asked for them.
3. **Works for you?** A review on the actor page is the single most useful thing you can do for it.

### ⚖️ Is it legal to scrape Instagram stories?

This actor reads only what Instagram shows to anyone without logging in. It does not use an account, does not bypass a login, and cannot see private profiles.

Courts in the United States have held that collecting publicly available data is not unauthorised access under the Computer Fraud and Abuse Act — the *hiQ Labs v. LinkedIn* line of cases. That is not the whole picture, and it is not legal advice.

Public does not mean unrestricted. Personal data about identifiable people is regulated by the GDPR in Europe and by similar laws elsewhere, whoever collected it. You need your own lawful basis to store and use it, and you are the data controller for whatever you export.

Apify's guidance on this is worth reading: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

# Actor input Schema

## `operationMode` (type: `string`):

Select what the run should collect. The fields you need to fill in below depend on this choice.

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

Instagram usernames or profile links, one per line — for example natgeo, or https://www.instagram.com/natgeo/. Used by Mode 1 and Mode 2. Leave it empty and the run does a small capped demo on three well-known accounts so you can see the output shape first; it costs under $0.10 and says in the results that it was a demo. A private account, a deleted account, and a misspelled name cannot be read; each one comes back as its own free row naming the account and the reason.

## `maxAccounts` (type: `integer`):

Hard ceiling on how many accounts this run reads, across Mode 1 and Mode 2 — each account that is successfully read is one paid event ($0.01), and that one charge covers every live story the account has, whether it is one or twenty. An account that was read and had nothing live is still a read, so it is charged. Accounts that turn out to be private, missing or unreadable are not charged. Free plan ceiling: 8 accounts regardless of this value. 0 = unlimited. Default 100.

## `includeHighlightItems` (type: `boolean`):

When on, every highlight is opened and its items are returned. When off, you get the highlight list only — cover, title, creation date and item count — which is enough to see what an account keeps, and costs nothing beyond the account charge.

## `maxHighlightsPerAccount` (type: `integer`):

How many highlights to open per account, newest first. Each opened highlight is one paid event ($0.0125), and one commonly holds twenty to thirty items. Accounts often keep more than ten; anything past this ceiling comes back as a row naming what was left unopened, so nothing disappears silently. Applies only when "Open each highlight" is on. On the free plan at most 2 highlights per account are opened, whatever you set. 0 = unlimited. Default 10.

## `storyUrls` (type: `array`):

Links to a story, a highlight, or a shared story, one per line. Accepts the three forms Instagram hands out: a story link, a highlight link, and the short share link that starts with /s/. Each link is resolved to the account behind it and that account is then read, so a link to one story returns everything that account has live.

## `analyzeFrames` (type: `boolean`):

Instagram publishes a story's stickers and music as data, but not the words the author typed over the photo — on 32 of 66 measured frames Instagram returned no text at all while the picture carried a whole paragraph. With this on, each frame is read by an image model and four columns are filled in: the text on the picture, what the picture shows, the brands visible in it, and the language of the text. Each frame that comes back readable is one paid event ($0.0115 on a paid plan, $0.0125 on the free one, dropping to $0.010 at higher volume), on top of the account charge. Frames skipped by a cap or that come back unreadable are delivered without those columns and are not charged. A default run of 100 accounts with 3 frames each costs $4.00 to $4.45 with this on, against $1.00 with it off.

## `maxAnalyzedPerAccount` (type: `integer`):

How many frames per account are read by the model, newest first. This is what keeps the bill predictable on accounts that post a lot: at 32 stories an uncapped account would cost $0.40 by itself. Frames past this ceiling are still delivered, with the reason named in the analysis columns. Free plan: at most 3 frames per run in total, regardless of this value. 0 = unlimited. Default 3.

## `skipPrivate` (type: `boolean`):

Private accounts publish nothing that can be read without following them. Leaving this on skips them before any work is done, so they are never charged. Turning it off makes the run read a private account like any other, which means it is charged for the read even though it comes back empty.

## Actor input object example

```json
{
  "operationMode": "storiesByUsername",
  "usernames": [],
  "maxAccounts": 100,
  "includeHighlightItems": true,
  "maxHighlightsPerAccount": 10,
  "storyUrls": [],
  "analyzeFrames": true,
  "maxAnalyzedPerAccount": 3,
  "skipPrivate": true
}
```

# Actor output Schema

## `liveStatus` (type: `string`):

No description

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

No description

## `runSummary` (type: `string`):

No description

## `skipped` (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 = {
    "operationMode": "storiesByUsername"
};

// Run the Actor and wait for it to finish
const run = await client.actor("afanasenko/instagram-stories-highlights-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 = { "operationMode": "storiesByUsername" }

# Run the Actor and wait for it to finish
run = client.actor("afanasenko/instagram-stories-highlights-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 '{
  "operationMode": "storiesByUsername"
}' |
apify call afanasenko/instagram-stories-highlights-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,afanasenko/instagram-stories-highlights-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/Gm6HyYGnTBqZMxe7d/builds/LxyYmHXJ8h2qGYube/openapi.json
