If you are three days into Meta's login flow and still not holding a working token, stop and answer one question first: are you pulling data for accounts that authorize you, or public data about accounts that never will?
That single question decides whether you need any of it. The Graph API and its OAuth chain are mandatory for owned-account insights, the private metrics only the account holder can see. Public profile and post data is a different problem with a different answer, and a lot of people grind through app review before realising most of what they wanted sat on the public side the whole time.
Does Instagram support OAuth?
Yes, and that is the part people underestimate. It is not one login. A working Instagram Graph integration walks a chain: Facebook Login, then a Business Login permission grant, then the Facebook Page, then the Instagram professional account connected to that Page, and only then the access token you actually make calls with. Each hop has its own token type and its own expiry, and the docs for each hop live in a different place.
The common experience is losing an entire day just working out which APIs are needed and which token belongs where, with the official documentation as the hardest part of the job. Parts of it are occasionally wrong, and things break when Meta ships changelog updates.
None of that is a reason to avoid the Graph API if you need what it returns. It is a reason to be certain you need it.
What genuinely requires the Graph API
Anything the account holder sees and the public does not:
- Reach, impressions, saves, and profile-visit counts
- Story views and story interaction metrics
- Audience demographics and follower breakdowns
- Publishing, comment moderation, and DM access
- Historical insight windows tied to the account
If your product is an analytics dashboard for a client's own account, or a scheduler that posts on their behalf, you need OAuth. Build it properly: get long-lived tokens, refresh them on a schedule, and assume the changelog will break you a couple of times a year.
Is there a public Instagram API?
Not an official one. Meta retired the old public Instagram API years ago, and the current Basic Display replacement still authenticates as a user. But public profile and post data is publicly rendered, and reading it does not involve OAuth, an app review, or a Facebook Page.
What is available without any login:
- Profile fields: username, full name, follower and following counts, media count, bio, external URL, verified and private flags
- Post fields: shortcode, media type, like and comment counts, timestamp, caption, media URLs
- Public comment threads, hashtag and user search, public reels and tagged posts
That covers most competitor research, creator vetting, campaign tracking, and lead-enrichment use cases. It does not cover anything private, and no vendor can sell you private data without the account's consent.
Is there a free Instagram API?
Meta's Graph API has no per-call fee, so it is "free" in the sense that the cost is your engineering time and the app review process. For public data, the honest answer is that you are choosing between maintaining a collection layer yourself or paying someone per call.
The self-hosted route is not free either. The recurring cost is not writing the scraper, it is the week Instagram changes a layout, your parser dies quietly, and nobody notices until someone asks why the numbers went flat. That is the line item that never makes it into the build-versus-buy spreadsheet.
Evaluating a managed public-data vendor
Teams weighing a managed provider against building in-house usually evaluate on four axes: reliability, field coverage, operational effort, and vendor dependence. Those are the right axes. Here is what actually separates vendors on each.
Test the failure cases before the happy path. Request a private account, a deleted account, and an account that never existed. Some APIs return HTTP 200 with an empty or status-flagged body rather than a 4xx, which means a naive integration cheerfully stores nulls and bills you for it. You want to know that behavior on day one, not after a backfill. Check whether failed lookups are billed, too, because several providers charge for them.
Check how long media URLs live. Instagram serves images and video from a signed CDN, and those links expire in hours. A response that hands you image_versions2 or video_versions entries is giving you a URL with a clock on it. If you are persisting media, you have to fetch and rehost it during the same job. Storing the link is storing garbage.
Diff one real response against the documentation. Field coverage claims drift from actual payloads. Pull a live response, print the keys, and compare. This takes ten minutes and it is the single highest-value thing you can do during a trial.
Read the pricing model, not the price. Per-call, per-row, and bandwidth-based pricing produce wildly different bills for the same job. A 5,000-profile backfill can be twenty dollars or four hundred depending on which model you picked, and the per-unit headline number tells you nothing about which.
On vendor dependence: building in-house does not remove the dependency, it just moves it. You are still dependent on Instagram, only now without a support address. The real mitigation is architectural. Keep your own storage schema, normalize at the boundary, and never let a vendor's response shape leak into your database. Do that and switching providers is a day of work instead of a rewrite.
What a public lookup actually returns
A profile call against a managed API returns the public fields directly, no token dance:
curl -X POST https://api.scavio.dev/api/v1/instagram/profile \
-H "Authorization: Bearer $SCAVIO_API_KEY" \
-H "Content-Type: application/json" \
-d '{"username": "nasa"}'{
"data": {
"pk": 528817151,
"username": "nasa",
"full_name": "NASA",
"follower_count": 104397074,
"following_count": 92,
"media_count": 4884,
"is_private": false,
"is_verified": true,
"biography": "Making the seemingly impossible, possible.",
"external_url": "https://www.nasa.gov"
},
"response_time": 812,
"credits_used": 10
}Posts come back with the fields you would expect to aggregate on, including code (the shortcode), media_type, like_count, comment_count, and taken_at as a Unix timestamp. Note that caption is an object rather than a plain string, which is the kind of thing you only learn by pulling a real response rather than reading a field list.
The decision, compressed
Owned-account metrics mean OAuth, and there is no way around it. Public data means no OAuth, and your real choice is maintaining a parser or paying per call.
If it is the second one, evaluate on failure behavior, media URL lifetime, payload-versus-docs drift, and pricing model. Those four questions separate vendors far more reliably than a feature table does.
Scavio covers the public side across sixteen Instagram endpoints, documented at Instagram API with full request and response reference in the Instagram API docs. One key, no OAuth chain, no app review. If your project also needs the private metrics, you will still be writing the Graph integration, and this post does not change that.