This guide covers Instagram profile and post lookups via Social Fetch's /v1/instagram/** routes, with runnable examples below. It also explains what DIY browser scraping and Meta's Graph API actually involve on this platform. For the generic build-vs-buy comparison, see Social Fetch vs DIY scraping.
The shortest path is a single request:
curl -sS \
-H "x-api-key: $SOCIALFETCH_API_KEY" \
"https://api.socialfetch.dev/v1/instagram/profiles/instagram"You'll need an API key and curl or the TypeScript SDK. New to the API? Start with the Quickstart.
DIY browser scraping on Instagram
A plain fetch() to instagram.com gets blocked almost immediately — Instagram inspects TLS fingerprints, cookies, and request patterns. The numbers you care about sit in embedded GraphQL / shared-data JSON blobs, not the DOM.
from playwright.async_api import async_playwright
import asyncio, random
async def scrape_instagram_profile(username: str):
async with async_playwright() as p:
browser = await p.chromium.launch(
headless=False,
proxy={
"server": "http://residential-proxy.example:9000",
"username": "user",
"password": "pass",
},
)
context = await browser.new_context(
user_agent=pick_real_user_agent(),
locale="en-US",
timezone_id="America/New_York",
)
page = await context.new_page()
await page.goto("https://www.instagram.com/", wait_until="networkidle")
await asyncio.sleep(random.uniform(2.0, 5.0))
await page.goto(
f"https://www.instagram.com/{username}/",
wait_until="networkidle",
)
# Profile fields usually live in embedded GraphQL / shared-data JSON,
# not in stable DOM selectors. You still parse opaque blobs after this.
html = await page.content()
await browser.close()
return htmlA working DIY pipeline also needs:
- Residential or mobile proxies. Datacenter IPs are flagged within a few hits.
- Session and login-wall handling. Public pages often redirect into login or challenge flows mid-cron.
- GraphQL document churn. Query hashes and
doc_idvalues move without a changelog. A parser that worked Tuesday returns empty arrays Friday. - Behavioral pacing. Fixed intervals read as a bot, so you add randomized delays and cap concurrency.
Instagram quietly renames internal fields and reshapes media objects. A scraper that looked solid in staging drifts in production.
Meta Graph API limits
Meta's Instagram developer products fit apps inside Meta's ecosystem — publishing on a Business or Creator account you manage, reading insights for assets that granted access, or messaging with approved permissions:
- Instagram Graph API exposes profiles, media, insights, and comments for accounts you own or that authorize your app. App review and Business verification sit in front of most production scopes.
- Basic Display / consumer login paths (where still relevant) are for user-authorized personal data — not bulk competitor enrichment.
- Marketing / ads APIs cover campaigns and ad accounts, not arbitrary public creator lookups.
The ownership wall is intentional. Check Meta for Developers before building — terms and product names change often.
Using the Social Fetch API
Social Fetch exposes Instagram under documented /v1/instagram/** routes — profiles, posts, reels, stories/highlights, search, comments, transcripts, and more. One header authenticates every call; responses share the same data + meta envelope across platforms.
Hover underlined tokens for details.
Get a profile
The same lookup in cURL, the TypeScript SDK, Python, and more — switch tabs to match your stack:
const response = await fetch(
"https://api.socialfetch.dev/v1/instagram/profiles/instagram",
{
headers: {
"x-api-key": process.env.SOCIALFETCH_API_KEY,
},
}
);
const body = await response.json();
console.log(response.status, body);Most Instagram profile lookups are 1 credit when the lookup completes (including private / not_found outcomes that still return HTTP 200). Trust meta.creditsCharged on every response.
List a profile's posts
const response = await fetch(
"https://api.socialfetch.dev/v1/instagram/profiles/instagram/posts",
{
headers: {
"x-api-key": process.env.SOCIALFETCH_API_KEY,
},
}
);
const body = await response.json();
console.log(response.status, body);Full parameters: Get Instagram profile and Profile posts. Reels, highlights, search, and transcripts sit next to them in the API reference. Profile post and reel list routes are also 1 credit per completed page.
Paginate through everything
Post and reel list endpoints return one page plus a cursor. Pass the cursor back verbatim until it's gone:
import { SocialFetchClient } from "@socialfetch/sdk";
const client = new SocialFetchClient({
apiKey: process.env.SOCIALFETCH_API_KEY!,
});
const allPosts = [];
let cursor: string | undefined;
do {
const result = await client.instagram.getProfilePosts({
handle: "natgeo",
cursor,
});
if (!result.ok) {
console.error(result.error.code, result.error.requestId);
break;
}
allPosts.push(...result.value.data.posts);
cursor = result.value.data.page.nextCursor ?? undefined;
} while (cursor);Stop when data.page.nextCursor is null. Don't loop on a total count — upstream totals are estimates. The cursor is the source of truth. Each page is a separate completed lookup for billing.
Reading the response
A successful response wraps the payload alongside billing metadata:
{
"data": {
"lookupStatus": "found",
"profile": {
"platform": "instagram",
"handle": "natgeo",
"displayName": "National Geographic",
"verified": true,
"privateAccount": false
},
"metrics": {
"followers": 280000000,
"following": 140,
"posts": 28000
}
},
"meta": {
"requestId": "req_01example",
"creditsCharged": 1,
"version": "v1"
}
}The one gotcha: an HTTP 200 does not guarantee lookupStatus: "found". A private or non-existent account can return 200 with a status field — handle it in application logic. Every response carries meta.requestId for support tracing. See Errors and Credits.
Post detail with downloadMedia=true is the common surcharge case: 11 credits on success (1 base + 10 for hosted media download). Leave downloadMedia off unless you need the files.
What you can build
- Influencer vetting — pull profile metrics and recent posts before outreach, and reconcile CRM handles against live numbers.
- Competitive content monitoring — snapshot competitor profiles, posts, and reels on a schedule without running a scraper per brand.
- Brand-safety and topic pipelines — pair captions with post/reel transcripts when on-screen text is thin.
For the same identity pattern across Instagram, TikTok, and YouTube, see Cross-platform creator profiles.
FAQ
Is scraping Instagram legal?
It depends on your jurisdiction, what data you collect, and how you use it. Collecting public, business-level metrics for B2B analytics is a common pattern, and courts (e.g. hiQ v. LinkedIn) have generally treated public-web data as fair game in several jurisdictions. You remain responsible for Instagram's terms, applicable privacy law, and your own contracts. This is a technical guide, not legal advice — talk to counsel if you're collecting at scale.
Can't I just use the Instagram Graph API?
Not for arbitrary public creator lookups. Graph covers accounts you manage or that grant your app access. For web-parity public data in a generic backend, a data API is the usual fit. See Meta Graph API limits.
How fresh is the data?
Each request fetches live from Instagram at call time — there's no cache returning an hour-old snapshot. If a number looks off, meta.requestId lets support trace that specific lookup.
What happens if a profile is private or doesn't exist?
Check data.lookupStatus. Don't treat a 200 alone as "data is present" — a private or missing account returns 200 with a status field. Details in Errors.
How are credits charged?
Credits charge when a lookup completes, including 200 outcomes like private or not_found. Most Instagram profile, post-list, reel-list, search, highlight, and transcript routes are 1 credit per completed request. Post detail with downloadMedia=true is 11 credits on success. Validation failures and upstream lookup_failed / temporary unavailability do not bill the same way — see Credits. Always reconcile against meta.creditsCharged.
How does this compare to other providers?
See the side-by-side comparisons: vs Apify, vs Bright Data, vs EnsembleData, the full compare hub, and Best Instagram data APIs in 2026.
Next steps: Quickstart · Instagram platform hub · Instagram API reference · Pricing