One endpoint, 20 Instagram data operations. Generate a key from your dashboard and you're pulling data.
Pass your API key as a bearer token on every request.
Authorization: Bearer YOUR_API_KEYEvery request has the same shape — an endpoint key from the table below, and itsparams.
| Field | Type | Description |
|---|---|---|
| endpoint | string | Required. One of the endpoint keys below. |
| params | object | The parameters for that endpoint — see "Params" column below. |
Grouped by category. Each one expands into its params and an example response — real Instagram payloads run into the hundreds of fields, so examples below are abbreviated to the ones you'll actually reach for.
The usual entry point: resolve an @handle into a full public profile — bio, follower/following/media counts, verification and business/private status, avatar — plus the numeric id that every other user-scoped endpoint below needs. If you already have the numeric id, user_by_id is a faster round trip.
| param | required | description |
|---|---|---|
| username | yes | The account's handle, without the "@" (e.g. "instagram"). |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"pk": "25025320",
"username": "instagram",
"full_name": "Instagram",
"is_private": false,
"is_verified": true,
"follower_count": 675000000,
"following_count": 130,
"media_count": 7600,
"biography": "Bringing you closer to the people and things you love. ...",
"profile_pic_url": "https://..."
// + ~200 more fields
}Same profile payload as user_by_username, keyed by numeric id instead of handle. Prefer this one once you've already resolved an id — it's a direct lookup rather than a username search.
| param | required | description |
|---|---|---|
| id | yes | The account's numeric Instagram ID — not the @username. Resolve it first with user_by_username if you only have the handle. |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"pk": "25025320",
"username": "instagram",
"full_name": "Instagram",
"is_private": false,
"is_verified": true,
"follower_count": 675000000
// + ~200 more fields
}The "About this account" panel Instagram shows on a profile: verification status, the country the account was registered in, the date it was created, and any former usernames. Useful for lightweight account-authenticity checks without pulling the full profile payload.
| param | required | description |
|---|---|---|
| id | yes | The account's numeric Instagram ID — not the @username. Resolve it first with user_by_username if you only have the handle. |
{
"is_verified": true,
"country": "US",
"date_joined": "2010-03-25T12:00:00Z",
"former_usernames": ["old_handle"]
}A page of a user's feed posts (photos, videos, carousels — not reels or stories), newest first. Paginate with profile_grid_items_cursor from the previous response's cursor field.
| param | required | description |
|---|---|---|
| user_id | yes | The account's numeric Instagram ID — not the @username. Resolve it first with user_by_username if you only have the handle. |
| profile_grid_items_cursor | no | Pagination cursor from the previous page's response. Omit to get the first page. |
| flat | no | Return a flat array of posts instead of Instagram's grouped grid-section structure. |
{
"items": [
{ "id": "...", "code": "Cxxxxxxxxxx", "media_type": 1, "like_count": 4213, "comment_count": 87, "caption": { "text": "..." } }
],
"cursor": "QVFB..."
}A page of a user's Reels, newest first — same shape as user_medias but scoped to Reels only.
| param | required | description |
|---|---|---|
| user_id | no | The account's numeric Instagram ID — not the @username. Resolve it first with user_by_username if you only have the handle. |
| page_id | no | Pagination cursor from the previous page's response. Omit to get the first page. |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"items": [
{ "id": "...", "code": "Cxxxxxxxxxx", "media_type": 2, "play_count": 91234, "like_count": 5310, "video_duration": 14.7 }
],
"page_id": "QVFB..."
}The account's currently-live story items. Empty once the last story expires (24h after posting) — there's no way to fetch expired stories through this endpoint.
| param | required | description |
|---|---|---|
| user_id | yes | The account's numeric Instagram ID — not the @username. Resolve it first with user_by_username if you only have the handle. |
| force | no | Passed through to bypass any upstream cache and force a fresh fetch. |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"items": [
{ "id": "...", "media_type": 1, "taken_at": 1732000000, "expiring_at": 1732086400, "image_versions2": { "candidates": [{ "url": "https://..." }] } }
]
}The list of highlight reels pinned to a profile (cover image, title, item count) — not the story items inside them. Fetch a specific highlight's contents with highlight_by_id.
| param | required | description |
|---|---|---|
| user_id | yes | The account's numeric Instagram ID — not the @username. Resolve it first with user_by_username if you only have the handle. |
| amount | no | Maximum number of highlights to return. |
| page_id | no | Pagination cursor from the previous page's response. |
| force | no | Passed through to bypass any upstream cache and force a fresh fetch. |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"items": [
{ "id": "highlight:17900000000", "title": "Travel", "media_count": 12, "cover_media": { "url": "https://..." } }
]
}A page of accounts following the given user, in the order Instagram returns them (not chronological). Private accounts you don't have visibility into will return a limited or empty list.
| param | required | description |
|---|---|---|
| user_id | yes | The account's numeric Instagram ID — not the @username. Resolve it first with user_by_username if you only have the handle. |
| page_id | no | Pagination cursor from the previous page's response. Omit to get the first page. |
{
"users": [
{ "pk": "...", "username": "...", "full_name": "...", "is_private": false }
],
"page_id": "QVFB..."
}A page of accounts the given user follows. Same pagination and visibility rules as user_followers.
| param | required | description |
|---|---|---|
| user_id | yes | The account's numeric Instagram ID — not the @username. Resolve it first with user_by_username if you only have the handle. |
| page_id | no | Pagination cursor from the previous page's response. Omit to get the first page. |
{
"users": [
{ "pk": "...", "username": "...", "full_name": "...", "is_private": false }
],
"page_id": "QVFB..."
}Full details for a single post (or carousel/reel) by its shortcode: caption, like/comment counts, media URLs, timestamps, and tagged users. Returns 404 for deleted or unavailable posts rather than a partial result. Note: usertags aren't returned for video media.
| param | required | description |
|---|---|---|
| code | yes | The shortcode from the post URL — the "Cxxxxxxxxxx" in instagram.com/p/Cxxxxxxxxxx/. |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"status": "ok",
"num_results": 1,
"items": [
{ "id": "...", "code": "Cxxxxxxxxxx", "media_type": 1, "like_count": 4213, "comment_count": 87, "caption": { "text": "..." } }
]
}Same payload as media_by_code — use this one when you have the full post URL and don't want to parse the shortcode out of it yourself.
| param | required | description |
|---|---|---|
| url | yes | The full post URL, e.g. https://www.instagram.com/p/Cxxxxxxxxxx/. |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"status": "ok",
"num_results": 1,
"items": [
{ "id": "...", "code": "Cxxxxxxxxxx", "media_type": 1, "like_count": 4213, "comment_count": 87 }
]
}A page of top-level comments on a post, newest first, including each commenter's basic profile info and like count on the comment.
| param | required | description |
|---|---|---|
| id | yes | The post's numeric media id (from media_by_code / media_by_url). |
| can_support_threading | no | Whether to return threaded (nested reply) comments if the client supports it. |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
| page_id | no | Pagination cursor from the previous page's response. |
{
"comments": [
{ "pk": "...", "text": "...", "user": { "username": "..." }, "comment_like_count": 12, "created_at": 1732000000 }
],
"page_id": "QVFB..."
}The accounts that liked a post, most-recent-like first. For posts with like counts hidden by the poster, this can return an empty or partial list.
| param | required | description |
|---|---|---|
| id | yes | The post's numeric media id (from media_by_code / media_by_url). |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"users": [
{ "pk": "...", "username": "...", "full_name": "...", "is_verified": false }
]
}Details for one story item by its id (from user_stories). Returns nothing once the story has expired — Instagram doesn't retain expired stories server-side.
| param | required | description |
|---|---|---|
| id | yes | The story item's numeric id (from user_stories). |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"id": "...",
"media_type": 1,
"taken_at": 1732000000,
"expiring_at": 1732086400,
"image_versions2": { "candidates": [{ "url": "https://..." }] }
}The story items inside one highlight reel (from user_highlights) — the archived stories a user has pinned to their profile, which don't expire.
| param | required | description |
|---|---|---|
| id | yes | The highlight's id (from user_highlights, e.g. "highlight:17900000000"). |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"id": "highlight:17900000000",
"title": "Travel",
"items": [
{ "id": "...", "media_type": 1, "image_versions2": { "candidates": [{ "url": "https://..." }] } }
]
}Details for a geotag location: name, address, coordinates, and the numeric id used to look up posts tagged there.
| param | required | description |
|---|---|---|
| id | yes | The location's numeric id, as seen on a geotagged post or in a location search result. |
{
"pk": "...",
"name": "New York, New York",
"lat": 40.7128,
"lng": -74.006,
"address": ""
}Instagram's account search, ranked the same way the in-app search bar ranks results for that query — not a plain substring match.
| param | required | description |
|---|---|---|
| query | yes | The search text — a name or partial username. |
| page_token | no | Pagination token from the previous page's response. |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"users": [
{ "pk": "...", "username": "...", "full_name": "...", "is_verified": false }
],
"has_more": true,
"page_token": "..."
}The combined "Top" search results Instagram's search bar shows by default — a mix of accounts, hashtags, and places matching the query, in one ranked list.
| param | required | description |
|---|---|---|
| query | yes | The search text. |
| next_max_id | no | Pagination cursor from the previous page's response. |
| safe_int | no | Return large integers (IDs, counts) as strings instead of numbers, so languages without native 64-bit ints don't lose precision. |
{
"users": [{ "pk": "...", "username": "..." }],
"hashtags": [{ "hashtag": { "name": "...", "media_count": 12345 } }],
"places": [{ "place": { "location": { "name": "..." } } }]
}curl -X POST https://api.fairscrape.online/v1/scrape \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"endpoint": "user_by_username", "params": {"username": "instagram"}}'import requests
response = requests.post(
"https://api.fairscrape.online/v1/scrape",
headers={"Authorization": "Bearer YOUR_API_KEY"},
json={"endpoint": "user_by_username", "params": {"username": "instagram"}},
)
print(response.json())const response = await fetch("https://api.fairscrape.online/v1/scrape", {
method: "POST",
headers: {
Authorization: "Bearer YOUR_API_KEY",
"Content-Type": "application/json",
},
body: JSON.stringify({
endpoint: "user_by_username",
params: { username: "instagram" },
}),
});
const data = await response.json();Success (200):
{ "success": true, "data": { ... } }Errors:
| Status | Meaning |
|---|---|
| 400 | Unknown endpoint, or missing a required param. |
| 401 | Missing, invalid, or revoked API key. |
| 402 | No active plan, expired plan, or insufficient wallet balance. Response includes current balance. |
| 429 | Rate limit exceeded for your plan — slow down and retry. See pricing for each plan's requests/sec cap. |
| 502 | Upstream call failed. You are not charged for this request. |
Questions? support@fairscrape.online