Instagram Stories & Highlights Scraper — Links, Mentions, Music
Pricing
from $10.00 / 1,000 accounts
Instagram Stories & Highlights Scraper — Links, Mentions, Music
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).
Pricing
from $10.00 / 1,000 accounts
Rating
0.0
(0)
Developer
Andrey Afanasenko
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
3 days ago
Last modified
Categories
Share
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:
{"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
- Open the actor and pick Mode 1 — Capture live stories.
- Paste your usernames, one per line.
@signs and profile links both work. - Press Start. Results appear row by row while the run is going.
- 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
linkStickersis 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 bymusicOriginalOwner. - Live now — sort by
expiringAt. The soonest to expire is the oldest story still up. - Accounts worth a closer look —
accountStatus = okanditemKind = story, then count rows perownerUsername.
📡 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.
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, nottakenAt, 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 — set it to run daily, which is what stories require.
- Integrations — 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 | Full profile data with filters — bio, counts, contacts, quality signals. |
| Instagram Email Scraper | Emails, phone numbers and websites accounts publish. |
| Instagram Post Likers Scraper | The accounts that liked or commented on a post. |
| Instagram Followers Scraper | Follower and following lists for any public account. |
| Instagram Follower Tracker | Watches an account and reports who joined and who left. |
| Instagram Reel Transcript | On-screen text, hooks and transcripts from reels. |
| Instagram Related Profiles | The accounts Instagram suggests next to a profile. |
| Instagram Influencer Search | Finds creators by niche, size and engagement. |
🛟 Support & feedback
- Something wrong with a run? Open an issue on this actor's page and paste the run ID. Every run writes a
USER_MESSAGErecord explaining what happened — quoting it helps. - Need a column that isn't here? Ask. Several columns in this actor exist because someone asked for them.
- 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?