Instagram's API publishes reels and reads your own, from a professional account you log in as. Other accounts' reels come only through Business Discovery, for Business and Creator accounts. ToolzerHub lists any public account's reels by username, 12 per call with play counts but no watch-time metrics; an unknown username returns a 503.
Does Instagram have a reels API?
Yes, as part of the Instagram Platform. Meta's content publishing guide (updated June 30, 2026) shows "how to publish single images, videos, reels (single media posts), or posts containing multiple images and videos (carousel posts) on Instagram professional accounts". There is no separate reels product. A reel is a media object, and Meta's IG Media reference describes media as "an Instagram album, photo, or video (uploaded video, live video, reel, or story)".
| You want | Meta's route | Who |
|---|---|---|
| Publish a reel | media_type=REELS |
Your account |
| Your reels | media edge | Your account |
| Watch time, reach | media insights | Your account |
| Others' reels | Business Discovery | Business or Creator |
| A reels list | none | n/a |
Publishing reels
"To publish a reel, create a container for the video and include the media_type=REELS parameter along with the path to the video using the video_url parameter." Then you publish the container. Reels can't go in carousels, and a published reel reads back as VIDEO: Meta says to "request its media_product_type field instead" to tell it apart.
The daily limit depends on where you read it. The guide's Rate Limit section says "Instagram accounts are limited to 100 API-published posts within a 24-hour moving period", and its carousel section on the same page says "Accounts are limited to 50 published posts within a 24-hour period." The content_publishing_limit edge shows an account's current usage.
Reading reels from other accounts
On your own reels, media insights add watch time, reach and skip rate. For anyone else's, Business Discovery is the route, from an app with Facebook Login and only for Business or Creator targets. Its sample returns view_count for a reel, which Meta describes as "View count for Instagram Reels, which includes both paid and organic metrics", and marks "Available for Business Discovery API only."
The video file is not guaranteed. Meta leaves out media_url for video with copyrighted or licensed audio, and when "The reel owner has turned off downloads for the reel", a rule that applies "only on endpoints that read other users' media, such as business discovery". Meta's advice is to "Treat media_url as an optional field". The IG User reference lists no reels edge, so there is no call that returns an account's Reels tab. We did not call Meta's API; this is from its documentation.
List a public account's reels
We make ToolzerHub. Our Instagram API lists the reels on a public account's Reels tab by username, with one API key and no Meta app. GET /v1/instagram/user/reels returns 12 reels per call and costs 1 credit; pass paging_info.max_id back as cursor until more_available is false (our OpenAPI file, 2026-10-17). Each reel has code, taken_at, play_count, like_count, comment_count and its caption. play_count is the number shown on the Reels tab; we have not compared it with Meta's view_count.
The posts list doesn't replace it. MrBeast's posts list (/v1/instagram/user/posts, paged to the end on 2026-10-16) held 211 reels; his reels list held 705. Our post on getting a user's posts covers that list.
This script writes each account's reels to CSV.
import csv
import os
import sys
import time
from datetime import datetime, timezone
import requests
URL = "https://api.toolzerhub.com/v1/instagram/user/reels"
HEADERS = {"x-api-key": os.environ.get("TOOLZERHUB_API_KEY", "")}
FIELDS = ["account", "owner", "code", "url", "posted_at", "plays", "likes", "comments", "caption"]
calls = 0
def cell(value):
# Spreadsheets run text starting with = + - or @ as a formula; an apostrophe keeps it text.
if isinstance(value, str) and value[:1] in ("=", "+", "-", "@", "\t", "\r"):
return "'" + value
return value
def get(params, tries=4):
# 429 and 503 are retried; the wait comes from the error body or the Retry-After header.
global calls
for attempt in range(tries):
r = requests.get(URL, headers=HEADERS, params=params, timeout=90)
calls += 1
if r.status_code == 400: # malformed username: skip this account
print("bad request:", r.json()["error"]["message"].splitlines()[0])
return None
if r.status_code not in (429, 503) or attempt == tries - 1:
if r.status_code >= 500: # any 5xx, or a 503 past the retries: skip
print(f"HTTP {r.status_code}, skipping:", r.text[:120].replace("\n", " "))
return None
r.raise_for_status()
return r.json().get("data")
try:
wait = r.json()["error"]["details"]["retryAfter"]
except (ValueError, KeyError, TypeError):
wait = None
try:
wait = int(wait or r.headers.get("Retry-After") or 5 * (attempt + 1))
except ValueError:
wait = 5 * (attempt + 1)
time.sleep(min(wait, 60))
def export_account(writer, account, max_pages):
params, seen, pages = {"username_or_url": account}, set(), 0
status = "page cap reached, more available"
while pages < max_pages:
data = get(params)
if not data or not data.get("items"):
status = "stopped early: failed or empty page" if pages else "nothing returned"
break
pages += 1
for item in data["items"]:
reel = item.get("media") or item
key = reel.get("pk") or reel.get("code")
if not key or key in seen: # pages can repeat a reel
continue
seen.add(key)
code = reel.get("code") or ""
caption = (reel.get("caption") or {}).get("text") or ""
writer.writerow({
"account": account, "owner": (reel.get("user") or {}).get("username"), # collabs differ
"code": code, "url": f"https://www.instagram.com/reel/{code}/" if code else "",
"posted_at": datetime.fromtimestamp(reel["taken_at"], timezone.utc).isoformat()
if reel.get("taken_at") else "",
"plays": reel.get("play_count"), "likes": reel.get("like_count"),
"comments": reel.get("comment_count"),
"caption": cell(caption.replace("\r", " ").replace("\n", " ")),
})
info = data.get("paging_info") or {}
if not (info.get("more_available") and info.get("max_id")):
status = "end"
break
params["cursor"] = info["max_id"]
time.sleep(0.3)
print(f"{account}: {len(seen)} reels, {pages} pages ({status})")
return len(seen)
def main(accounts, max_pages="50", out="reels.csv"):
total = 0
with open(out, "w", newline="", encoding="utf-8-sig") as f: # BOM: Excel reads emoji
writer = csv.DictWriter(f, fieldnames=FIELDS)
writer.writeheader()
for account in [a.strip().lstrip("@") for a in accounts.split(",") if a.strip()]:
total += export_account(writer, account, int(max_pages))
print(f"wrote {total} reels to {out} in {calls} calls")
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.exit("usage: python instagram_reels.py spacex,nasa [max_pages] [file.csv]")
if not HEADERS["x-api-key"]:
sys.exit("set TOOLZERHUB_API_KEY first")
main(*sys.argv[1:])
A 400 skips that account. A 429 or 503 is retried with the wait from retryAfter or Retry-After; a 503 that keeps coming back, or any other 5xx, skips the account, and a 429 that outlasts the retries, a 401 or a 402 stops the run with an error. The owner column shows who posted each reel, since collaborative reels from other accounts appear in the list. We tested those branches against a stand-in server, not live.
Run it
export TOOLZERHUB_API_KEY=your_key
python instagram_reels.py "spacex, @bbcnews ,,nosuchuser9q8z7x" 30 reels.csv
Output on 2026-10-17, with a stray space, an @, an empty item and an unknown username added:
spacex: 78 reels, 7 pages (end)
bbcnews: 195 reels, 17 pages (end)
HTTP 503, skipping: {"error":{"code":"SITE_UNAVAILABLE","status":503,"message":"Upstream returned 502","retryable":true,"details":{"reason":
nosuchuser9q8z7x: 0 reels, 0 pages (nothing returned)
wrote 273 reels to reels.csv in 29 calls
It took 186 seconds, partly because the unknown username was tried four times: our route answers an unknown name with a retryable 503 instead of an empty result. SpaceX's reels had a median of about 2.4 million plays. One BBC News page of 12 came back without dates, captions or owner, so those cells are empty in the CSV.
What we measured
All numbers are from 2026-10-17. Each run went until more_available was false; BBC News is from an earlier script run, and its oldest date leaves out 12 undated rows.
| Account | Reels | Calls | Oldest |
|---|---|---|---|
| SpaceX | 78 | 7 | 2022-02-03 |
| BBC News | 207 | 18 | 2022-12-14 |
| NASA | 292 | 25 | 2022-08-01 |
| MrBeast | 705 | 59 | 2022-12-23 |
- The list is not fixed for every account. SpaceX gave 78 both times; BBC News gave 207, then 195 in the run above, with 171 reels in both.
- The counts include collaborative reels posted by other accounts: 39 of BBC News's 195 came from 10 other accounts, and 11 of MrBeast's first 480 on 2026-10-16.
- Every page held 12 reels except the last, with no repeats.
countaccepts up to 50, but Instagram serves 12. - The oldest reel matched the posts list. NASA's posts list, 2,000 posts back to August 2020, held no reel older than 2022-08-01; its older videos are typed
feedorigtv. MrBeast's oldest reel in both lists is 2022-12-23. detail=summaryis lighter and faster (median 1.2 seconds a call against 3.2 on SpaceX) but has no date or caption.- Reliability: in the 7 days to 2026-10-17 the route had 136 successful calls and 1 server error, and 12 repeat calls on four accounts all returned 12 reels.
What it costs
One credit per call of 12 reels, at $0.99 to $1.90 per 1,000 credits ($1.45 on the $29 plan). MrBeast's 705 reels took 59 credits: 6 to 11 cents. 1,000 reels are about 84 calls, 8 to 16 cents. The free tier's 100 credits a month cover about 1,200 reels. Failed calls cost nothing.
Where Meta's API is the better pick
Use Meta's API to publish reels and to read your own reels' average watch time, skip rate and reach. It costs nothing per call and Meta supports it. Our route reads public accounts only, publishes nothing, and returns no watch-time metrics. Business Discovery's view_count counts paid views too; we don't know whether play_count does. For comments on a reel, see getting Instagram comments.
We are not affiliated with Meta Platforms, Inc. or Instagram.
Sources
- Meta, Content publishing (reels, rate limits), https://developers.facebook.com/documentation/instagram-platform/content-publishing, read 2026-10-17
- Meta, IG User media reference (reel containers), https://developers.facebook.com/documentation/instagram-platform/instagram-graph-api/reference/ig-user/media, read 2026-10-17
- Meta, IG Media reference (media_product_type, view_count, media_url), https://developers.facebook.com/documentation/instagram-platform/reference/instagram-media, read 2026-10-17
- Meta, IG Media insights (reels metrics), https://developers.facebook.com/documentation/instagram-platform/reference/instagram-media/insights, read 2026-10-17
- Meta, IG User Business Discovery reference, https://developers.facebook.com/documentation/instagram-platform/instagram-graph-api/reference/ig-user/business_discovery, read 2026-10-17
- Meta, IG User reference (edges), https://developers.facebook.com/documentation/instagram-platform/instagram-graph-api/reference/ig-user, read 2026-10-17
- ToolzerHub OpenAPI file, https://api.toolzerhub.com/openapi.json, checked 2026-10-17
- ToolzerHub pricing, https://toolzerhub.com/pricing, checked 2026-10-17