Instagram Story Scraper | Stories & Highlights avatar

Instagram Story Scraper | Stories & Highlights

Pricing

from $3.82 / 1,000 stories

Go to Apify Store
Instagram Story Scraper | Stories & Highlights

Instagram Story Scraper | Stories & Highlights

Extract Instagram stories and highlights from any public account: image and video links, exact posting time, expiry, swipe-up links and mentions, plus followers, following, posts, bio and website on every row. Track competitors, creators and news accounts daily with no login or account needed.

Pricing

from $3.82 / 1,000 stories

Rating

0.0

(0)

Developer

SilentFlow

SilentFlow

Maintained by Community

Actor stats

0

Bookmarked

4

Total users

3

Monthly active users

3 days ago

Last modified

Share

Instagram Story Scraper

Every active story and every highlight of a public Instagram account, as a table: image and video links, exact posting time, expiry, swipe-up link, mentions, and the account's followers on each row. Three news accounts, 43 stories, in 24 seconds. No login.

How it works

How it works

  1. You paste one or more accounts, or story links. A username, an @handle or a profile link all name an account; a story link names one precise story.
  2. Each account is read once. Its active stories come back in one call. If you ask for highlights, each album pinned on the profile is opened, newest first, up to the cap you set.
  3. One row comes back per story or highlight item. 26 fields: the media with its links and exact time, and the account it belongs to with followers, name, bio and website. Ready for a spreadsheet, a database or an AI pipeline.

✨ Why teams choose this over other Instagram story scrapers

Taking screenshots of competitors' stories every morning before they vanish? Asked by a client to prove that a sponsored story went live at the right time with the right link? Getting back 150 raw keys per story and a unix timestamp when all you wanted was a date and a follower count?

  • πŸ“Š 20 fields filled on every row, not 11. The other flat story scraper on the Store fills 11 keys per row; the most used ones return the raw Instagram object with 150 nested keys and unix timestamps. Here every story row carries 20 filled columns, measured on the default run of 22 September 2026 (43 rows, 21 columns filled on the majority of rows, the swipe-up link on 25 of them). No other story scraper puts followersCount, followingCount, postsCount, biography and externalUrl on the row.
  • πŸ‘€ The account on every row. Followers, following, posts, name, bio, website, verified badge and avatar come with each story. One dataset answers both "what did they post" and "how big are they", with no second scraper to join.
  • ⏰ Exact time and expiry, in a format that sorts. takenAt and expiringAt are RFC 3339 (2026-09-21T22:07:02Z), not 1758492422. Sort a day of stories, prove a posting window, schedule the next run before anything expires.
  • πŸ”— Accounts or precise story links. Name an account by username, @handle or profile link, or paste the link of one story (instagram.com/stories/cnn/3992904485714001336/) and get exactly that story with its account's figures, to prove a sponsored story went live. The most used scraper of the niche accepts plain usernames only, and no field here is required: accounts, links or both.
  • 🎞️ Stories and highlights, chosen per run. Read what is live now, the permanent albums pinned on the profile, or both, with a cap on albums. The two most used story scrapers read stories only; highlights here return rows even at 3 a.m. when nothing is live.
  • πŸ–ΌοΈ Direct media links and a permalink. imageUrl for photos and posters, videoUrl for the mp4 of video stories, thumbnailUrl for a preview, and a stable url per row. Download what you want to keep.
  • 🧹 No error rows. One row is one real story or highlight item. An unknown or private account produces no row and a clear message on the run, where other scrapers write an error item into your export. Unknown values are null, never an empty string, and no item appears twice.
  • πŸ”‘ No login, no account to connect. Public accounts only. Paste a username and press Start.

🎯 What you can do with Instagram story data

TeamWhat they build
Influencer marketingProof of delivery for a paid story: the row shows when it went live, the link it carried and the media, taken by a schedule before it expired
Competitive researchA daily archive of every story a list of rival brands posted, with links, mentions and media, searchable months later
Social media agenciesA morning digest of what each client's competitors pushed overnight, ready for Slack or a spreadsheet
Affiliate and e-commerceA tracker of the swipe-up links and promo codes creators post in stories, with the UTM tags as they appear
Newsrooms and PRA timeline of the stories a public figure or a news account published around an event, with exact times
Research and archivesA dataset of a brand's highlight albums, item by item, with posting dates that span years
Creator platformsA vetting card per creator: followers, posting cadence in stories, share of video versus image, links pushed

πŸ“₯ Input parameters

Essentials

FieldTypeDescription
usernamesarrayPublic accounts to read, one per line. Accepts a username (cnn), a handle (@cnn) or a profile link (https://www.instagram.com/cnn/).
startUrlsarrayLinks of precise stories (https://www.instagram.com/stories/cnn/3992904485714001336/): each gives exactly that story while it is live (24 hours). A profile link here reads the whole account. Highlight links do not name their account: add the account and choose highlights instead. Fill usernames, startUrls or both.
maxItemsinteger, default 100Maximum rows for the whole run, stories and highlight items together.

🎞️ Content

FieldTypeDescription
contentTypestring, default storiesstories reads what the account posted in the last 24 hours, one call per account. highlights reads the permanent albums pinned on the profile, one call per album. both reads the two.
maxHighlightsinteger, default 5How many highlight albums to open per account, newest first. Each album returns all its items. Ignored when contentType is stories.

βš™οΈ Advanced

FieldTypeDescription
debugModeboolean, default falseAdds detailed lines to the run log. Leave it off for normal runs.

πŸ“Š Output data

Each row is one story or one highlight item. An active story of a news account looks like this (long media links shortened here):

{
"id": "3989588439640364857_217723373",
"url": "https://www.instagram.com/stories/cnn/3989588439640364857/",
"type": "story",
"mediaType": "image",
"highlightId": null,
"highlightTitle": null,
"link": "https://www.cnn.com/2026/09/19/style/cfda-fashion-boss-resigns-kolb-protesters-hnk-intl?utm_medium=social&utm_source=igstoryCNN",
"mentions": [],
"username": "cnn",
"userId": "217723373",
"fullName": "CNN",
"biography": "Asking the hard questions and bringing unique perspective from across the globe. This is CNN.",
"externalUrl": "http://cnn.com/linkinbio",
"isVerified": true,
"followersCount": 23592848,
"followingCount": 323,
"postsCount": 29599,
"profilePicUrl": "https://scontent-lga3-2.cdninstagram.com/v/t51.2885-19/353448964_228072746694866_3965541026640463359_n.jpg?…",
"takenAt": "2026-09-19T11:07:04Z",
"expiringAt": "2026-09-20T11:07:04Z",
"highlightCreatedAt": null,
"imageUrl": "https://scontent-lga3-2.cdninstagram.com/v/t51.82787-15/818122990_18633735430059374_6730580538173429432_n.jpg?…",
"videoUrl": null,
"thumbnailUrl": "https://scontent-lga3-2.cdninstagram.com/v/t51.82787-15/818122990_18633735430059374_6730580538173429432_n.jpg?…",
"input": "cnn",
"scrapedAt": "2026-09-20T03:38:17Z"
}

A video item of a highlight album keeps the same 26 columns. It carries the mp4 in videoUrl, its poster in imageUrl, the album in highlightId and highlightTitle, and no expiringAt since highlights do not expire (account block shortened here):

{
"id": "3797974848153407573_217723373",
"url": "https://www.instagram.com/s/aGlnaGxpZ2h0OjE4NTQ3NjI4MzIwMDE2NTQy?story_media_id=3797974848153407573",
"type": "highlight",
"mediaType": "video",
"highlightId": "18547628320016542",
"highlightTitle": "πŸŽ‡",
"link": null,
"mentions": [],
"username": "cnn",
"userId": "217723373",
"fullName": "CNN",
"followersCount": 23592848,
"takenAt": "2025-12-29T02:05:04Z",
"expiringAt": null,
"highlightCreatedAt": "2025-12-29T02:06:51Z",
"imageUrl": "https://scontent-lga3-2.cdninstagram.com/v/t51.71878-15/…jpg?…",
"videoUrl": "https://scontent-lga3-2.cdninstagram.com/o1/v/t2/f2/m78/…mp4?…",
"thumbnailUrl": "https://scontent-lga3-2.cdninstagram.com/v/t51.71878-15/…jpg?…",
"input": "https://www.instagram.com/cnn/",
"scrapedAt": "2026-09-20T03:47:33Z"
}

πŸ—‚οΈ Data fields

26 fields per row: 4 identity, 4 content, 10 account, 3 time, 3 media, 2 meta. mentions is the only list, the usernames tagged in the story.

GroupFields
Identityid (Instagram media id), url (permalink), type (story or highlight), mediaType (image or video)
ContenthighlightId, highlightTitle, link (the swipe-up link), mentions
Accountusername, userId, fullName, biography, externalUrl, isVerified, followersCount, followingCount, postsCount, profilePicUrl
TimetakenAt (RFC 3339, UTC), expiringAt (stories only, 24 hours after takenAt), highlightCreatedAt (highlight items only)
MediaimageUrl (the photo, or the poster of a video), videoUrl (mp4, videos only), thumbnailUrl
Metainput (the account as you typed it), scrapedAt (RFC 3339, UTC)

Good to know when you store the data:

  • id is Instagram's own media id and never changes. url is built from it: the story permalink for a story, the share link of the album item for a highlight.
  • takenAt is the moment the story was posted. expiringAt is when Instagram removes it from the profile. A highlight item keeps its original takenAt, which can be years old, and highlightCreatedAt tells when the album was created.
  • imageUrl, videoUrl, thumbnailUrl and profilePicUrl point to Instagram's own media servers. They stay valid for a few days, then Instagram rotates them: download the files you want to keep, url stays.
  • link is set only when the story carries a swipe-up link, mentions is an empty list when nobody is tagged.
  • followersCount, followingCount and postsCount are the numbers shown on the profile at run time.
  • The account block is identical on every row of an account, so the first row of each username is the account's profile.

πŸš€ Examples

Get the active stories of three news accounts

{
"usernames": ["cnn", "bbcnews", "skynews"]
}

Watch a list of competitors every morning

Put this on a daily schedule. Each run returns what is live at that moment, with time, link and media.

{
"usernames": ["@nike", "@adidas", "@puma", "@newbalance"],
"maxItems": 200
}

Export the highlight albums of a brand

{
"usernames": ["https://www.instagram.com/cnn/"],
"contentType": "highlights",
"maxHighlights": 10,
"maxItems": 500
}

Read stories and the latest album together

{
"usernames": ["foxnews", "skynews"],
"contentType": "both",
"maxHighlights": 1,
"maxItems": 100
}

Check that a sponsored story is live on a creator's account

{
"usernames": ["https://www.instagram.com/bleacherreport/"],
"maxItems": 20
}

Sample a large watchlist quickly

{
"usernames": ["cnn", "bbcnews", "skynews", "foxnews", "bleacherreport", "natgeo"],
"maxItems": 30
}

πŸ€– Copy to your AI assistant

Paste this block into Claude, ChatGPT or Cursor to give it full context about this scraper:

You have access to the Instagram Story Scraper on Apify: silentflow/instagram-story-scraper
Input schema:
- usernames (array of strings): Instagram usernames, @handles or profile links of public accounts
- startUrls (array of {url}): links of precise stories, each returning exactly that story while it is live; fill usernames, startUrls or both
- maxItems (integer, default 100): max rows for the whole run
- contentType (string, default "stories"): "stories" (last 24 hours), "highlights" (permanent albums) or "both"
- maxHighlights (integer, default 5): albums opened per account, newest first
- debugMode (boolean, default false)
Output, one row per story or highlight item (26 fields, null when unknown):
- id (string), url (string), type ("story" | "highlight"), mediaType ("image" | "video")
- highlightId (string), highlightTitle (string), link (string), mentions (string[])
- username, userId, fullName, biography, externalUrl, profilePicUrl (strings)
- isVerified (boolean), followersCount, followingCount, postsCount (integers)
- takenAt, expiringAt, highlightCreatedAt (RFC 3339 UTC)
- imageUrl, videoUrl, thumbnailUrl (strings, Instagram media links valid a few days)
- input (string), scrapedAt (RFC 3339 UTC)
Private accounts and unknown usernames return no row. No login needed. Use apify-client for Python or JavaScript.

πŸ’» Integrations

Keep a daily archive of competitors' stories (Python)

import csv
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("silentflow/instagram-story-scraper").call(run_input={
"usernames": ["nike", "adidas", "puma"],
"maxItems": 200,
})
rows = list(client.dataset(run["defaultDatasetId"]).iterate_items())
with open("stories-archive.csv", "a", newline="") as f:
writer = csv.writer(f)
for r in rows:
writer.writerow([r["takenAt"], r["username"], r["mediaType"], r["link"], ",".join(r["mentions"]), r["url"], r["videoUrl"] or r["imageUrl"]])
print(f"{len(rows)} stories archived")

Alert Slack when a creator posts a story with a link (JavaScript)

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_APIFY_TOKEN' });
const run = await client.actor('silentflow/instagram-story-scraper').call({
usernames: ['bleacherreport', 'espn'],
maxItems: 50,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
for (const story of items.filter((s) => s.link)) {
await fetch(process.env.SLACK_WEBHOOK_URL, {
method: 'POST',
body: JSON.stringify({ text: `@${story.username} posted a story at ${story.takenAt} linking to ${story.link}` }),
});
}

Download the media of a highlight album (Python)

import requests
from apify_client import ApifyClient
client = ApifyClient("YOUR_APIFY_TOKEN")
run = client.actor("silentflow/instagram-story-scraper").call(run_input={
"usernames": ["cnn"],
"contentType": "highlights",
"maxHighlights": 1,
"maxItems": 100,
})
for item in client.dataset(run["defaultDatasetId"]).iterate_items():
media_url = item["videoUrl"] or item["imageUrl"]
ext = "mp4" if item["videoUrl"] else "jpg"
with open(f'{item["username"]}-{item["id"]}.{ext}', "wb") as f:
f.write(requests.get(media_url, timeout=60).content)

πŸ“ˆ Performance

Measured on 22 September 2026 on real accounts.

RunRowsTime
3 news accounts, active stories (the default input)4324 seconds
1 account by profile link, its 2 latest highlight albums2823 seconds
3 accounts, stories and 1 album each, one unknown account, capped at 252525 seconds
2 sports accounts by profile link, active stories1342 seconds
2 news accounts, capped at 5512 seconds
MetricValue
Fields per row26
Calls per account1 for stories, plus 1 per highlight album
Time per callabout 10 seconds, the pace the source allows
Columns filled on the default runall, except link and mentions when the story carries none, and the highlight columns on stories
Limit per runno fixed limit: maxItems is yours to set

πŸ’Ύ Data export

Every run stores its rows in a dataset you can download as JSON, CSV, Excel, XML or HTML from the Storage tab, or pull from the API:

https://api.apify.com/v2/datasets/{DATASET_ID}/items?format=csv&token=YOUR_TOKEN

The dataset has two ready-made table views: Stories (account, type, media, highlight, posted, swipe-up link, story URL, image) and Accounts (account, name, followers, following, posts, verified, website, avatar). Schedules, webhooks and the Apify integrations (Google Sheets, Slack, Zapier, Make, n8n) work on top of the same dataset.

πŸ’‘ Tips for best results

  1. Schedule twice a day for a complete archive. Stories last 24 hours. A run every 12 hours sees every story at least once; expiringAt tells you how much margin you had.
  2. Start with accounts that post daily. News and sports accounts have stories around the clock. A brand that posts twice a week returns no story row on most runs, which is normal: switch to both to always get rows.
  3. Use highlights for permanent content. Campaign albums, product albums and press albums stay on the profile for years. maxHighlights decides how many albums open, newest first.
  4. Download the media you want to keep. Instagram rotates its media links after a few days. url stays valid, the files do not.
  5. Size maxItems for the whole run. Ten accounts with about 8 stories each need maxItems: 100. With highlights, count up to 100 items per album.
  6. Group rows by username for account reports. The account block is identical on every row of an account.

❓ FAQ

What does this scraper extract? The active stories and the highlight albums of public Instagram accounts, one row per item, with 26 fields: the media (type, image, video, thumbnail, permalink), its exact posting time and expiry, the swipe-up link and mentions, the album it belongs to, and the account (name, bio, website, verified badge, followers, following, posts, avatar).

What can I type in the accounts field? A username (cnn), a handle (@cnn), a profile link in any form (https://www.instagram.com/cnn/, instagram.com/cnn), or a story link (instagram.com/stories/cnn/…). A link to a post or a reel is skipped and named in the run log.

Do I need an Instagram account? No. The scraper reads public accounts. There is no login, no key and no session to refresh.

Why does an account return no story? Stories last 24 hours. If the account posted nothing in that window, there is nothing to read, and the run log says so. Run again later, put the run on a schedule, or set contentType to both to get the highlight albums as well.

What about private accounts? Their stories are not public, so the scraper skips them, names them in the run log, and writes no row. Your dataset never contains error rows.

How fresh is the data? Live. Every run reads the accounts at run time. scrapedAt tells you when each row was read, takenAt when the story was posted.

Are the media links permanent? url is permanent. imageUrl, videoUrl, thumbnailUrl and profilePicUrl are links to Instagram's media servers and stay valid for a few days. Download the files you want to keep.

Can I scrape many accounts in one run? Yes. List as many accounts as you need. An account named twice is read once, and no item is delivered twice in a run. Each account takes about ten seconds, plus about ten seconds per highlight album.

How do highlights work? Highlights are the albums pinned under the bio of a profile. With contentType set to highlights or both, the scraper opens up to maxHighlights albums, newest first, and returns every item of each album with the album's id, title and creation date.

Does it get story views, replies or the viewers list? No. Those numbers are only visible to the account owner. The scraper returns what a visitor of the profile can see.

Is there a limit on the number of rows? No fixed limit. maxItems caps the whole run and you choose it.

Can I get the text written on a story? Not as a field: Instagram does not publish the text of stickers and captions. You get the image or video, which you can pass to an OCR or vision model.

This Actor extracts publicly available data from Instagram. It does not bypass any login, paywall or CAPTCHA, and it only reads public accounts. Users are responsible for complying with Instagram's terms of service and with applicable data protection laws (GDPR, CCPA, and PIPL where relevant). The output contains account information that account owners publish themselves (username, name, bio, website, follower counts, avatar); when you process it as personal data, handle it accordingly. The data returned is informational; verify accuracy for regulated use cases.

πŸ“¬ Support

Need something this scraper does not do yet? We ship features fast.

  • Feature requests go straight to our backlog
  • Enterprise needs? We do custom integrations and high-volume plans
  • Pricing details live on the Monetization tab of the actor page

Response time: usually under 24 hours.

Check out our other scrapers: silentflow on Apify