Get Instagram post comments as JSON

One request returns the first page of public comments on a post or reel.

People looking for an Instagram comment scraper usually want the text under one post, with the like count on each comment, as JSON they can store. That is one GET.

GET /v1/instagram/post/comments returns the first page of public comments on a post or reel. The reference describes that page as about 14 comments, in Instagram's own order. Each comment includes likes. Reply counts are null, because Instagram sends them empty to logged-out visitors.

The endpoint is in beta. A field the platform does not provide comes back as null. The API does not fill it in.

Send the key#

Put the key in the x-api-key header. It is not accepted in the query string, so it does not land in a log line or a browser history. A missing, malformed or revoked key is 401 unauthorized. A suspended key or team is 403 forbidden. Too few credits is 402 insufficient_credits. The shapes are on the authentication page.

Parameters#

Send one of url or id.

url is a post or reel link: /p/..., /reel/... or /tv/..., on instagram.com or instagr.am. id is the shortcode or the numeric media id. shortcode and media_id are aliases of id.

include_replies is accepted and ignored. Replies need a login, so the flag changes nothing. cursor is on the parameter list because list endpoints share it. On this endpoint has_more is always false. There is no logged-out way to the next page, so a cursor will not uncover the rest of the thread.

trim drops null fields and extra. raw also returns the platform object. max_age_days takes a number from 0 to 30. Absent or 0 means fetch fresh. A cached copy inside the window costs 0 credits. This endpoint keeps results 30 days. Nothing comes from the cache unless you ask. See caching.

The recorded request uses a public reel URL.

curl
curl -G "https://api.socialscrape.io/v1/instagram/post/comments" \
  -H "x-api-key: $SOCIALSCRAPE_API_KEY" \
  --data-urlencode "url=https://www.instagram.com/reel/DfF3eqGSKKc/"
Python
import os
import requests

params = {
    "url": "https://www.instagram.com/reel/DfF3eqGSKKc/",
}
res = requests.get(
    "https://api.socialscrape.io/v1/instagram/post/comments",
    headers={"x-api-key": os.environ["SOCIALSCRAPE_API_KEY"]},
    params=params,
)
body = res.json()

if body["ok"]:
    print(body["data"])
else:
    print(body["error"]["code"], body["error"]["message"])
TypeScript
const url = new URL("https://api.socialscrape.io/v1/instagram/post/comments");
url.search = new URLSearchParams({
  "url": "https://www.instagram.com/reel/DfF3eqGSKKc/"
}).toString();
const res = await fetch(url, {
  headers: { "x-api-key": process.env.SOCIALSCRAPE_API_KEY! },
});
const body = await res.json();

if (body.ok) {
  console.log(body.data);
} else {
  console.error(body.error.code, body.error.message);
}

Read body["ok"] before you touch data. The Python and TypeScript above already branch on error.code and error.message. Retry only when error.retryable is true. The message is for humans.

What the response contains#

A success envelope has ok, credits_charged, credits_remaining, cached, cached_at and request_id, then data. List endpoints also return cursor and has_more on the envelope. For this call both are empty of a next page: has_more is false and cursor is null.

data.object is list. Comments are data.items. Each item is a comment:

  • object is comment and platform is instagram.
  • id is the comment id. url points at that comment. post_id is the shortcode. parent_id is null on a top-level comment.
  • author carries id, handle, name, url, avatar_url and verified.
  • text is the comment body. published_at is when it was posted.
  • stats.likes is the like count. stats.replies is null. stats.dislikes is null.
  • is_pinned may be null. is_by_creator is true when the account that owns the post wrote the comment.

Sample. The recorded response is shortened and anonymised, so the author handle in that file is a placeholder (sample_user) and is not someone to store as a real account. stats.likes in that sample is a small integer, and stats.replies is null, which is the real shape, not an anonymisation. Do not treat sample balances (credits_remaining in the recording) as your account. Your balance is whatever the live envelope returns.

The comment total is not on this payload. It is stats.comments on the post, from GET /v1/instagram/post, using the same URL or shortcode. That call returns the caption, counts, media, owner, tagged users and, for a video, a view count taken from the embed page. extra.views_source is embed_views in that case, and the reference says it differs from the play count of the reels tab. include_play_count set to false skips that extra fetch.

curl
curl -G "https://api.socialscrape.io/v1/instagram/post" \
  -H "x-api-key: $SOCIALSCRAPE_API_KEY" \
  --data-urlencode "url=https://www.instagram.com/reel/DfF3eqGSKKc/"
Python
import os
import requests

params = {
    "url": "https://www.instagram.com/reel/DfF3eqGSKKc/",
}
res = requests.get(
    "https://api.socialscrape.io/v1/instagram/post",
    headers={"x-api-key": os.environ["SOCIALSCRAPE_API_KEY"]},
    params=params,
)
body = res.json()

if body["ok"]:
    print(body["data"])
else:
    print(body["error"]["code"], body["error"]["message"])
TypeScript
const url = new URL("https://api.socialscrape.io/v1/instagram/post");
url.search = new URLSearchParams({
  "url": "https://www.instagram.com/reel/DfF3eqGSKKc/"
}).toString();
const res = await fetch(url, {
  headers: { "x-api-key": process.env.SOCIALSCRAPE_API_KEY! },
});
const body = await res.json();

if (body.ok) {
  console.log(body.data);
} else {
  console.error(body.error.code, body.error.message);
}

One post plus one comment page is two successful requests, so two credits if both miss the cache.

Cost#

A successful comment page is 1 credit. You do not pay for a second page, because the second page is not available. Failures are free. Cached repeats are free when max_age_days is set.

New accounts get 100 credits once, with no card. Pack credits never expire. Monthly plan credits reset each month and do not roll over. The current packs and plans are on pricing. The rules, including which credits are spent first, are in credits.

Limits#

You get the first page Instagram shows a logged-out visitor, about 14 comments, in Instagram's order. You do not get a sort by likes. You do not get replies. You do not get the rest of a post that has hundreds of comments. If you need the size of the thread, read stats.comments on the post and treat the gap as data you do not have.

invalid_params and unsupported_url mean the link or the id was wrong. not_found means the post is missing. Do not retry those. rate_limited is 429, retryable, and costs 0 credits. The retry-after header says how many seconds to wait. The limit is per team. On free credits it is 30 requests a minute. A paid pack is 300. Monthly plans run from 120 on Starter to 1,200 on Scale. The table is on rate limits. Other codes are on errors.

The API is in early access, and this endpoint is beta, so later responses may gain fields. They will not start inventing reply counts.

Next#

Parameters, the sample and every error for this call are on the Instagram comments API page and in the reference. The same request in more languages is the tutorial, with a Python script and a JavaScript script. The post lookup is Instagram post or reel details. Every Instagram route is on the Instagram API hub.

If the job is a keyword rather than one URL, search reels first and then open comments on the ones you keep. That path is social listening.

Questions

Can I get every comment on a viral post?

No. The endpoint returns about 14 comments, in Instagram's own order, and has_more is always false. There is no logged-out next page. The total lives on the post as stats.comments.

Can I read replies?

No. include_replies is accepted and ignored. Reply counts are null because Instagram does not send them to logged-out visitors. Replies need a login.

What do I send, the URL or the shortcode?

One of them. url is a /p/, /reel/ or /tv/ link. id is the shortcode or the numeric media id. shortcode and media_id are aliases of id.

How much does a page cost?

1 credit when the request succeeds. A failed request costs 0. A cached repeat costs 0 if you send max_age_days. Results are kept 30 days.

Build on social data early.

Developers and agent builders get the first keys.

Get early access