Instagram Reel Scraper - $0.35 per 1,000 Reels
Pricing
from $0.35 / 1,000 reel scrapeds
Instagram Reel Scraper - $0.35 per 1,000 Reels
Give it Instagram handles and get each profile's reels tab newest-first: play counts, likes, comments, caption, duration, the direct video file, the cover image and the audio track. No login, no cookies, no API key. The cheapest Instagram reel scraper on the market.
Pricing
from $0.35 / 1,000 reel scrapeds
Rating
0.0
(0)
Developer
Dami's Studio
Maintained by CommunityActor stats
0
Bookmarked
3
Total users
2
Monthly active users
2 days ago
Last modified
Categories
Share
Instagram Reel Scraper
Give it Instagram handles and get each profile's reels tab back, newest first: play count, likes, comments, caption, hashtags, duration, the direct video file, the cover image and the audio track behind the reel. No API key and no browser, and nothing for you to set up — it reads the same public feed the reels tab itself reads.
- Many handles in one run; every reel is one row, deduplicated inside the run.
- Newest first, exactly as Instagram orders the reels tab, with pinned reels flagged rather than silently reordered.
- Stop at a date with
onlyPostsNewerThan, or cap each profile withresultsLimit— you only pay for rows you receive. - Collab reels are included, with every co-author handle listed.
- Run it with empty input and you get a labelled sample row, free, so you can see the shape before spending anything.
- Nothing to configure. Handles are read without an account, and a built-in session covers the handles Instagram refuses to show a logged-out visitor at all.
Price
$0.35 per 1,000 reels, plus a $0.0005 start fee per run (billed per gigabyte of run memory, so exactly that on the default 1 GB).
This is the cheapest Instagram reel scraper on the market, and it is the same rate on every plan, free or paid. There are no volume tiers, no minimum spend, no subscription and no add-on fees. What you read here is what you pay on day one and on day four hundred.
| Reels | Total cost |
|---|---|
| 100 | $0.0355 |
| 1,000 | $0.3505 |
| 10,000 | $3.5005 |
| 100,000 | $35.0005 |
What is actually charged
- One
reel-scrapedevent per reel row written to the dataset. Nothing else is metered per row. - Free: the sample row an empty run returns, and every diagnostic row — a blocked target, a dead URL, a search that matched nothing. Those rows all carry
"charged": false. - A profile that turns out to be private, deleted or reel-less costs nothing beyond the start fee — it returns a free diagnostic row instead.
- Reels already returned earlier in the same run are dropped before they are charged.
- Reels filtered out by
onlyPostsNewerThanorskipPinnedPostsare never charged, because they never become rows. - A run that finds nothing costs the start fee and nothing more.
- Rows never leave the dataset without a charge, and are never charged without a row. The billed event is a named one, so there is no price quietly attached to
apify-default-dataset-item— the trick that makes some scrapers bill you for their own error messages.
Input
{"usernames": ["nasa","natgeo","https://www.instagram.com/nike/"],"resultsLimit": 30,"onlyPostsNewerThan": "3 months","skipPinnedPosts": false}
| Field | What it does |
|---|---|
usernames | One or more Instagram handles. nasa, @nasa, https://www.instagram.com/nasa/ and a numeric profile id all work. Up to 100 per run. |
resultsLimit | How many reels to take from each profile, newest first. Default 30, maximum 1,000. This is per profile, so three handles at 30 is up to 90 rows. |
maxItems | Optional overall ceiling for the whole run, across every handle. Useful as a spend guard when you pass a long list of handles. |
onlyPostsNewerThan | Stop once the reels get older than this. Takes a date (2026-05-01) or a plain phrase (3 months, 2 weeks, 10 days). Leave it empty to ignore dates. |
skipPinnedPosts | Set to true to drop the reels the account has pinned to the top of its tab, so you only get the chronological feed. |
sessionCookies | Leave empty. Runs work out of the box using a built-in session for the handles that need one. That session is shared, so on a long list under heavy load some handles can come back blocked; putting your own Instagram cookie here gives the run a rate limit nobody else shares. Paste it as sessionid=...; csrftoken=... — Chrome: F12 → Application → Cookies → instagram.com. It is used for this run's requests and nothing else. |
proxyUrls | Leave empty. The run brings its own addresses and the cost of them is already inside the price. Fill this in only if you want traffic to leave through proxy servers you already pay for, as http://user:pass@host:port. |
Run it with empty input and you get one clearly labelled sample row, free, so you can see the output shape before you spend anything.
Output
One row per reel. A real row from a real run:
{"ok": true,"charged": true,"recordType": "reel","inputUsername": "nasa","shortCode": "DcBx_I1iHZW","url": "https://www.instagram.com/reel/DcBx_I1iHZW/","caption": "Check out the eclipse from 50,000 feet in the air!\n\nThese views, including footage from GoPro cameras, were captured by NASA's WB-57 aircraft during the 2026 total solar eclipse. Taking off from Iceland, our pilots studied the Sun's corona as they raced along the path of totality.\n\nCredit: NASA\n\n#NASA #Eclipse2026 #Aircraft","videoPlayCount": 6843356,"likesCount": 266714,"commentsCount": 1329,"videoDuration": 92.9489974975586,"videoUrl": "https://scontent-yyz1-1.cdninstagram.com/o1/v/t2/f2/m86/AQPIqo5-Uqofr5Hb3KFa-LDO1CW2ZC_FITrcfxz-9Cvg.mp4?...","displayUrl": "https://scontent-yyz1-1.cdninstagram.com/v/t51.82787-15/774149093_18637093324049152_5106811212992624343_n.jpg?...","audioTitle": "Original audio","ownerUsername": "nasa","isPinned": false,"id": "3963668990156895830","type": "Video","productType": "clips","hashtags": ["NASA","Eclipse2026","Aircraft"],"mentions": [],"videoViewCount": 6843356,"dimensionsWidth": 1080,"dimensionsHeight": 1920,"takenAtTimestamp": 1786726237,"timestamp": "2026-08-14T16:50:37.000Z","ownerFullName": "NASA","ownerId": "528817151","ownerIsVerified": true,"coauthorUsernames": ["gopro"],"isPaidPartnership": false,"hasAudio": true,"audioId": "27860248933613853","audioArtist": "nasa","audioIsOriginal": true,"audioDurationMs": 92933,"inputUrl": "https://www.instagram.com/nasa/reels/","scrapedAt": "2026-08-15T22:22:06.980Z"}
Field notes
videoPlayCount— plays as Instagram reports them at read time.videoViewCountcarries the same number, kept so an existing pipeline written against another reels feed keeps parsing.videoUrl— a direct, playable MP4 link. It is signed and expires after a few hours, so download it in the same session rather than storing the link — shortened above for legibility, the real row carries the full URL.displayUrl— the cover frame as a JPEG, also a signed link — shortened above for the same reason.isPinned— true when the account has pinned this reel to the top of its tab. Pinned reels are hoisted out of date order, which is why they are flagged rather than silently moved.coauthorUsernames— the other accounts on a collab reel. A collab reel appears on every co-author's tab, so you may see it under more than one handle if you scrape both.ownerUsername— who actually posted the reel. On a collab this can differ from the handle you asked for, which is whyinputUsernameis a separate field.audioTitle— "Original audio" for a sound the account made itself, or the track title for a licensed song.audioIsOriginaltells you which.videoDuration— length in seconds, as a decimal.timestamp— when the reel was posted, ISO 8601 in UTC.takenAtTimestampis the same moment as a Unix number.id— the numeric media id. Stable, and safe as a primary key across re-runs;shortCodeis equally stable and is what appears in the public URL.
Every real row carries "charged": true. Sample rows carry "_sample": true and diagnostic rows carry "_diagnostic": true with an errorCode you can filter on, and neither is ever billed.
How it works
- It calls the same public feed the reels tab on a profile page calls, and reads the JSON that comes back — no page rendering and no headless browser.
- Every handle is tried logged-out first, because that is what the reels tab of a public profile answers. Only the handles Instagram will not show that way — measured as a property of the account, not of the connection — fall back to a built-in session, so the fallback is reserved for the handles that actually need it.
- Each handle is turned into its numeric profile id once, and the id is only accepted if Instagram states it belongs to the handle you asked for — a collab post on the profile is owned by the other account, and taking that id would quietly return the wrong profile's reels.
- Several profiles are read at the same time, each on its own address, so a long list of handles finishes in a fraction of the time and costs a fraction of the compute.
- The reels feed is then paged with a cursor until your limit or your date cut-off is reached.
- Traffic leaves through a large pool of rotating addresses. Instagram meters these feeds per address, so a refusal is answered by moving to a new address rather than by waiting, and nothing is billed per gigabyte.
- Reel ids already seen in the run are skipped, so a collab reel that appears under two handles is only charged once.
What people use it for
- Tracking a set of creators or brands week by week: schedule the same handles daily and diff on
idto see what is new and how the play counts moved. - Finding out what actually works on an account before you brief a campaign — sort the rows by
videoPlayCountand read the top ten captions. - Building a swipe file of reference reels with the cover image and a playable video link already attached.
- Audio research:
audioId,audioTitleandaudioIsOriginalshow which sounds an account leans on and which of those are its own. - Competitive benchmarking across a whole category at once — pass thirty handles, cap each at ten reels, and you have a category snapshot in one run.
- Feeding a dashboard or a warehouse with a flat, typed table instead of scraping a rendered page that changes shape every month.
Reading the output
Every run writes three kinds of row and they are trivial to tell apart:
- Real rows carry
"charged": trueand"recordType": "reel". One billed event each, and nothing else is metered per row. - The sample row carries
"_sample": trueand"charged": false. There is exactly one, it only appears when the input had no handles in it, and it exists so you can look at the output shape before you spend anything. - Diagnostic rows carry
"_diagnostic": true,"charged": falseand anerrorCodeyou can switch on:NOT_FOUNDfor a handle Instagram says does not exist,NOT_AVAILABLEwhen Instagram returns an empty answer for the handle from every address tried and from a second endpoint — either a typo or an account that is closed to logged-out visitors,NO_RESULTSfor a public account with no reels,BAD_INPUTfor an entry that is not a handle,BLOCKEDwhen Instagram stopped answering for that profile,TIME_BUDGETwhen the run ran out of time before reaching a handle, andDEAD_LISTonce when six handles in a row have returned nothing and the run stops early rather than spend your time on the rest. Each one names theinputUsernameit belongs to and explains itself in plain English.
If you only want data, filter on charged == true. The number of those rows always equals the number of events you were billed for, so the dataset is its own invoice.
Handling the video and cover links
The videoUrl and displayUrl fields are direct, signed links to Instagram's media servers. They play and download without any header or cookie, but the signature expires within a few hours, so treat them as something to fetch now rather than to store. If you need the files kept, download them in the same job that reads the dataset. The reel's own page URL (url) never expires, so keep that as the permanent reference.
Limitations
- Public accounts only. A private account returns a free diagnostic row saying so — there is no way to read a private profile without an account, and this Actor never creates or uses one.
- A small number of otherwise public accounts are closed to logged-out visitors entirely: Instagram answers for them with an empty result no matter where the request comes from, verified from a clean home connection as well as from the run's own addresses. Those handles are retried with the built-in session, and if that does not open them either they return a free NOT_AVAILABLE row; no proxy or re-run changes it.
- The built-in session is shared, and Instagram rate-limits per account rather than per caller, so it is not unlimited throughput. Under heavy concurrent load supply your own cookie in
sessionCookiesfor a rate limit that is yours alone. If the built-in session runs out mid-run, the run finishes with what it collected and says so on its status line rather than failing. - The reels tab only. Photo posts, carousels, stories, highlights and IGTV-only uploads are out of scope; use a posts or stories Actor for those.
- Play counts, likes and comment counts are a snapshot at read time. They keep moving, so two runs an hour apart will legitimately disagree.
- Instagram hoists pinned reels above the chronological feed. The date filter therefore ignores pinned reels when deciding where to stop, and
isPinnedtells you which rows were hoisted. - A collab reel is on every co-author's tab, so scraping two co-authors returns it under both handles — once per handle, deduplicated only within a single run.
- Video and cover links are signed and expire after a few hours. The reel page URL does not.
- Some accounts hide their reels tab or have never posted a reel; those return a free
NO_RESULTSrow rather than an error. - Instagram meters these feeds per address. A very deep pull on many handles at once can hit a refusal, and the run then reports an honest
BLOCKEDrow for that handle with the reels it did get already delivered and charged. - The ceiling is 100 handles per run and 1,000 reels per handle. Split larger jobs across runs.
- Comment text, liker lists, view-through rates, follower counts and anything else behind a login are not available and are not returned.
Questions
Do I need an Instagram account, a cookie or an API key?
No. Runs work out of the box with nothing filled in. Handles are read the way an anonymous visitor reads a reels tab, and the handles Instagram will not show that way fall back to a built-in session. Private accounts are still out of reach either way.
Then what is sessionCookies for?
A private rate limit. The built-in session is shared between runs, and Instagram counts requests per account rather than per caller, so a busy hour is a slower hour for everyone using it. Paste your own Instagram cookie into sessionCookies and this run uses only that — its own quota, nobody else's. It is used for the run's requests and nothing else: never stored, never logged, never written into the dataset. Optional, and most runs never need it.
What does a run actually cost me?
The start fee once, plus one charge per reel row you receive. A run over three handles at 30 reels each is 90 charged rows. Sample rows and diagnostic rows are free, and a handle that returns nothing costs nothing beyond the start fee.
Will the run fail if a handle is wrong or an account is private?
No. It writes an uncharged diagnostic row for that handle, carries on with the rest, and finishes as succeeded. A failed run would still bill the start fee, which would mean paying to be told about a typo.
How do I get only the newest reels?
Set onlyPostsNewerThan to a date or a phrase like 2 weeks. The run stops walking a profile as soon as it passes the cut-off, so a daily schedule reads only what is new and charges only for that.
Can I pass profile URLs or numeric ids instead of handles?
Yes. nasa, @nasa, https://www.instagram.com/nasa/ and the numeric profile id are all accepted in the same list. A single reel URL is not a profile, so it comes back as a free BAD_INPUT row telling you so.
Why did I get a reel from a different account?
Collab reels. When two accounts publish a reel together it sits on both tabs, and the row keeps ownerUsername as whoever posted it while inputUsername stays the handle you asked for.
Is it safe to run on a schedule?
Yes. Nothing is held between runs, so the same input can run hourly or daily. Use id or shortCode to work out which rows are new since last time.