Instagram Stories Scraper
Scrape public Instagram stories: media URLs, type, timestamp, mentions, links and hashtags. Only live stories, gone after 24 hours. $2.50 per 1,000.
How it works
- 1Open it on Apify
Hit Run on Apify — it opens the tool in the cloud, no install.
- 2Set the inputs
Adjust
profiles,maxStoriesPerProfile,includeHighlights(sensible defaults are pre-filled). - 3Click Run
The tool runs on Apify’s cloud and collects the data for you.
- 4Export the results
Download as JSON, CSV or Excel, or pipe straight into your app, Google Sheets, or an AI agent.
Pricing
$0.0025 per result = $2.5 per 1,000
| You are charged for | When | Price |
|---|---|---|
| Result returned | Charged once per genuine result row. Samples, diagnostics and blocked runs are never charged. | $0.0025 |
Pay-per-event pricing: you are billed per result, not per subscription. Billing is handled by Apify on your own account. These are the live Apify store prices, in effect since 2026-09-18, and they are what you are actually charged.
Inputs
| Field | What it does | Type |
|---|---|---|
profiles | Up to five public Instagram usernames, @handles, or profile URLs. Empty input or no configured account session returns exactly one labeled, uncharged sample row. | array |
maxStoriesPerProfile | Most rows returned for each profile, counting current stories and highlights together. Highlights can hold hundreds of items, so this is what keeps a run's size and cost predictable. | integer |
includeHighlights | Highlights are the trays pinned to a profile. They do not expire, so this is how you get a profile's older stories rather than only what is live today. It is ON, so a run returns both unless you untick it. Two honest caveats: highlights make a run bigger and therefore dearer, since you pay per row either way; and a profile with nothing pinned simply returns nothing extra. | boolean |
requestTimeoutSeconds | Timeout for each authenticated Instagram request. | integer |
maxRunSeconds | Hard wall-clock bound for profile resolution and story retrieval. | integer |
sessionCookies | Optional, and normally not needed, runs work with no cookie at all. Supply your own Instagram account cookie here to run on your own account, and to reach feeds that need a signed-in visitor. In Chrome: F12 -> Application -> Cookies -> https://www.instagram.com -> copy the sessionid value. Use an account you own and are authorized to automate. Cookie values are never logged or written to output. Prefer a throwaway account over your main one. | array |
maxAttempts | Bounded retries across rotating configured accounts and sticky proxy sessions. | integer |
What you get
A structured dataset — each result includes fields like:
sourceUsernamestoryIdmediaTypetakenAtexpiresAtcaptionstoryUrlExport every run as JSON, CSV or Excel, or send it to your app, a database, Google Sheets, or an AI agent.
14 ready-to-run use cases
Instagram Stories Scraper: BMW, Audi, Mercedes-Benz
All three accounts' current stories in one run: media URLs, type, duration, posted time and caption. Public profiles, no login and no cookie.
Instagram Story Viewer: Starbucks Stories as Data
Starbucks' live stories with direct image and video URLs, media type, posted time, duration and caption. No login and no cookie needed.
Anonymous Instagram Story Viewer for Rival Brands
Nike, Adidas and Puma stories pulled with no account of yours involved: media URLs, type, posted time, duration and caption. Current stories only.
See Instagram Stories Anonymously: Starbucks, McDonald's
Neither account gets a view from your side because no account of yours is used. Returns media URLs, type, duration, posted time and caption.
Instagram Story Archive: Save Stories Before They Go
Cristiano's current stories with direct media URLs and posted times. The CDN links expire, so download what you want to keep soon after the run.
Sponsored Instagram Stories: Paid-Partnership Flag
Each story comes back with a paid-partnership flag, media URL, posted time, duration and caption. Only what is live at run time, so run it daily.
Instagram Stories API for BBC News and CNN
Current stories from both accounts as JSON: media URLs, type, duration, posted time and caption. Call it from your own code, no login required.
Instagram Story Downloader for Apple and Samsung
Direct image and video URLs for whatever both accounts have live right now. It returns links, not the files, and those links time out quickly.
Save Instagram Stories from Zara and H&M Daily
A daily run catches what these two posted before it disappears: media URLs, type, duration, posted time and caption. Current stories, not highlights.
IG Story Viewer for Barcelona and Real Madrid
Matchday stories from both clubs with media URLs, type, duration and posted time. Run it after a game to catch the stories before they expire.
Instagram Story Time Posted, Across Four Brands
Every story from Nike, Adidas, Puma and Under Armour with its posted timestamp. Count the rows per day to compare how often each account posts.
Instagram Story Links and Media URLs: Sephora, ASOS
A permalink and direct media URL for each live story. Worth saying plainly: link stickers are not read out, so the swipe-up target is not in the data.
Instagram Story Data for Netflix: Media and Caption
Media URLs, type, duration, posted time and caption for each live story. Poll and question stickers are not returned as data, only as the image itself.
Instagram Story Viewer Online for Gymshark
Gymshark's live stories with media URLs, posted time and caption text. Codes burned into an image stay in the image; only the caption comes back.
Ready-made automation using this tool
A finished workflow you can import into n8n and run — this tool does the data-gathering inside it. Free, and yours to change.
Save Instagram stories to a spreadsheet before they vanish
Instagram stories disappear after 24 hours. This checks the accounts you name a few times a day and copies each new story into a Google Sheet — the image, the link, when it went up — so you still have it next week.
Related tools in Developer & Research Tools
Other ready-to-run tools in the same category — all pay-per-use on the Apify cloud.
GitHub Scraper
Search GitHub repos and users: stars, forks, language, topics, licence, plus user bio, company and followers. No token needed. $0.90 per 1,000 rows.
Stack Overflow / Stack Exchange Scraper
Search Stack Overflow and Stack Exchange by keyword or tag. Score, answer count, views, reputation and body text. $2 per 1,000 questions.
Package Registry Scraper (npm + PyPI)
Get npm and PyPI package metadata as JSON. Version, license, author, repo, keywords and npm monthly downloads. $2 per 1,000 packages.
arXiv Scraper
Search arXiv papers by title, author, abstract or category. Get full abstracts, authors, categories, DOI, dates and PDF links. $2 per 1,000 papers.
OpenAlex Scholarly Works Scraper
Search 250M+ OpenAlex papers with no API key. Get titles, authors, venue, year, citations, DOI, OA links and full abstracts. $2.00 per 1,000 papers.
Crossref Scholarly Works Scraper
Search 150M+ papers on Crossref: DOI, title, authors, journal, publisher, date, citations and abstract. No API key. $1.00 per 1,000 works.
Where this tool sits
- Categories
- Developer & Research Tools
Instagram Stories Scraper: live stories and pinned highlights from public profiles
Name up to five public Instagram handles and get their stories back as rows. Media type, the image or video link, when it was posted, the caption, any location tag, and the sponsored flag.
Here is the thing that decides whether this is useful to you. A story is gone 24 hours after it goes up, so a run only sees what is live at the moment you press Start. If you want the older material, that is what highlights are: the trays an account pins to its profile, which do not expire. They are switched on by default.
| Input | Up to 5 public handles, @handles or profile URLs |
| Output | One row per story or highlight item |
| Ceiling | 100 rows per profile, 5 profiles per run |
| Account needed | None from you |
| Price | $2.50 per 1,000 rows, flat on every plan |
🔍 What Instagram Stories Scraper does
It reads what is live on each handle right now, plus the pinned highlight trays if you leave those on, and writes one row per item. Stories and highlights come back in the same shape, and recordType tells you which you are looking at. Highlight rows also carry the tray they came from in highlightTitle.
Nothing to log into. No API key, no cookie, no app review.
maxStoriesPerProfile is applied to current stories and to highlights separately. Set it to 25 and a profile with both can return up to 50 rows, and you pay per row. Set it low while you are working out how much a handle actually has.
If you do supply your own cookie in sessionCookies, the run uses your account's own rate limit, and it returns current stories only. Highlights come back on the default route.
📥 What you give it
{
"profiles": ["nasa", "natgeo"],
"maxStoriesPerProfile": 25,
"includeHighlights": true
}
| Field | Default | What it is |
|---|---|---|
profiles | none | nasa, @nasa or a full profile URL. Up to 5 in one run. |
maxStoriesPerProfile | 25 | Rows per profile, 1 to 100, counted separately for current stories and for highlights. |
includeHighlights | true | The pinned trays. Untick it to get only what is live today. A profile with nothing pinned simply returns nothing extra. |
maxRunSeconds | 120 | Wall-clock ceiling for the whole run, 20 to 180. |
requestTimeoutSeconds | 15 | How long one request may take, 5 to 30. |
maxAttempts | 6 | How many times a refused request is retried before the run gives up on it. 1 to 12. |
sessionCookies | none | Optional. Your own Instagram sessionid, for your own rate limit. Current stories only on this route. |
proxyConfiguration | Apify default | Leave it alone. Put servers of your own in proxyUrls inside it if you have them. |
Start a run with no profiles and you get one labelled sample row showing the output shape. That row is not charged.
📤 What you get back
A real row from a real run, with the long media links cut short:
{
"ok": true,
"recordType": "story",
"storyId": "3978846251986655690",
"sourceUsername": "nasa",
"sourceProfileId": "528817151",
"ownerUsername": "nasa",
"mediaType": "video",
"takenAt": "2026-09-04T15:23:44.000Z",
"expiresAt": null,
"caption": null,
"imageUrl": "https://scontent-xxc1-1.cdninstagram.com/v/t51.82787-15/...",
"videoUrl": "https://scontent-xxc1-1.cdninstagram.com/o1/v/t2/f2/m78/...",
"durationSeconds": 15,
"dimensions": null,
"isSponsored": false,
"location": null,
"storyUrl": "https://www.instagram.com/stories/nasa/3978846251986655690/"
}
A highlight row is the same shape with recordType: "highlight" and two extra fields, highlightId and highlightTitle, naming the tray it was pinned into.
| Field | What it is |
|---|---|
storyId | Unique per item. Use it as your dedupe key across runs. |
mediaType | image, video or carousel. A video row carries both imageUrl (the cover frame) and videoUrl. |
imageUrl, videoUrl | Signed links that expire within hours. Download anything you want to keep, in the same job. |
takenAt | When the item was posted. null when Instagram did not supply it, never a made-up date. |
expiresAt, dimensions | Frequently null. They arrive when Instagram sends them and are left empty when it does not, so do not build on them. |
location | An object with the place id, name, address and coordinates when the item carries a location sticker. null otherwise. |
isSponsored | Instagram's own paid-partnership flag on the item. |
Nothing is guessed or padded.
🧾 Reading the output
Three kinds of row land in your dataset, and only the first kind is billed.
| Row | How to spot it | Billed |
|---|---|---|
| A story or a highlight item | ok: true and a storyId | yes |
| The sample row | _sample: true, and only on a run with no profiles | no |
| A diagnostic | ok: false and an errorCode | no |
Filter on ok == true and you have your media. Every diagnostic row names the handle it belongs to in sourceUsername, so you always know which profile it is about.
| Code | What it means |
|---|---|
NO_CURRENT_STORIES | Nothing was live on that profile at the moment of the run. |
NOT_FOUND | No such account. |
PRIVATE_OR_RESTRICTED | The account is private, or closed to a reader who is not following it. |
BAD_INPUT | Nothing in profiles looked like a handle. |
PARTIAL | The run delivered some rows and then stopped. What arrived is complete and correct. |
DEADLINE_EXCEEDED | The run hit maxRunSeconds before reaching that profile. Raise it. |
RATE_LIMITED | Too many requests too close together. Space the runs out. |
AUTHENTICATION_FAILED, SESSION_EXHAUSTED | If you supplied a cookie, check it is still valid. |
PROXY_GROUP_IGNORED | A setting in proxyConfiguration could not be used as written. |
SERVER_ERROR, NETWORK | Instagram was unreachable or answered badly. Re-run it. |
No diagnostic row is billed as a result.
▶️ How to run it
1. Open Instagram Stories Scraper and click Try for free. 2. Put your handles into Public Instagram profiles, up to five. 3. Set Maximum current stories per profile. Start at 5 while you look at the output shape. 4. Leave Also get story highlights on if you want the older pinned material. 5. Click Start, then download the dataset as JSON, CSV or Excel.
💰 How much does it cost?
$2.50 per 1,000 rows. Flat on every Apify plan, no volume tiers.
One charge per row delivered, whether it is a live story or a highlight item. Sample rows and diagnostic rows are not billed, and a profile with nothing live is not billed for results.
Remember the cap counts twice, once for current stories and once for highlights. A five-profile run at 25 can come back with 250 rows rather than 125 if every profile has both.
💡 What people use it for
- Checking daily whether a set of brands is running stories, and archiving them before they vanish.
- Pulling a competitor's highlight trays as a snapshot of how they present themselves.
- Collecting story links and sponsored flags to see which creators are running paid placements.
- Keeping a record of a campaign's stories, since nobody can go back for them the next day.
🚧 What it does not do
- No expired stories. Once the 24 hours are up the item is gone, and highlights are the only
way back to older material.
- No private accounts, and no accounts that only show stories to followers.
- No viewer lists, no reply counts, no poll or quiz results. Those are visible only to the
account that posted.
- Highlights need the default route. Supply your own cookie and you get current stories only.
expiresAtanddimensionsare often empty, so do not build a pipeline that requires them.- Media links expire within hours. Download the files in the same job.
- Five profiles per run, 100 rows per profile on each of the two kinds.
🧭 Which Instagram scraper do you need?
| If you want | Use |
|---|---|
| Live stories and pinned highlights | This one |
| Posts and reels from a profile | Instagram Scraper |
| Follower counts, bio, email and links | Instagram Profile Scraper |
| Reels from a profile's reels tab | Instagram Reel Scraper |
| Posts other people made about a handle | Instagram Mentions Scraper |
❓ Questions people ask
Do I need an Instagram account? No. The cookie field is optional and lets the run use your own account.
Why did I get nothing back? Most likely nobody had a story live at that moment. The NO_CURRENT_STORIES row in your dataset says so, and it is not billed.
Can I get stories from yesterday? Only if the account pinned them into a highlight. Instagram deletes the rest after 24 hours.
Can the account see that I read its story? No. Nothing is viewed as an account, so nothing turns up in its viewer list.
How often should I schedule it? Every few hours if you want to catch everything, since stories come and go inside a day.
Is scraping Instagram legal? This reads public profiles only, never private accounts or messages. Results can still contain personal data, which GDPR and similar laws cover, so have a reason for collecting it. Apify's write-up on the legality of web scraping is a good starting point, and we are not lawyers.
🆘 If something breaks
Open the Issues tab on the actor page. Send the handle you used and the run ID. The errorCode on the diagnostic row usually explains it on its own.