One handle in. Clean JSON out.
Give it a public Instagram handle and get that account's recent feed posts back as an array of JSON objects — caption, engagement counts, timestamp, media type and thumbnail for each one. One call returns one array sized by `limit` — there is no cursor to follow — and billing is per post returned, at 2 credits each, so a default call of 20 costs 40 credits. No Graph API app review, no Business account linkage, no Page token.
The difference
On the left, what a headless browser hands you. On the right, what the endpoint hands you.
<article class="_aagv _ab8w x1n2onr6" role="presentation"><div class="x9f619 xjbqb8w x78zum5"><div class="_aagu"><img alt="Photo by @creator" class="x5yr21d xu96u03" src="https://scontent.cdninstagram.com/v/t51...blob"/></div><section class="x6s0dn4 x78zum5 xdt5ytf"><span class="x1lliihq _aacl _aaco">55,210 likes</span><div class="_a9zs"><span dir="auto">Three settings you should change today</span></div><span class="_aacl _aaco x1i10hfl">View all 981 comments</span></section><time class="_aaqe" datetime="2026-07-03T12:00:00.000Z">18h</time></div><script type="application/json" data-sjs>{"require":[["ScheduledServerJS","handle",null,[{"__bbox"... {"data": [{"id": "C8xQvZ2sVAb","url": "https://www.instagram.com/reel/C8xQvZ2sVAb/","caption": "Three settings you should change today","posted_at": "2026-07-03T12:00:00Z","metrics": {"likes": 55210,"comments": 981}}],"meta": {"count": 2,"limit": 20,"item": "post"},"request_id": "req_01JZX4M8Q2TE9W"}
The payload
An array under `data`, newest post first, one object per post on the account's grid. Each object carries the shortcode as its id, the canonical permalink, the caption text, like and comment counts, the publish timestamp, a thumbnail URL and a small nested author block. Reels and video posts also carry a play count and a runtime.
The shape is deliberately the same object the Instagram Stats API returns for a single URL, so a list call and a detail call are interchangeable in your storage layer. Upsert on `id` and you can mix the two without writing a second mapper.
You control how much comes back with `limit`, which defaults to 20 and accepts anything from 1 to 500. Requests above 50 are executed as an asynchronous job instead of being answered inline. There is no cursor, page token or offset in the response, so how far back you reach is decided entirely by `limit` on a single call. Cost scales with what you actually receive: ask for 50 posts, pay for 50 posts. Ask for 5 and pay for 5.
Play count for video and reel posts. Always null on still images and carousels — Instagram does not publish a view count for those.
Pricing
Each post returned costs 2 credits — about 1¢ on the monthly plan. Billing is per item, so a default 20-post call runs 20¢, and an empty result still costs 1 credit.
Estimate only, on a full-year basis. 2 credits per returned post. Monthly: $5 per 1,000 credits with $4/1,000 top-ups. Annual: $54 per 12,000 credits with $3/1,000 top-ups. We show whichever plan is cheaper for your annual volume, divided by 12. Failed calls are never charged; cache hits cost the same as fresh calls.
Entry price, side by side
Credits are not equivalent units across vendors — each meters differently. Price your own workload on both before deciding on entry price alone. At high volume, several of these are cheaper per credit than we are.
Engineering notes
We document exactly how every endpoint behaves — nulls, caching, billing — so what you ship on day one is still running in month six. No surprises, no support tickets.
We read Instagram the way a logged-out visitor does. If an account is private, its grid is not public, so there is nothing to return and the call errors rather than handing back an empty array dressed up as success. Failed calls are not charged.
Check `is_private` on the Instagram Channel Stats API first if you are working through a list of handles of unknown quality. One stats call is cheaper than a failed page attempt plus a retry.
Billing is 2 credits per post returned, not per request. A `limit=50` call costs 100 credits; a `limit=5` call costs 10. Set `limit` to what you will actually store, because you pay for every item that comes back whether or not you read it.
There is no cursor, page token or offset in the response. One call returns one array and that is the end of it. To reach further back you raise `limit` and call again from the top — which re-fetches everything you already had, and bills you for it a second time. Upsert on `id` when you merge.
`limit` accepts 1 to 500, and anything above 50 runs as an asynchronous job rather than an inline response. Instagram will sometimes return fewer posts than you asked for on accounts with a short or hard-to-reach back catalogue; that is the end of what is publicly reachable, not a bug, and you are only billed for what arrived.
More fields go null here than on other platforms because Instagram lets creators hide like counts per post, disable comments, and post without captions. `views` is null on every image and carousel, and `shares` is null on everything — Instagram publishes no public share figure.
Do not treat a null count as zero in an average. Filter those posts out of the denominator or your engagement rate will drift low on accounts that hide likes.
The `thumbnail` URL points at Instagram's CDN. Those links carry signed expiry parameters and stop working after a while, so storing the string and rendering it a week later will give you broken images. Fetch the bytes at ingest time and put them in your own bucket if the image needs to persist.
Responses cache in the medium class. Calling the same handle with the same limit twice in a row returns the second one from cache with `x-cache: hit`, in milliseconds, at the same credit cost. Add `fresh=true` when you specifically need to catch a post published minutes ago — a daily competitor sweep does not need it.
Questions
Send a GET to /v1/instagram/channel-posts with the handle and your API key. Instagram's Graph API only reaches accounts you own or manage, and requires a Business account, a linked Facebook Page and app review. This endpoint reads the public grid of any public account, so competitor and creator research works without any of that setup.
200 credits. Billing is 2 credits per post returned, so 100 posts is 200 credits — about $1.00 on the monthly plan at $0.005 per credit, or $0.90 on annual. That is one call with `limit=100`; because the limit is above 50 it runs as an asynchronous job rather than returning inline. Failed calls are not charged.
As far as a single call with a high `limit` reaches, which varies by account. The maximum `limit` is 500, and there is no cursor to continue past whatever that call returns. Recent posts are reliable; the deeper into a large back catalogue you ask, the more likely Instagram returns fewer items than you requested. There is no fixed cutoff we can promise, and no way to resume a deeper crawl — if a `limit=500` call comes back with 180 posts, 180 posts is what is publicly reachable for that handle.
Because Instagram only publishes a play count for video content. Still images and carousel posts have no public view figure, so `views` is null on them rather than zero. Likes can also be null when the creator has hidden the like count on that specific post. Treat null as absent data, not as an engagement of zero.
Reels can appear in the grid results and are labelled through the `type` field, but this endpoint is scoped to the main profile feed. If reels are what you are analysing, use the Instagram Channel Reels API — it targets them directly and gives cleaner coverage than filtering these results after the fact.
No. We read only what a logged-out browser can see, so a private account returns an error and no charge. There is no setting, plan or parameter that changes this. If you are running a list of handles, check the account's `is_private` flag with the Instagram Channel Stats API first and skip the private ones.
Not entirely. The `hashtags` array comes from the upstream page and is sometimes null even on captions that clearly contain tags. If hashtag analysis is central to your project, parse `caption` yourself with a simple regex and use `hashtags` only as a fallback. The caption text itself is the more dependable field.
Next
100 trial credits on signup — no card, key on screen immediately.