Give this endpoint an Instagram handle and it returns that account's recent reels as an array of JSON objects, newest first. Each reel carries its own view, like and comment counts, its caption, its runtime and its posted timestamp. Billing is per reel returned, 1 credit each, so a 20-reel pull costs 20 credits.
| parameter | type | description |
|---|---|---|
| handle | string, required | The Instagram username, without the @. |
| limit | integer | Items per page, up to 50 synchronously. Above that the call becomes a job. |
| cursor | string | meta.next_cursor from the previous page. |
| fresh | boolean | Skip the stored copy and read live, at the same price. |
| fields | string | Comma-separated field paths to keep. |
| format | json, csv | CSV flattens each item to one row. |
1 credit per reel. Failed calls are never charged, and empty results are free up to 25 a day. Stored copies are refreshed every 3 hours.
An array under `data`. Every element is one reel: the short code that identifies it, the canonical URL, the caption as written, the public counters, how long the clip runs, when it went up, a thumbnail image URL and the owner's handle and display name. The list is ordered the way Instagram serves the account's reels tab, which in practice means most recent first.
This is the same object shape the single-post endpoints return, so a reel pulled from here and a post pulled by URL are interchangeable in your storage layer. That matters if you are writing both into one table — you do not need two schemas or a translation step between them.
One list call also warms our per-item cache for the reels it contained. If you fetch a handle's reels and then immediately ask for stats on one of those reels by URL, that second call is served from cache and comes back in milliseconds instead of seconds. It still costs its own credits, but the wait disappears.
curl "https://api.instadata.dev/v1/instagram/channel-reels?handle=nasa&limit=10" \ -H "Authorization: Bearer ik_live_..."
{
"data": [
{
"id": "C8xQvZ2sVAb",
"url": "https://www.instagram.com/reel/C8xQvZ2sVAb/",
"caption": "POV: your setup finally works",
"posted_at": "2026-07-05T15:30:00Z",
"metrics": {
"views": 421009,
"likes": 38112,
"comments": 640
}
},
{
"id": "C8xQvZ2sVAb1",
"url": "https://www.instagram.com/reel/C8xQvZ2sVAb/",
"caption": "POV: your setup finally works",
"posted_at": "2026-07-05T15:30:00Z",
"metrics": {
"views": 421009,
"likes": 38112,
"comments": 640
}
}
],
"meta": {
"count": 2,
"limit": 20,
"item": "reel"
},
"request_id": "req_01JZX4M8Q2TE9W"
} | field | type | note |
|---|---|---|
| id | string | Instagram short code for the reel (the part after /reel/ in the URL). Stable, and the right primary key. |
| url | string | Canonical instagram.com link to the reel, derived from the short code when the upstream payload omits it. |
| type | string|null | Media type as Instagram classifies it, e.g. a clips/video marker. Null when the payload carries no type. |
| caption | string|null | Caption text exactly as posted, including hashtags and line breaks. Null when the reel has no caption. |
| views | number|null | Public play count for the reel. Null when Instagram is not exposing a play count on that item. |
| likes | number|null | Public like count. Null when the account has hidden like counts on the post. |
| comments | number|null | Number of comments. Get the text itself from the Instagram Comments API. |
| shares | null | Always null on this endpoint — a literal null, never a number. Instagram does not publish a share count on public reel pages, and we will not invent one. |
| duration_sec | number|null | Clip runtime in seconds. Useful for separating 7-second loops from 90-second explainers before you compare engagement. |
| posted_at | string|null | ISO 8601 UTC timestamp of publication. Subtract from now() to get reel age. |
| author | object | Nested { handle, name } — the account's username and display name. Either key can be null. Follower counts are not here; use the Instagram Channel Stats API. |
| thumbnail | string|null | URL of the cover frame. Instagram CDN links expire, so mirror the image if you need it long-term. |
| hashtags | string[]|null | Hashtags associated with the reel as bare strings. Null when the upstream payload has no hashtag array — parse the caption yourself if you need a guaranteed list. |
1 credit per reel. Ask for 50 and you are charged for 50; ask for 10 and you are charged for 10. Set your limit to the number you will genuinely use rather than pulling a large page and discarding most of it.
At $0.005 a credit on monthly billing, a reel is half a cent and a 20-item pull is about 10 cents. Annual billing drops the credit to $0.0045.
This endpoint returns a single array of up to `limit` reels. No cursor, page token or offset comes back in the response, so there is no way to resume where a previous call stopped. To reach further back, raise `limit` on a fresh call — the accepted range is 1 to 500, and anything above 50 is run as an asynchronous job rather than answered inline.
That means a deeper pull re-fetches from the top and overlaps with what you already have. Upsert on `id` when you merge, and remember you are billed for every item the larger call returns, not just the new ones.
We read public pages logged out. A private account is not visible to us any more than it is to a logged-out browser, and the call errors rather than returning a partial list. Unavailable and deleted handles behave the same way. Failed calls are not charged.
The field exists in the response for shape compatibility with the other post objects, but Instagram does not surface a public share count on reels, so this endpoint returns null every time. Do not build a metric on it. Saves are not exposed publicly either, which is why there is no saves key at all.
This endpoint sits in the medium cache class, so repeated requests for the same handle inside the window return the stored array immediately with x-cache: hit, at the same credit cost. That is usually what you want — a creator does not post every minute.
Add fresh=true when you specifically need to catch a brand new reel, such as the first call of a monitoring cycle. Counters on reels posted in the last day move fast, so if you are charting growth, sample on a fixed cadence rather than whenever your job happens to run.
Call /v1/instagram/channel-reels with the handle and a limit. The endpoint returns the account's recent reels newest first; raise the limit to reach further back. Instagram does not expose an unlimited public archive, so very deep history on a prolific account may not be fully reachable. For most competitor and research work the last few dozen reels is what carries signal anyway.
100 credits. Billing on this endpoint is 1 credit per reel returned, so 100 reels is 100 credits — about $0.50 on monthly billing at $0.005 a credit, or $0.45 on annual at $0.0045. Cached responses cost the same as fresh ones. Calls that error are never charged.
No. There is no OAuth flow, no app review, no linked Facebook Page. You send a GET with your API key and a handle. Instagram's own Graph API only reaches accounts you have been granted access to, which rules it out for competitor research; this endpoint reads the same public reel pages anyone can open in a browser.
Because Instagram does not publish it. Public reel pages show plays, likes and comments; share and save counts are visible only to the account owner in their own insights. The key is present in the response for consistency with the other post objects, and it will be null. We would rather return an honest null than a number we guessed at.
No. Everything we read is public content fetched logged out, so a private account returns an error and no charge. There is no setting, plan or parameter that changes this. If you manage the account yourself, Instagram's own insights in the app will give you more detail than any public source can.
Channel reels returns only reels — the short vertical video format. Channel posts returns the account's feed content, which includes photos, carousels and feed videos. If you are studying short-form video performance specifically, use this endpoint so your dataset is not diluted by static posts that never had a view count to begin with.
Take the url field from any item and pass it to the Instagram Transcript API. That returns the spoken words as text. A common pipeline is one channel-reels call to discover the reels, then transcript calls on the handful whose view counts stood out, so you are only paying for transcription on content worth reading.