Give it the URL of a public Instagram post, Reel or carousel and get the engagement numbers back as JSON. 1 credit per post, no Graph API app review, no Business account linkage, no headless browser to keep alive. The call reads the same public page you would open yourself.
| parameter | type | description |
|---|---|---|
| url | string, required | A public Instagram post, reel or profile URL. Share links are resolved. |
| fresh | boolean | Skip the stored copy and read live, at the same price. |
| fields | string | Comma-separated field paths to keep. |
| format | json | JSON envelope. |
1 credit per post. Failed calls are never charged, and empty results are free up to 25 a day. Stored copies are age-aware, 15 minutes to 7 days.
One object per post. Likes and comments, the caption and its hashtags, the media type, when it went up, who posted it, and a thumbnail URL. That is enough to build a content dashboard, back-fill a reporting table, or score a creator's recent output without touching Meta's developer console.
Instagram publishes fewer numbers than it collects, and the response reflects that honestly. View counts only exist for video — Reels and video posts carry a play count, a photo or carousel does not. Share counts are not published anywhere on a public post page, so the `shares` key is always null. It stays in the response so the post shape is stable across endpoints; the reel-shares endpoint reads share counts through a separate upstream add-on.
The identifier we return is the shortcode from the URL (the `ABC123` in /p/ABC123/), not Instagram's internal media id. It is stable for the life of the post and it round-trips into a URL, which makes it a better primary key for most databases.
curl "https://api.instadata.dev/v1/instagram/stats?url=https%3A%2F%2Fwww.instagram.com%2Fp%2FC8xQvZ2sVAb%2F" \ -H "Authorization: Bearer ik_live_..."
{
"data": {
"platform": "instagram",
"entity_id": "C8xQvZ2sVAb",
"url": "https://www.instagram.com/reel/C8xQvZ2sVAb/",
"author": {
"handle": "instagram",
"name": "Example Creator"
},
"posted_at": "2026-06-30T14:05:00Z",
"metrics": {
"views": 1204593,
"likes": 88410,
"comments": 2314,
"shares": 10092
}
},
"request_id": "req_01JZX4M8Q2TE9W"
} | field | type | note |
|---|---|---|
| id | string | The post shortcode taken from the URL — stable for the post's lifetime and usable as a primary key. |
| url | string | Canonical instagram.com permalink. Falls back to a /p/{shortcode}/ URL built from the id if none was published. |
| type | string|null | Media kind as Instagram labels it, e.g. Image, Video, Sidecar (carousel), Clips (Reel). Null when the page does not expose it. |
| caption | string|null | Caption text exactly as posted, hashtags and line breaks included. Null when the post has no caption. |
| views | number|null | Play count. Present for Reels and video posts; null for photos and most carousels, because Instagram publishes no view figure for them. |
| likes | number|null | Public like count. Null when the account has hidden like counts on that post — a per-post setting the owner controls. |
| comments | number|null | Comment count. To read the comment text itself, use the Instagram Comments API. |
| shares | null | Always null — a literal null, never a number or a string. Instagram does not publish a share count on public post pages; the key exists so the post shape is the same on every endpoint. For reels, the reel-shares endpoint reads the count through a separate add-on. |
| duration_sec | number|null | Video runtime in seconds. Null for images and carousels. |
| posted_at | string|null | ISO 8601 UTC publish timestamp. Subtract from now() to get post age for velocity maths. |
| author | object | Nested { handle, name }: the posting account's username and display name. Either key can be null. Follower counts come from the Instagram Channel Stats API, not here. |
| thumbnail | string|null | URL of the post's display image. Instagram CDN links are signed and expire — download the bytes if you need them later, do not store the link. |
| hashtags | string[]|null | Hashtags associated with the post as bare strings. Null when none were found. |
Instagram lets an account hide like counts per post. When that is on, the public page shows no number and we return null for `likes` while `comments` still works normally. Treat null as unknown. Coercing it to 0 will quietly drag down every average you compute over a creator's feed.
The same rule applies to `views` on a photo. Absent is not zero.
A Reel or video post carries a play count. A single photo or a carousel of photos does not, so `views` comes back null. If you are comparing post formats, compare likes and comments across the set and treat views as a video-only metric rather than trying to normalise around the gap.
A carousel that contains a video sometimes reports a count and sometimes does not, depending on how Instagram renders it that day. Code for both.
We read public pages logged out. If the account is private, the post was deleted, or it is geo-restricted where the request lands, the call returns an error instead of a half-filled object. Failed calls are not charged.
This is also why there is no follower-only content here. There is no session to log in with, by design.
The `thumbnail` link points at Instagram's CDN and carries a signature with a lifetime measured in hours to days. Saving it in a database and rendering it two weeks later gives you broken images. Fetch the bytes at ingest time and store them yourself if the image matters.
Responses sit in the fast cache class, so a repeat call for the same post inside the window comes back in milliseconds with x-cache: hit. A hit costs the same 1 credit as a miss. Pass fresh=true to skip the cache — worth doing on the first read of a monitoring cycle, wasteful on every read.
Send a GET to /v1/instagram/stats with the post URL and your API key. There is no app review, no Business or Creator account requirement, and no OAuth token to refresh. Meta's Graph API only returns insights for accounts you hold a token for, which rules it out entirely for competitor research or influencer vetting. This endpoint reads the public post page instead.
Because the post is not a video. Instagram publishes a play count for Reels and video posts only; photos and photo carousels have no public view figure, so we return null rather than inventing one. If you need a number for every post in a set, use likes and comments as your comparable metrics and treat views as video-only.
No. Instagram does not show a share count on public post pages, so no tool reading public data can report one, including this one. The `shares` key is present in the response and always null so your parsing code does not have to branch per endpoint. For reels, the reel-shares endpoint reads the count through a separate upstream add-on and is priced accordingly.
1 credit per post. Credits are $0.005 each on monthly billing and $0.0045 on annual, so a call is half a cent or less and $5 covers roughly a thousand posts. Cached responses cost the same as fresh ones. Calls that fail — private account, deleted post, bad URL — are never charged.
Yes. Reel URLs (/reel/…), photo posts (/p/…) and carousels all go to the same endpoint at the same price. The `type` field tells you which one you got back, and Reels additionally carry `views` and `duration_sec`. You do not need to detect the format before calling.
One URL per call. Run them concurrently — each call is independent and the API expects parallel traffic. If you are starting from an account rather than a list of links, the Instagram Channel Posts API returns a list of recent posts in one call, and those URLs drop straight into this endpoint.
We only read pages that any logged-out visitor can load, and we do not touch private accounts, follower-only content or personal data behind a login. That said, what you may do with the data depends on your jurisdiction and your purpose — aggregate analytics sits very differently from profiling individuals. Check with your own counsel before building anything that stores data about identifiable people.