A Facebook Reel and a Facebook feed video are the same object as far as publishing is concerned, and two different objects as far as analytics are concerned. They do not return the same metrics. The one most people reach for first — a completion rate — exists for feed video and does not exist for Reels at all, because Meta does not report one.
That asymmetry is the whole reason this is confusing. So rather than a tour of the API, here is the metric set for each video type, what Meta actually gives you, and what you have to compute or live without.
If you are looking for how to post a Reel rather than measure one, that is on the Facebook API page, which covers the upload, the cover image and the specs. This post is only about reading the numbers back.
What Facebook returns for a Reel
One call, GET /v1/posts/{id}/analytics, returns metrics per social account the post went to, plus aggregated totals. For a Facebook Reel the video-specific fields are:
Field | What it means |
|---|---|
| Plays excluding replays |
| Plays including replays |
| Replay count |
| Average time spent watching, in milliseconds |
| Total watch time across all plays, replays included, in milliseconds |
| Page followers gained from this Reel |
| The retention graph — opt in, see below |
Plus the engagement fields every post has: likes, comments, shares, impressions, reach, engagement_total, engagement_rate.
Two things to internalise from that table. views and total_plays are not the same number, and the gap between them is your replay volume — which, for a Reel, is often the more interesting figure. And watch time is in milliseconds, not seconds; an average_watch_time_ms of 4200 is 4.2 seconds, and treating it as 4,200 seconds is the kind of bug that makes a dashboard look plausible and be wrong by three orders of magnitude.
media_product_type tells you which kind of object you are holding. It is one of FEED, REELS or STORY, and you should branch on it rather than inferring the type from which fields came back non-null.
The metric Reels do not have
approx_completion_rate is Facebook regular video only — the share of views that reached 97% of the video. It is approximate because Meta has no true completion metric, and for Reels it has none at all. So the field is simply absent from a Reel's metric set rather than returned as zero.
If you need a completion-like number for a Reel, the honest substitutes are average_watch_time_ms against the Reel's duration, or the last point of the retention graph, which roughly approximates the completion share. Both are estimates. Neither is a completion rate, and labelling one as such in a client-facing report is how you end up defending a number you cannot source.
The retention graph
Retention is the part nothing else on our site covers, and it is opt-in because it costs an extra Graph API request per video:
1curl "https://api.outstand.so/v1/posts/POST_ID/analytics?include=retention" \
2 -H "Authorization: Bearer YOUR_API_KEY"include is a comma-separated list of costlier metrics. retention is ignored for other networks and for non-video posts, so you can pass it unconditionally in a mixed-network report without special-casing.
What comes back under metrics.retention is an array of at most 41 points:
1"retention": [
2 { "t": 0, "pct": 100 },
3 { "t": 1, "pct": 86.4 },
4 { "t": 2, "pct": 71.9 },
5 { "t": 40, "pct": 18.2 }
6]t is a position key returned by Meta, ascending — an interval index over the video, not a timestamp in seconds. pct is the percentage of plays still watching at that position, 0–100. Meta samples the points; you do not choose the resolution, and a short Reel will come back with fewer than 41.
Reading it: the drop between t: 0 and t: 1 is your hook, and it is usually the steepest segment in the array. The last point roughly approximates the completion share. A shelf — a long run of near-identical pct values — means people who got that far mostly finished. The whole array is null when Meta did not report it, which is not the same as a flat zero.
Reels vs feed video vs Stories
Metric | Reel | Feed video | Instagram Story |
|---|---|---|---|
| plays excluding replays | yes | yes |
| yes | — | — |
| yes | yes | — |
| yes | yes | — |
| no — Meta reports none | yes | — |
| yes | — | — |
| with | with | — |
| yes | yes | not supported, returns |
| — | — | yes |
Instagram Stories are in that table because they are the sharpest edge case: their insights are only queryable for roughly 24 hours after publish. After that the endpoint returns metrics: null with metrics_error.code: "metrics_expired" for that account. If a Stories number matters to you, you have to collect it on the day.
Instagram Reels are a fourth shape again — they add skip_rate, the share of views skipped within the first three seconds, which has no Facebook equivalent. Meta marks it as estimated and in development, so treat it as directional.
What is not available, and how you can tell
This is the section worth reading before you design a schema, because the API distinguishes three states that are easy to collapse into one.
- A measured zero stays
0. Nobody watched it is a fact, and it is reported as a fact. - An unreported metric is
null, and it is named inplatform_specific.unavailable_fields. That list is the thing to log.nullon its own does not tell you whether Meta refused the metric, does not support it for this object type, or has not computed it yet — the named list is how you find out which fields were actually asked for and did not come back. engagement_totalandengagement_ratearenullwhen the counts they derive from are unavailable rather than being computed from a partial set. Aggregated totals across accounts sum only available measurements, so a total can be partial; engagement-rate averages include measured zeros and exclude unavailable rates.
Meta's own raw metric names are under platform_specific.video, alongside the video id — useful when you need to reconcile a figure against Business Suite. The names you will see there include post_video_avg_time_watched for Facebook and ig_reels_avg_watch_time, ig_reels_video_view_total_time and reels_skip_rate on the Instagram side.
Two operational constraints that are not metric gaps but will look like them:
- Reading video insights needs the
read_insightspermission, and the connected Page user needs the Analyze task. Without it you get no video fields, and the failure is a permission problem rather than an empty Reel. - Instagram data can lag up to 48 hours. A Reel published this morning with thin numbers this afternoon is usually not a measurement bug.
Why the Graph API route is more work than it looks
You can of course read all of this from Meta directly. What you take on by doing so: insights live on versioned edges, so a Graph API version bump can change or retire a metric under you; the video fields come from a different edge than the engagement counts, so one post is several requests; the retention graph is another request again; and Meta's deprecations land as runtime errors rather than warnings. We hit exactly that — fetching Facebook Stories and Reels analytics started failing with a "singular statuses API is deprecated" error, which we had to absorb and repair on our side.
The reason to use one endpoint instead is not that the Graph API is hard to call. It is that the mapping — which metric exists for which media_product_type, which name Meta uses this version, which absence is a null and which is a zero — is the part that rots, and it is better maintained in one place than in your reporting code.
Common questions
Can I get Facebook Reels views via the API? Yes — views on GET /v1/posts/{id}/analytics, counting plays excluding replays. Use total_plays if you want replays included.
Does the Facebook API return watch time? Yes, as average_watch_time_ms and total_watch_time_ms, both in milliseconds, with total watch time including replays.
What is the Facebook Reels insights endpoint? Through Outstand it is GET /v1/posts/{id}/analytics, with ?include=retention for the retention graph. There is no separate Reels-only route; you branch on media_product_type.
Is there a completion rate for Reels? No. Meta reports none. approx_completion_rate is feed video only — use average watch time or the last retention point, and label it as an estimate.
Does this work for Reels I did not publish through Outstand? Yes. Facebook video and Reel insights work for imported posts as well as ones published through the API, and Reels are included in Facebook Page post imports.
Where to go next
The post analytics reference documents every field above with its per-network behaviour, the Facebook configuration guide has the Page permissions and connection requirements, and the social media analytics API guide covers the same endpoint across every network we support rather than just Facebook video.
If the reason you want these numbers is a report somebody else reads, exportable social media reports is the shorter path — the retention graph and watch-time fields are the ones worth putting in front of a client, and the unavailable_fields list is what keeps a report honest about what it could not measure.