# Instagram Scraper API: guide for AI agents You can call this HTTP API to read public Instagram data: profiles, posts, reels, single posts, comments, similar accounts, hashtags, topics, locations and trending reels. It uses no Instagram accounts (logged-out scraping), so only public data is available. ## Basics - Base URL: https://scraper.viralspot.ai - Auth: send your API key in the `x-api-key` header on every request (except `/api/v1/health`). Ask the user for the key; never guess it. - Every endpoint is a GET with query parameters and returns JSON. - Example: curl --get "https://scraper.viralspot.ai/api/v1/instagram/user/info" --data-urlencode "username=nasa" -H "x-api-key: $API_KEY" ## Conventions - IDs (`pk`, `id`, media ids, user ids) are strings. Timestamps are Unix seconds. - Media identifiers (`media_id`) accept a shortcode (`DdHyaYAifb6`), a numeric media id, or a full post/reel URL. User endpoints accept a username or a profile URL. - Pagination: pass the previous response's token back. Names differ per endpoint and are listed on each endpoint below (`pagination_token`, `max_id`, `cursor`). Stop when the token is null or `has_next_page` is false. Most feeds return at most 12 items per upstream page. - Image and video URLs (fbcdn.net / cdninstagram.com) are signed and expire after a few days. Download them if you need to keep them. - Every call fetches fresh data; there is no response caching. Calls take roughly 1-5 s, some up to ~20 s. Don't fire many calls in parallel; a concurrency of about 4 is safe. ## Errors - 400: missing or invalid parameter. Fix the request; don't retry as is. - 401 / 403: bad API key or no access. - 404: the user or post doesn't exist, is private, or is hidden from logged-out visitors (age- or region-restricted accounts). A 404 does not prove the account is deleted. - 429: rate, credit or upstream capacity limit. Wait a few seconds (respect `Retry-After` if present) and retry. - 502: Instagram returned a bad or incomplete answer. Retry once later. - 501: Instagram requires login for this query. Retrying won't help. - 503 / 504: timed out. Retry later. Error bodies look like {"detail": "..."}. ## Things to know - `user/posts` and `user/reels` include collab posts where the account is only a coauthor. In those, the item's `user` is the other account. To count only the account's own posts, keep items whose `user.pk` equals the account's `pk`. - Pinned posts come first in `user/posts`, out of date order. Pinned markers (`timeline_pinned_user_ids`) are numbers while `pk` is a string, so compare them as strings. - `media/info` returns empty `coauthor_producers` for collab posts unless you pass `coauthors=true`. With it, `coauthors_source` tells you where the list came from; `null` means the lookup failed, so an empty list is unknown rather than "no collaborators". - `media/info` has no music. Use `anon/media/music` for song, artist, original-audio flag and audio id. - `video_view_count` is null; use `play_count` for views. - Not available: followers/following lists, user search, live stories, account join date/country/former usernames, total reels count, complete or recent hashtag feeds, private accounts' posts. ## Endpoints Parameters marked "required" must be sent. Response examples are abbreviated and illustrative; real responses can have more fields, and fields that Instagram omits are null. ## User endpoints ### GET /api/v1/instagram/user/info User profile info (no posts or reels) Profile metadata only — the same data as `user/about`. Posts live on `user/posts`, reels on `user/reels`. Parameters: - `username` (string, optional): Instagram username or URL - `username_or_url` (string, optional): Alias for username Response example: ```json { "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "biography": "Discover stories from around the world.", "is_private": false, "is_verified": true, "edge_followed_by": { "count": 1000000 }, "edge_follow": { "count": 100 }, "edge_owner_to_timeline_media": { "count": 1000 } }, "source": "anon" } ``` ### GET /api/v1/instagram/user/similar Similar / suggested accounts Find accounts Instagram considers similar to a given profile. Uses the related-profile list available to logged-out clients. Coverage varies by account and can be empty when Instagram's profile response is degraded. Returns the accounts Instagram exposes without a viewer session. Authentication: x-api-key header (or ?api_key= query param). Parameters: - `username` (string, required): Instagram username to find similar accounts for Response example: ```json { "username": "instagram", "count": 1, "profiles": [ { "id": "787132", "username": "natgeo", "full_name": "National Geographic" } ], "source": "anon" } ``` ### GET /api/v1/instagram/user/reels User reels (raw passthrough, native play_count) Raw user reels via clips/user (native play_count): {"reels":[{"node":{"media":{...},"__typename":"XDTClipsItemDict"}}], "pagination_token": ...}. Parameters: - `username` (string, optional): Instagram username or URL - `username_or_url` (string, optional): Alias for username - `user_id` (string, optional): Numeric Instagram user ID; skips username resolution - `amount` (integer, optional, default 12): Number of reels to fetch (max 50) - `max_reels` (integer, optional): Alias for amount - `max_id` (string, optional): Pagination cursor — previous response's pagination_token Response example: ```json { "reels": [ { "node": { "media": { "pk": "3928250036051888465", "code": "DaD8phTyclR", "media_type": 2, "like_count": 1200, "comment_count": 24, "caption": { "text": "A new perspective." }, "user": { "pk": "25025320", "username": "instagram" }, "play_count": 45000 } } } ], "pagination_token": null } ``` ### GET /api/v1/instagram/user/about Profile metadata only (fast, no posts) Profile-only lookup (no posts). Returns followers, following, bio, is_business, category, contact info (business_email, public_phone_number), profile_pic_url_hd. Parameters: - `username` (string, required): Instagram username Response example: ```json { "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "biography": "Discover stories from around the world.", "is_private": false, "is_verified": true, "edge_followed_by": { "count": 1000000 }, "edge_follow": { "count": 100 }, "edge_owner_to_timeline_media": { "count": 1000 } }, "source": "anon" } ``` ### GET /api/v1/instagram/anon/user/profile Public profile via logged-out web (no account) Parameters: - `username` (string, required) Response example: ```json { "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "biography": "Discover stories from around the world.", "is_private": false, "is_verified": true, "edge_followed_by": { "count": 1000000 }, "edge_follow": { "count": 100 }, "edge_owner_to_timeline_media": { "count": 1000 } } } ``` ### GET /api/v1/instagram/user/posts Complete post fields for ViralSpot, up to 12 items per page Fresh feed including images, carousels and videos/reels. Returns full metric/date/caption/thumbnail fields or an explicit upstream error. Continue with pagination_token; do not reuse old web-GraphQL cursors. Parameters: - `username` (string, optional): Instagram username or profile URL - `username_or_url` (string, optional): Alias for username - `amount` (integer, optional, default 12, min 1, max 50): Requested size; Instagram caps each page at 12 - `pagination_token` (string, optional) - `max_id` (string, optional): Alias for pagination_token Response example: ```json { "posts": [ { "node": { "pk": "3928250036051888465", "code": "DaD8phTyclR", "media_type": 1, "like_count": 1200, "comment_count": 24, "caption": { "text": "A new perspective." }, "user": { "pk": "25025320", "username": "instagram" }, "taken_at": 1789412287, "like_and_view_counts_disabled": false, "is_video": false, "product_type": "feed", "missing_fields": [], "image_versions2": { "candidates": [ { "url": "https://example.com/image.jpg", "width": 1080, "height": 1080 } ] } } } ], "count": 1, "has_next_page": false, "pagination_token": null, "source": "mobile", "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "biography": "Discover stories from around the world.", "is_private": false, "is_verified": true, "edge_followed_by": { "count": 1000000 }, "edge_follow": { "count": 100 }, "edge_owner_to_timeline_media": { "count": 1000 } } } ``` ### GET /api/v1/instagram/anon/user/reels Profile reels via logged-out GraphQL (with play/like/comment counts) Parameters: - `username` (string, required) - `amount` (integer, optional, default 12): 1-100 per page - `max_id` (string, optional) Response example: ```json { "reels": [ { "node": { "pk": "3928250036051888465", "code": "DaD8phTyclR", "media_type": 2, "like_count": 1200, "comment_count": 24, "caption": { "text": "A new perspective." }, "user": { "pk": "25025320", "username": "instagram" }, "play_count": 45000 } } ], "pagination_token": null } ``` ### GET /api/v1/instagram/anon/user/embed Profile summary + latest ~6 posts via the lightweight profile embed page Parameters: - `username` (string, required) Response example: ```json { "username": "instagram", "media_count": 1000, "follower_count": 1000000, "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "biography": "Discover stories from around the world.", "is_private": false, "is_verified": true, "edge_followed_by": { "count": 1000000 }, "edge_follow": { "count": 100 }, "edge_owner_to_timeline_media": { "count": 1000 } }, "latest": [ { "code": "DaD8phTyclR", "like_count": 1200, "comment_count": 24 } ], "source": "embed" } ``` ### GET /api/v1/instagram/anon/user/full Full profile (counts, bio, business contact, latest posts+reels with counts, related profiles) Parameters: - `username` (string, required) Response example: ```json { "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "biography": "Discover stories from around the world.", "is_private": false, "is_verified": true, "edge_followed_by": { "count": 1000000 }, "edge_follow": { "count": 100 }, "edge_owner_to_timeline_media": { "count": 1000 }, "follower_count": 1000000, "media_count": 1000 } } ``` ### GET /api/v1/instagram/anon/user/similar Related / similar accounts for a user (~48) Parameters: - `username` (string, required) Response example: ```json { "username": "instagram", "count": 1, "profiles": [ { "id": "787132", "username": "natgeo", "full_name": "National Geographic" } ] } ``` ### GET /api/v1/instagram/anon/user/feed User posts via anonymous mobile API (full objects: like/comment/play counts) Parameters: - `username` (string, required): username or numeric user id - `max_id` (string, optional): pagination_token from previous page Response example: ```json { "posts": [ { "node": { "pk": "3928250036051888465", "code": "DaD8phTyclR", "media_type": 1, "like_count": 1200, "comment_count": 24, "caption": { "text": "A new perspective." }, "user": { "pk": "25025320", "username": "instagram" } } } ], "pagination_token": null } ``` ### GET /api/v1/instagram/anon/user/posts_only User posts WITHOUT reels (images / carousels / feed videos), 12 per page Parameters: - `username` (string, required): username or numeric user id - `amount` (integer, optional, default 12): 1-50 non-reel posts to return - `max_id` (string, optional): pagination_token from previous page - `types` (string, optional, default "image,carousel,video"): comma list of image, carousel, video (feed videos that are not reels) Response example: ```json { "posts": [ { "node": { "pk": "3928250036051888465", "code": "DaD8phTyclR", "media_type": 1, "like_count": 1200, "comment_count": 24, "caption": { "text": "A new perspective." }, "user": { "pk": "25025320", "username": "instagram" } } } ], "pagination_token": null, "types": [ "carousel", "image", "video" ] } ``` ### GET /api/v1/instagram/anon/user/clips User reels via anonymous mobile API (play_count, 12/page) Parameters: - `username` (string, required): username or numeric user id - `max_id` (string, optional) Response example: ```json { "reels": [ { "node": { "media": { "pk": "3928250036051888465", "code": "DaD8phTyclR", "media_type": 2, "like_count": 1200, "comment_count": 24, "caption": { "text": "A new perspective." }, "user": { "pk": "25025320", "username": "instagram" }, "play_count": 45000 } } } ], "pagination_token": null } ``` ### GET /api/v1/instagram/user/by_id Profile summary from a numeric user id Resolve a numeric user id to username, name, bio, follower counts, verified/private flags and whether the account has an active story right now (`has_active_story`; story contents are not available logged out). `highlight_count` counts at most 10; `has_more_highlights` is true when there are more (use `user/highlights` for the full list). Parameters: - `user_id` (string, required): Numeric Instagram user id Response example: ```json { "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "is_verified": true, "profile_pic_url": "https://example.com/avatar.jpg", "biography": "...", "is_private": false, "follower_count": 686721131, "following_count": 298, "has_clips": true, "has_active_story": true, "latest_story_at": 1790103695 }, "highlight_count": 7, "has_more_highlights": false, "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/user/highlights A user's story highlights (titles and covers) List a public account's highlights. Pass a highlight `id` to `user/highlight` for its stories. `has_more` is true only if Instagram returned a partial list (the first 10) and the full list was unavailable. Parameters: - `username` (string, optional): Instagram username or profile URL (or pass user_id) - `user_id` (string, optional): Numeric Instagram user id; skips the username lookup Response example: ```json { "user_id": "25025320", "username": "instagram", "highlights": [ { "id": "18223279177302854", "title": "close friends", "cover_url": "https://example.com/cover.jpg" } ], "count": 1, "has_more": false, "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/user/highlight Stories inside one highlight Every story item in a highlight: media type, date, duration, image and video URLs. Media URLs are signed and expire. Unknown highlights return 404. Parameters: - `highlight_id` (string, required): Highlight `id` from `user/highlights` (optionally prefixed `highlight:`) Response example: ```json { "highlight_id": "18223279177302854", "title": "close friends", "user_id": "25025320", "username": "instagram", "items": [ { "id": "3398250234472938888", "media_type": 2, "taken_at": 1719323002, "video_duration": 15, "has_audio": true, "display_url": "https://example.com/frame.jpg", "video_url": "https://example.com/story.mp4" } ], "count": 1, "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/user/tagged Posts a user is tagged in, with cursor pagination Posts other accounts tagged this user in, 12 per page. Send `next_cursor` as `cursor` until `has_next_page` is false. Instagram omits some fields here (for example `taken_at` and the author's username); they stay null. Parameters: - `username` (string, optional): Instagram username or profile URL (or pass user_id) - `user_id` (string, optional): Numeric Instagram user id; skips the username lookup - `cursor` (string, optional): Copy next_cursor from the previous page Response example: ```json { "user_id": "25025320", "posts": [ { "id": "3986708666006474244", "shortcode": "DdTomjESY4E", "url": "https://www.instagram.com/p/DdTomjESY4E/", "media_type": 2, "product_type": "clips", "taken_at": 1789472774, "caption": "Example caption", "like_count": 21, "comment_count": 7, "like_and_view_counts_disabled": false, "display_url": "https://example.com/image.jpg", "video_url": "https://example.com/video.mp4", "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "is_verified": true, "profile_pic_url": "https://example.com/avatar.jpg" } } ], "count": 1, "has_next_page": true, "next_cursor": "1247853487850121245", "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ## Media endpoints ### GET /api/v1/instagram/media/convert Convert a media ID, shortcode or URL without an Instagram request Returns the numeric media ID as a string, shortcode and canonical URLs. Compound IDs discard the owner suffix. This is a mathematical conversion, not a check that the post exists or is a reel. Digit-only shortcodes should be supplied as an Instagram URL to distinguish them from numeric IDs. Standard API-key request limits and credits apply; no upstream call is made. Parameters: - `media_id` (string, required, min length 1, max length 2048) Response example: ```json { "media_id": "3985276232175651873", "shortcode": "DdOi55Gowwh", "post_url": "https://www.instagram.com/p/DdOi55Gowwh/", "reel_url": "https://www.instagram.com/reel/DdOi55Gowwh/" } ``` ### GET /api/v1/instagram/media/metadata Combined media details, titles, sponsors and accessibility descriptions Fetch native logged-out GraphQL metadata, with a public-page fallback. Sponsor relationships come only from explicit sponsor tags; pending status is preserved. Partnerships do not establish that an ad is currently active. `native_title` is nullable; a caption-derived display title is labeled. Accessibility descriptions include carousel children, with nulls when absent; these are not audio transcripts. Native fields and media URLs vary by post. This uses one normal API request credit and no logged-in Instagram account. Parameters: - `media_id` (string, required, min length 1, max length 2048): Shortcode, numeric/compound media ID or Instagram post/reel URL Response example: ```json { "identifiers": { "media_id": "3985276232175651873", "shortcode": "DdOi55Gowwh", "post_url": "https://www.instagram.com/p/DdOi55Gowwh/", "reel_url": "https://www.instagram.com/reel/DdOi55Gowwh/" }, "titles": { "native_title": null, "display_title": "An example caption", "display_title_source": "caption_first_line" }, "sponsorship": { "is_paid_partnership": true, "is_ad": null, "is_affiliate": null, "relationships": [ { "creator": { "id": "123", "username": "example_creator" }, "sponsor": { "pk": "456", "username": "example_brand" }, "is_pending": false, "media_id": "3985276232175651873", "shortcode": "DdOi55Gowwh", "evidence": "instagram_sponsor_tag" } ] }, "accessibility": [ { "media_id": "3985276232175651873", "caption": null, "source": null } ], "media": { "id": "3985276232175651873", "shortcode": "DdOi55Gowwh", "caption": "An example caption" }, "source": "instagram_logged_out_graphql" } ``` ### GET /api/v1/instagram/media/info Single post/reel full detail Detailed metadata for a single post or reel by shortcode, numeric pk, or URL. Returns available counts, caption, URLs, sponsor tags and accessibility text. Missing native fields remain null; paid partnerships do not imply active ads. Music attribution is not included; use `anon/media/music`. Parameters: - `media_id` (string, required): Post/reel shortcode (e.g. DYvZX7Spf8-), numeric pk, OR full /p// URL - `full` (boolean, optional, default false): true = raw native GraphQL object, with public-page fallback. - `lite` (boolean, optional, default false): Default false prefers native GraphQL for sponsor tags, accessibility and other available metadata, plus duration enrichment. true opts into partial embed data. Fields can be null. - `coauthors` (boolean, optional, default false): true fills coauthor_producers for collab posts (logged-out GraphQL returns [] for them) and adds coauthors_source. Free for the owner's 12 latest posts; older posts cost one extra ~176 KB proxied page fetch. Ignored with full=true. Response example: ```json { "media": { "id": "3928250036051888465", "shortcode": "DaD8phTyclR", "is_video": false, "owner": { "id": "25025320", "username": "instagram" }, "edge_media_preview_like": { "count": 1200 }, "edge_media_to_comment": { "count": 24 }, "edge_media_to_caption": { "edges": [ { "node": { "text": "A new perspective." } } ] }, "display_url": "https://example.com/image.jpg" }, "source": "embed" } ``` ### GET /api/v1/instagram/anon/media/info Single post/reel detail via logged-out GraphQL with reel enrichment Parameters: - `media_id` (string, required): shortcode, numeric pk, or /p/ URL - `full` (boolean, optional, default false): true = raw native GraphQL object, with public-page fallback - `lite` (boolean, optional, default false): Default false = native GraphQL plus reel enrichment. true opts into partial embed data. Fields vary by post. - `coauthors` (boolean, optional, default false): true fills coauthor_producers for collab posts (logged-out GraphQL returns [] for them) and adds coauthors_source. Free for the owner's 12 latest posts; older posts cost one extra ~176 KB proxied page fetch. Ignored with full=true. Response example: ```json { "media": { "id": "3928250036051888465", "shortcode": "DaD8phTyclR", "is_video": false, "owner": { "id": "25025320", "username": "instagram" }, "edge_media_preview_like": { "count": 1200 }, "edge_media_to_comment": { "count": 24 }, "edge_media_to_caption": { "edges": [ { "node": { "text": "A new perspective." } } ] }, "display_url": "https://example.com/image.jpg" }, "source": "embed" } ``` ### GET /api/v1/instagram/anon/media/music Music / audio attribution of a reel (artist, song, original audio, audio_id) Parameters: - `media_id` (string, required): shortcode, numeric pk, or /reel/ URL Response example: ```json { "code": "DaD8phTyclR", "is_video": false, "product_type": "feed", "music": null, "source": "embed" } ``` ### GET /api/v1/instagram/media/comments Public post/reel comments, with cursor pagination Fetch comment text, author, timestamp and likes without an Instagram account. Send `next_cursor` as `cursor` until `has_next_page` is false. `count` in the response is this page's number of comments, not the post's total count. Instagram may expose only a subset of the displayed total, including when it reports no next page. Reply bodies are not included (use `media/comments/replies` with a comment `id`); unknown reply/like counts remain null. Each page is a separate API request using normal limits and credits. `fetched_at` is UTC; every request fetches fresh data. Parameters: - `media_id` (string, required, min length 1, max length 2048): Shortcode, numeric media ID, or full Instagram post/reel URL - `count` (integer, optional, default 24, min 1, max 50): Requested page size; Instagram may return more or fewer comments - `cursor` (string, optional): Copy next_cursor from the previous page; keep the same media_id Response example: ```json { "media_id": "3987572378498793979", "shortcode": "DdWs_OAlIH7", "comments": [ { "id": "18104015129259386", "text": "Example comment", "created_at": 1789728060, "like_count": 0, "is_covered": false, "user": { "id": "12345", "username": "example_creator", "profile_pic_url": "https://example.com/avatar.jpg", "is_verified": false } } ], "count": 1, "has_next_page": false, "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-19T00:00:00+00:00" } ``` ### GET /api/v1/instagram/media/comments/replies Public replies to one comment, with cursor pagination Fetch the replies under one comment without an Instagram account. Take `comment_id` from a comment's `id` in `media/comments`. Pages hold about 15 replies; send `next_cursor` as `cursor` until `has_next_page` is false. Anonymous `reply_count` on top-level comments is null, so a comment with no replies returns an empty page. Instagram may hide some replies from logged-out viewers, so totals can be slightly below the displayed count. Instagram selects the thread by `comment_id` alone. A 404 means Instagram could not load that thread. Each page is a separate API request using normal limits and credits. `fetched_at` is UTC; every request fetches fresh data. Parameters: - `media_id` (string, required, min length 1, max length 2048): Shortcode, numeric media ID, or full Instagram post/reel URL - `comment_id` (string, required): Numeric `id` of a top-level comment from `media/comments` - `cursor` (string, optional): Copy next_cursor from the previous page; keep the same comment_id Response example: ```json { "media_id": "3983118388705688735", "shortcode": "DdG4RIxIPyf", "comment_id": "17973240719933659", "replies": [ { "id": "18148036234472326", "text": "@example Example reply", "created_at": 1789120851, "like_count": 0, "parent_comment_id": "17973240719933659", "is_covered": false, "user": { "id": "12345", "username": "example_fan", "profile_pic_url": "https://example.com/avatar.jpg", "is_verified": false } } ], "count": 1, "has_next_page": false, "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/media/likers Accounts that liked a post or reel Up to about 100 accounts that liked the post (Instagram's own cap; no pagination). Posts with hidden like counts may return fewer. Parameters: - `media_id` (string, required, min length 1, max length 2048): Shortcode, numeric media ID, or full Instagram post/reel URL Response example: ```json { "media_id": "3983118388705688735", "shortcode": "DdG4RIxIPyf", "users": [ { "id": "25025320", "username": "instagram", "full_name": "Instagram", "is_verified": true, "profile_pic_url": "https://example.com/avatar.jpg" } ], "count": 1, "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/media/related Posts Instagram shows as related to a post or reel The related posts Instagram shows logged-out visitors under a post (typically 4), with counts, caption, media URLs and author. Parameters: - `media_id` (string, required, min length 1, max length 2048): Shortcode, numeric media ID, or full Instagram post/reel URL Response example: ```json { "media_id": "3983118388705688735", "shortcode": "DdG4RIxIPyf", "posts": [ { "id": "3986708666006474244", "shortcode": "DdTomjESY4E", "url": "https://www.instagram.com/p/DdTomjESY4E/", "media_type": 2, "product_type": "clips", "taken_at": 1789472774, "caption": "Example caption", "like_count": 21, "comment_count": 7, "like_and_view_counts_disabled": false, "display_url": "https://example.com/image.jpg", "video_url": "https://example.com/video.mp4", "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "is_verified": true, "profile_pic_url": "https://example.com/avatar.jpg" } } ], "count": 1, "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/media/ai_summary Instagram's AI-generated title and summary for a post or reel The SEO title and summary Instagram generates for posts, reels and carousels. Not every post has one: about 60% of recent posts from large accounts did in testing (photos most often, newer posts more often). When Instagram has none, `available` is false and both fields are null; that is still a successful response. Parameters: - `media_id` (string, required, min length 1, max length 2048): Shortcode, numeric media ID, or full Instagram post/reel URL Response example: ```json { "media_id": "3990000000000000000", "shortcode": "DdcI4o0Prsz", "title": "Smiling in the Moment", "summary": "Discover the joy of living in the moment...", "available": true, "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/media/related_reels More reels chained from a reel (same creator first) The reels Instagram plays after this one for logged-out viewers, starting with the same creator's reels. The seed reel itself is excluded. Send `next_cursor` as `cursor` for more. Unknown media returns 404. Parameters: - `media_id` (string, required, min length 1, max length 2048): Shortcode, numeric media ID, or full Instagram post/reel URL - `cursor` (string, optional): Copy next_cursor from the previous page Response example: ```json { "media_id": "3989102446432402227", "shortcode": "DdcI4o0Prsz", "reels": [ { "id": "3986708666006474244", "shortcode": "DdTomjESY4E", "url": "https://www.instagram.com/p/DdTomjESY4E/", "media_type": 2, "product_type": "clips", "taken_at": 1789472774, "caption": "Example caption", "like_count": 21, "comment_count": 7, "like_and_view_counts_disabled": false, "display_url": "https://example.com/image.jpg", "video_url": "https://example.com/video.mp4", "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "is_verified": true, "profile_pic_url": "https://example.com/avatar.jpg" } } ], "count": 1, "has_next_page": true, "next_cursor": "QVFE...", "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/media/oembed Instagram's official oEmbed for a post or reel Caption (`title`), author name/id, thumbnail and the official embed `html` in one small, fast response. Unknown media returns 404. Parameters: - `media_id` (string, required, min length 1, max length 2048): Shortcode, numeric media ID, or full Instagram post/reel URL Response example: ```json { "media_id": "3983118388705688735", "shortcode": "DdG4RIxIPyf", "title": "Caption text…", "author_name": "natgeo", "author_id": "787132", "author_url": "https://www.instagram.com/natgeo", "thumbnail_url": "https://example.com/thumb.jpg", "thumbnail_width": 640, "thumbnail_height": 1137, "width": 658, "html": "
", "source": "instagram_oembed", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ## Search endpoints ### GET /api/v1/instagram/reels/trending Trending reels stream (Instagram's logged-out reels feed) Popular reels from the feed Instagram shows logged-out visitors on instagram.com/reels/: 8 on the first page, then 12 per page. It is a sampled stream, not a fixed chart: each call returns different reels, so page with `next_cursor` for more and de-duplicate by `id` if you collect over time. Parameters: - `cursor` (string, optional): Copy next_cursor from the previous page Response example: ```json { "reels": [ { "id": "3986708666006474244", "shortcode": "DdTomjESY4E", "url": "https://www.instagram.com/p/DdTomjESY4E/", "media_type": 2, "product_type": "clips", "taken_at": 1789472774, "caption": "Example caption", "like_count": 21, "comment_count": 7, "like_and_view_counts_disabled": false, "display_url": "https://example.com/image.jpg", "video_url": "https://example.com/video.mp4", "user": { "id": "25025320", "username": "instagram", "full_name": "Instagram", "is_verified": true, "profile_pic_url": "https://example.com/avatar.jpg" } } ], "count": 1, "has_next_page": true, "next_cursor": "QVFE...", "source": "instagram_logged_out_graphql", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/locations/countries Location directory: countries Countries in Instagram's public location directory, 96 per page. Pass a country `id` to `locations/cities`. Parameters: - `page` (integer, optional, default 1, min 1, max 1000): Page number (1-based); use next_page from the previous response Response example: ```json { "countries": [ { "id": "US", "name": "United States", "slug": "united-states" } ], "count": 1, "page": 1, "next_page": 2, "source": "instagram_location_directory", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/locations/cities Location directory: cities in a country Cities for a country, 96 per page, most active first. Pass a city `id` to `locations/places`. Unknown countries return 404. Parameters: - `page` (integer, optional, default 1, min 1, max 1000): Page number (1-based); use next_page from the previous response - `country` (string, required): Two-letter country id from `locations/countries` Response example: ```json { "country_info": { "id": "US", "name": "United States", "slug": "united-states" }, "cities": [ { "id": "c2420379", "name": "LosAngeles", "slug": "losangeles-united-states" } ], "count": 1, "page": 1, "next_page": 2, "source": "instagram_location_directory", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/locations/places Location directory: places in a city (with location ids) Places in a city, 96 per page. Each place `id` is a location id for `anon/location/posts`, `anon/location/info` and `anon/location/nearby`. Unknown cities return 404. Parameters: - `page` (integer, optional, default 1, min 1, max 1000): Page number (1-based); use next_page from the previous response - `city` (string, required): City id from `locations/cities` Response example: ```json { "country_info": { "id": "US", "name": "United States", "slug": "united-states" }, "city_info": { "id": "c2420379", "name": "LosAngeles", "slug": "losangeles-united-states" }, "places": [ { "id": "21065030", "name": "Grand Park", "slug": "grand-park" } ], "count": 1, "page": 1, "next_page": 2, "source": "instagram_location_directory", "fetched_at": "2026-09-23T00:00:00+00:00" } ``` ### GET /api/v1/instagram/anon/search Popular keyword discovery, with pagination (not an exhaustive feed) Parameters: - `query` (string, required, min length 1, max length 100) - `count` (integer, optional, default 29, min 1, max 29) - `cursor` (string, optional): Previous next_cursor; keep the same query Response example: ```json { "query": "travel", "count": 1, "items": [ { "shortcode": "DaD8phTyclR", "url": "https://www.instagram.com/reel/DaD8phTyclR/", "caption": "Travel inspiration", "author": { "username": "instagram", "full_name": "Instagram", "is_verified": true }, "play_count": 45000, "thumbnail_url": null, "video_versions": [] } ], "has_next_page": false, "next_cursor": null } ``` ### GET /api/v1/instagram/anon/hashtag/posts Hashtag-filtered popular discovery (not a full or recent hashtag feed) Search logged-out popular keyword candidates, then optionally filter captions. Coverage is partial and ranked, not chronological or complete. `scanned_count` counts candidates on this page; `count` is the number retained. An empty filtered page may still have `has_next_page=true`: follow its cursor. A final empty page does not mean the hashtag has no posts. Each page uses one normal API request credit. No Instagram account or third-party provider is used. Parameters: - `tag` (string, required, min length 1, max length 101) - `count` (integer, optional, default 29, min 1, max 29): Number of candidates requested before filtering - `cursor` (string, optional): Previous next_cursor; keep the same tag and exact_match - `exact_match` (boolean, optional, default true): Only include captions containing the exact hashtag Response example: ```json { "query": "nature", "hashtag": "nature", "exact_match": true, "scanned_count": 1, "count": 1, "items": [ { "shortcode": "DdOi55Gowwh", "url": "https://www.instagram.com/reel/DdOi55Gowwh/", "caption": "An example #nature caption", "author": { "username": "example_creator" }, "play_count": 0, "thumbnail_url": null, "video_versions": [] } ], "has_next_page": false, "next_cursor": null, "source": "instagram_logged_out_popular_search", "coverage": "popular_keyword_candidates" } ``` ### GET /api/v1/instagram/anon/hashtag/search Hashtag name search with counts (use hashtag/posts for partial discovery) Parameters: - `q` (string, required) Response example: ```json { "query": "travel", "count": 1, "results": [ { "id": "17841562498105353", "name": "travel", "media_count": 1000000, "formatted_media_count": "1M", "search_result_subtitle": "1M posts" } ] } ``` ### GET /api/v1/instagram/anon/topic Popular-topic page: reel count, related keywords, reels Parameters: - `keyword` (string, required) Response example: ```json { "keyword": "technology", "title": "Technology", "reel_count_text": "1K reels", "definition": null, "related_keywords": [ "innovation" ], "reels": [ { "node": { "pk": "3928250036051888465", "code": "DaD8phTyclR", "media_type": 1, "like_count": 1200, "comment_count": 24, "caption": { "text": "A new perspective." }, "user": { "pk": "25025320", "username": "instagram" } } } ] } ``` ### GET /api/v1/instagram/anon/location/posts Posts at a location via logged-out GraphQL Parameters: - `location_id` (string, required) - `tab` (string, optional, default "recent"): recent | ranked | top (top -> ranked) - `amount` (integer, optional, default 12): 1-50 Response example: ```json { "location_id": "212988663", "tab": "recent", "posts": [ { "node": { "pk": "3928250036051888465", "code": "DaD8phTyclR", "media_type": 1, "like_count": 1200, "comment_count": 24, "caption": { "text": "A new perspective." }, "user": { "pk": "25025320", "username": "instagram" } } } ], "count": 1 } ``` ### GET /api/v1/instagram/anon/location/nearby Nearby-place pins around a location via logged-out GraphQL Parameters: - `location_id` (string, required) Response example: ```json { "location_id": "212988663", "count": 0, "pins": [] } ``` ### GET /api/v1/instagram/anon/location/info Best-effort location page metadata (name, category, post count text) Parameters: - `location_id` (string, required) Response example: ```json { "id": "212988663", "name": null, "title": "Location on Instagram", "post_count_text": null, "category": null, "price_level": null } ``` ## System endpoints ### GET /api/v1/health Health check (no auth) Parameters: - none Response example: ```json { "status": "ok", "mode": "anon_only", "anon_pool": { "proxy": "residential/us/high", "size": 16, "requests": 1200, "failures": 0 }, "time": "2026-09-15T08:00:00" } ``` ### GET /api/v1/instagram/anon/stats Anon IP-pool stats Parameters: - none Response example: ```json { "requests": 1200, "failures": 0, "process": { "open_fds": 64, "h2_clients": 8 }, "cache": { "entries": 0, "enabled": false } } ```