Meta shut down the Instagram Basic Display API on December 4, 2024, and nothing replaces it for personal accounts. The two APIs that remain work only for Instagram Business and Creator accounts. We read Meta's documentation on 2026-10-16.
What Meta says about the shutdown
Meta's changelog entry for December 4, 2024 reads: "The Instagram Basic Display API has been deprecated. All requests to the Instagram Basic Display API will return an error message." The entry applies to all versions (changelog updated October 5, 2026).
Meta's announcement of September 4, 2024 gave 90 days' notice and said the API was "used to connect Instagram accounts to third-party consumer apps". It ends with the line that matters for personal accounts: "After December 4th, 2024, there will no longer be a set of Instagram APIs for consumer developer apps." Meta's old Basic Display URL now redirects to its Instagram Platform page (/documentation/instagram-platform).
The replacement works only for professional accounts
Meta points Basic Display developers to the Instagram API with Instagram Login or the Instagram API with Facebook Login. The overview page (updated September 28, 2026) says: "To use the APIs, your app users must have an Instagram professional account. An Instagram professional account can be for a business or creator."
| Instagram Login | Facebook Login | |
|---|---|---|
| Facebook Page | Not needed | Required |
| Host | graph.instagram.com |
graph.facebook.com |
| Token | Instagram User | Facebook User or Page |
| Hashtag search | No | Yes |
| Business Discovery | Not documented | Yes |
| Publishing, insights | Yes | Yes |
Serving accounts you don't own needs Advanced Access, which requires App Review and Business Verification. We found no Meta page that lets a personal account connect to either API.
What Business Discovery can read about other accounts
Business Discovery is the official way to read another account's profile and post metrics. (oEmbed returns embed HTML for a single public post, and Meta's terms bar using it for analytics.) Meta's reference says it is "Available for the Instagram API with Facebook Login" and returns data about "another Instagram Business or Creator" account. Data about age-gated accounts is not returned.
You call it on your own professional account's ID (Meta's sample uses 17841405309211844) with the other account's username: GET /17841405309211844?fields=business_discovery.username(bluebottle){followers_count,media_count,media}. The public fields include biography, followers_count, media_count, username and website, and the media edge can expand to comments_count, like_count and view_count. Meta notes that view_count includes paid and organic views, and that a direct request for any returned media object fails with insufficient permissions.
The token needs instagram_basic, instagram_manage_insights and pages_read_engagement (plus ads_read or ads_management if your Page role came through Business Manager). Business Discovery falls under Graph API Platform Rate Limits and uses a user token, and Meta does not publish the call count for user tokens. The media edge pages with before and after cursors only.
What you can do instead for public accounts
We make ToolzerHub. Our Instagram API reads a public profile or its posts from a username, with one API key and no Meta app, no Facebook Page and no professional account of your own. This script writes profiles and recent posts to two CSV files. To page an account's whole posts list, see Instagram API get user posts.
import csv
import os
import sys
import time
from datetime import datetime, timezone
import requests
BASE = "https://api.toolzerhub.com/v1/instagram"
HEADERS = {"x-api-key": os.environ["TOOLZERHUB_API_KEY"]}
PROFILE_FIELDS = ["username", "user_id", "full_name", "verified", "private", "followers",
"following", "external_url", "biography"]
POST_FIELDS = ["username", "code", "posted", "type", "likes", "comments", "caption", "url"]
def cell(value):
# Spreadsheets run text that starts 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(path, params, tries=4):
# 429 and 503 are retryable.
for attempt in range(tries):
r = requests.get(f"{BASE}/{path}", headers=HEADERS, params=params, timeout=90)
if r.status_code not in (429, 503) or attempt == tries - 1:
r.raise_for_status()
return r.json()["data"]
time.sleep(5 * (attempt + 1))
def profile_row(p):
return {
"username": p["username"],
"user_id": p["id"],
"full_name": p.get("full_name"),
"verified": p.get("is_verified"),
"private": p.get("is_private"),
"followers": (p.get("edge_followed_by") or {}).get("count"),
"following": (p.get("edge_follow") or {}).get("count"),
"external_url": p.get("external_url"),
"biography": (p.get("biography") or "").replace("\n", " "),
}
def post_row(username, m):
return {
"username": username,
"code": m["code"],
"posted": datetime.fromtimestamp(m["taken_at"], timezone.utc).isoformat(timespec="minutes"),
"type": m.get("product_type"),
"likes": m.get("like_count"),
"comments": m.get("comment_count"),
"caption": ((m.get("caption") or {}).get("text") or "").replace("\n", " "),
"url": f"https://www.instagram.com/p/{m['code']}/",
}
def main(usernames, limit="24"):
limit = int(limit)
n_profiles = n_posts = n_calls = 0
with open("profiles.csv", "w", newline="", encoding="utf-8") as pf, \
open("posts.csv", "w", newline="", encoding="utf-8") as qf:
profiles = csv.DictWriter(pf, fieldnames=PROFILE_FIELDS)
posts = csv.DictWriter(qf, fieldnames=POST_FIELDS)
profiles.writeheader()
posts.writeheader()
for name in [u.strip() for u in usernames.split(",") if u.strip()]:
profile = get("user/info", {"username_or_url": name})
n_calls += 1
if not profile: # unknown usernames return 200 with data null
print(f"{name}: not found")
continue
n_profiles += 1
profiles.writerow({k: cell(v) for k, v in profile_row(profile).items()})
cursor, got = None, 0
while got < limit:
params = {"user_id": profile["id"], "count": min(50, limit - got)}
if cursor:
params["cursor"] = cursor
page = get("user/posts", params)
n_calls += 1
for m in page["items"][: limit - got]:
posts.writerow({k: cell(v) for k, v in post_row(name, m).items()})
got += 1
cursor = page.get("next_max_id")
if not page.get("more_available") or not page["items"]:
break
n_posts += got
print(f"wrote {n_profiles} profiles and {n_posts} posts, {n_calls} calls")
if __name__ == "__main__":
if len(sys.argv) < 2:
sys.exit("usage: python instagram_profile_posts.py user1,user2 [posts_per_user]")
main(*sys.argv[1:])
/v1/instagram/user/info takes a username and returns the profile. /v1/instagram/user/posts returns up to 50 posts per call and a next_max_id that you pass back as cursor for the next page. cell() puts an apostrophe in front of text that starts with =, +, - or @, so a spreadsheet shows it as text.
Run the script
export TOOLZERHUB_API_KEY=your_key
python instagram_profile_posts.py nasa,mrbeast,natgeo 60
Output on 2026-10-16: wrote 3 profiles and 180 posts, 9 calls, in 38.8 seconds. Each account needed one profile call and two post calls (50, then 10). The profile file:
| username | followers | following | verified |
|---|---|---|---|
| nasa | 104,375,026 | 90 | yes |
| mrbeast | 90,969,166 | 1,013 | yes |
| natgeo | 268,361,712 | 195 | yes |
The first posts of the NASA file:
| posted | type | likes | comments |
|---|---|---|---|
| 2026-10-10 | clips | 688,608 | 6,824 |
| 2026-10-06 | feed | 257,196 | 790 |
| 2026-10-02 | carousel_container | 1,240,275 | 4,892 |
Notes on the 180 rows:
- Median likes were about 170,300 for nasa, 879,200 for mrbeast and 57,000 for natgeo.
- In all three accounts the first three rows are older than the rest. Pinned posts are the likely cause, which we did not confirm, so sort by
postedif you need newest first. Without those rows, dates ran from 2026-03-05 to 2026-10-09 for mrbeast and 2026-09-29 to 2026-10-16 for natgeo. typeis Instagram's own label:clipsis a reel,feeda single photo or video,carousel_containera multi-image post.- No post had a view count in the list. Reel views come from
/v1/instagram/post/viewsat 1 credit per reel. On 2026-10-16 it returned 23,543,099video_view_countand 61,516,871play_countfor one mrbeast reel. They are different metrics:video_view_countis the embed view count, andplay_countis the plays shown on the owner's Reels tab, available only for their 36 newest reels.
The request carries only a username and works the same for any public account; the response has no account-type field. We tested public accounts only.
Where Meta's API is the better pick
Use Meta's API when the account is yours or your customers' and they can sign in: reach and impressions, publishing, comment moderation and messaging exist only there. Our API reads what a signed-out visitor sees, with no login flow and no write access.
Smaller gaps in what we returned on 2026-10-16:
detail=fullon/v1/instagram/user/infocame back withis_partial: trueandfull_profile_unavailablefor both nasa and mrbeast, so there was nomedia_count. Business Discovery returnsmedia_count.- Posts carry
like_countandcomment_count, but no insights fields. - We return public data only and did not test private accounts.
- In the 7 days to 2026-10-16,
/v1/instagram/user/inforeturned 503 on 4.6% of 13,794 calls; the script above retries 503 and 429./v1/instagram/user/postshad 35 calls in that window, so we ran 10 more live accounts and all 10 returned posts.
What it costs
Each call is 1 credit. The run above used 9 credits: 1 to 2 cents at our rates of $0.99 to $1.90 per 1,000 credits ($1.45 on the $29 plan). At 50 posts per call, 1,000 posts from one account is 20 post calls plus 1 profile call: 21 credits, or 2 to 4 cents. The free tier gives 100 credits a month. For comments on a post, see how to export Instagram comments; for comments and keyword search in one script, see our Instagram scraper in Python.
We are not affiliated with Meta Platforms, Inc. or Instagram.
Sources
- Meta, Instagram Platform changelog (entry for December 4, 2024; page updated October 5, 2026), https://developers.facebook.com/documentation/instagram-platform/changelog, read 2026-10-16
- Meta, Update on Instagram Basic Display API (September 4, 2024), https://developers.facebook.com/blog/post/2024/09/04/update-on-instagram-basic-display-api/, read 2026-10-16
- Meta, Instagram Platform overview (updated September 28, 2026), https://developers.facebook.com/documentation/instagram-platform/overview, read 2026-10-16
- Meta, Instagram API with Facebook Login: Business Discovery (updated August 12, 2026), https://developers.facebook.com/documentation/instagram-platform/instagram-api-with-facebook-login/business-discovery, read 2026-10-16
- Meta, IG User Business Discovery reference, https://developers.facebook.com/documentation/instagram-platform/instagram-graph-api/reference/ig-user/business_discovery, read 2026-10-16
- Meta, IG User reference (public fields), https://developers.facebook.com/documentation/instagram-platform/instagram-graph-api/reference/ig-user, read 2026-10-16
- Meta, Graph API rate limiting (Platform Rate Limits), https://developers.facebook.com/docs/graph-api/overview/rate-limiting, read 2026-10-16
- ToolzerHub Instagram reference, https://api.toolzerhub.com/openapi.json, checked 2026-10-16
- ToolzerHub pricing, https://toolzerhub.com/pricing, checked 2026-10-16