How to Scrape Instagram Comments (Text, Usernames & Timestamps)
If you want to know what people actually think about a post, the comments are where it lives. Customer questions, complaints, praise, objections, and the occasional viral thread — all sitting under the post, unstructured and impossible to read at scale by hand.
Copying comments one by one doesn't work past the first few. This guide shows you how to scrape Instagram comments programmatically: the exact endpoint, the real response shape, how pagination works, and a few things the data honestly can't tell you.
What you can (and can't) get
From any public post or reel, each comment gives you:
| Field | What it is |
|---|---|
text | The comment content, including emoji |
user.username | The handle that wrote it |
created_at | ISO 8601 timestamp of when it was posted |
user.is_verified | Whether the commenter is verified |
user.id / user.pk | The commenter's numeric user ID |
user.profile_pic_url | The commenter's avatar URL |
What you can't get, so you don't build on false assumptions:
- Comments on private accounts. If the post isn't publicly visible, it isn't reachable. This is a hard limit, not a setting.
- Guaranteed per-comment like counts or structured reply threads. Instagram exposes these inconsistently; treat them as optional and read them defensively rather than assuming they're always present.
- Deleted or hidden comments. You only see what's live and public at request time.
The endpoint
One GET request returns a page of comments:
GET https://api.sociavault.com/v1/scrape/instagram/comments?url=<post-or-reel-url>
| Parameter | Required | Description |
|---|---|---|
url | Yes | Full Instagram post or reel URL |
cursor | No | Pagination cursor from the previous response's data.cursor |
It costs 1 credit per request (flat), regardless of how many comments come back in that page. To go deeper on a post with thousands of comments, you page through with cursor — each page is another 1-credit request.
Real response shape
SociaVault wraps every response in the same envelope: success, data, credits_used, and endpoint. The comments live in data.comments:
{
"success": true,
"data": {
"num_comments_grabbed": 343,
"comments": [
{
"id": "17916526530048829",
"text": "This ingredient list is actually clean, impressed",
"created_at": "2025-01-17T14:07:40.000Z",
"user": {
"username": "hearts4_therealest",
"is_verified": false,
"id": "64101106104",
"pk": "64101106104",
"profile_pic_url": "https://scontent.cdninstagram.com/v/..."
}
}
],
"cursor": "eyJjYWNoZWQi..."
},
"credits_used": 1,
"endpoint": "instagram/comments"
}
Two things worth internalizing: the payload is under data (not the top level), and data.cursor is what you pass back in to fetch the next page. When there are no more comments, cursor comes back empty or missing.
How to scrape Instagram comments in JavaScript
async function getComments(postUrl, cursor) {
const params = new URLSearchParams({ url: postUrl });
if (cursor) params.set("cursor", cursor);
const res = await fetch(
`https://api.sociavault.com/v1/scrape/instagram/comments?${params}`,
{ headers: { "x-api-key": "YOUR_API_KEY" } },
);
return res.json();
}
const first = await getComments("https://www.instagram.com/p/ABC123/");
for (const c of first.data.comments) {
console.log(`@${c.user.username}: ${c.text}`);
}
Paginate through every comment
Loop until there's no cursor left. Cap the page count so a runaway loop can't quietly burn credits:
async function getAllComments(postUrl, maxPages = 20) {
const all = [];
let cursor;
for (let page = 0; page < maxPages; page++) {
const { data } = await getComments(postUrl, cursor);
if (!data?.comments?.length) break;
all.push(...data.comments);
cursor = data.cursor;
if (!cursor) break;
await new Promise((r) => setTimeout(r, 300)); // be polite between calls
}
return all;
}
How to scrape Instagram comments in Python
import requests
API_KEY = "YOUR_API_KEY"
BASE = "https://api.sociavault.com/v1/scrape/instagram/comments"
def get_comments(post_url, cursor=None):
params = {"url": post_url}
if cursor:
params["cursor"] = cursor
res = requests.get(BASE, params=params, headers={"x-api-key": API_KEY})
return res.json()
def get_all_comments(post_url, max_pages=20):
comments, cursor = [], None
for _ in range(max_pages):
payload = get_comments(post_url, cursor).get("data", {})
batch = payload.get("comments", [])
if not batch:
break
comments.extend(batch)
cursor = payload.get("cursor")
if not cursor:
break
return comments
for c in get_all_comments("https://www.instagram.com/p/ABC123/"):
print(f"@{c['user']['username']}: {c['text']}")
What people actually do with comment data
Sentiment analysis
The most common use: figure out whether a post landed well. Pull a few hundred comments and score them.
from textblob import TextBlob
def sentiment_breakdown(comments):
tally = {"positive": 0, "negative": 0, "neutral": 0}
for c in comments:
polarity = TextBlob(c["text"]).sentiment.polarity
if polarity > 0.1:
tally["positive"] += 1
elif polarity < -0.1:
tally["negative"] += 1
else:
tally["neutral"] += 1
return tally
comments = get_all_comments("https://www.instagram.com/p/ABC123/")
print(sentiment_breakdown(comments))
# {'positive': 210, 'negative': 38, 'neutral': 95}
A caveat worth stating: off-the-shelf sentiment models struggle with sarcasm, slang, and emoji-only comments. Treat the breakdown as a directional signal, not a verdict.
Pull the questions people are asking
Comment questions are free FAQ and content-idea fuel:
function extractQuestions(comments) {
const starters = ["how", "what", "where", "when", "why", "can", "does", "is"];
return comments.filter((c) => {
const t = c.text.toLowerCase().trim();
return t.includes("?") || starters.some((s) => t.startsWith(s + " "));
});
}
Spot low-effort or bot-like comments
You can't see a commenter's follower count from this endpoint, so don't build detection on data you don't have. What you can flag cheaply: generic one-liners and emoji-only comments, which cluster on posts with inflated engagement.
function flagLowEffort(comments) {
const generic = ["nice", "great post", "love this", "amazing", "wow", "cool"];
const emojiOnly = /^[\p{Emoji}\s]+$/u;
const flagged = comments.filter((c) => {
const t = c.text.toLowerCase().trim();
return generic.includes(t.replace(/[!.]/g, "")) || emojiOnly.test(c.text);
});
return {
total: comments.length,
flagged: flagged.length,
rate: ((flagged.length / comments.length) * 100).toFixed(1) + "%",
};
}
This is a heuristic, not proof of bots — plenty of real people leave "🔥🔥🔥." Use it to compare posts, not to accuse accounts.
Export to CSV
function toCSV(comments) {
const header = ["username", "text", "created_at", "verified"];
const rows = comments.map((c) => [
c.user.username,
`"${c.text.replace(/"/g, '""')}"`,
c.created_at,
c.user.is_verified ?? false,
]);
return [header.join(","), ...rows.map((r) => r.join(","))].join("\n");
}
Tips for cleaner results
- Grab enough for the job. For sentiment, 200+ comments smooths out noise. A dozen tells you little.
- Cap your pagination. Always set a page limit so a viral post with 40,000 comments doesn't page forever.
- Store the timestamps.
created_atlets you track how sentiment shifts as a post ages or gets picked up. - Read optional fields defensively. If you rely on a field that isn't in the sample above, guard it with a fallback and log the raw response once to confirm it's there for your posts.
Getting started
- Sign up and grab 50 free credits — no card.
- Copy your API key from the dashboard.
- Send your first request to
/v1/scrape/instagram/commentswith any public post URL.
Frequently Asked Questions
How do I scrape comments from an Instagram post?
Send a GET request to /v1/scrape/instagram/comments with the post or reel url and your API key. You get back structured JSON with each comment's text, author username, and timestamp. To pull more than one page, pass the cursor from the previous response.
Can I scrape comments from any Instagram post?
Any public post or reel. Private accounts and their posts can't be accessed — that content isn't publicly visible, so there's no legitimate way to retrieve it.
How many comments can I get, and what does it cost?
Each request costs 1 credit and returns a page of comments. For posts with thousands of comments, you paginate with cursor — each additional page is another 1-credit request. Cap your loop so you only pay for what you need.
Do I get replies to comments?
The endpoint returns comments on the post. Reply threads and per-comment like counts are exposed inconsistently by Instagram, so don't assume they're always present — read those fields defensively and fall back gracefully when they're missing.
Can I get the commenter's profile details?
You get the commenter's username, verified status, user ID, and profile picture URL. For deeper data like their follower count or bio, run their handle through the Instagram profile endpoint separately.
Is scraping Instagram comments legal?
Scraping publicly visible data is generally permissible, but the details matter — see our Instagram scraping legal guide for the nuance (public vs. private data, terms of service, and relevant case law).
Related guides:
Found this helpful?
Share it with others who might benefit
Ready to Try SociaVault?
Start extracting social media data with our powerful API. No credit card required.