You can scrape Instagram's public profiles, posts, reels, comments and hashtags without logging in. That gets you captions, like and comment counts, play counts, timestamps, media links and owner details. The fastest way is a ready-made Actor: paste a profile or post URL, choose what to collect, and export JSON or CSV when the run finishes.
This guide covers the fields you get, the no-code steps, and the API flow for curl, Python, JavaScript and AI agents. It also covers costs, limits, the legal side and the official Instagram API. Every number comes from a real run on 22 October 2026 that collected the five latest reels from National Geographic's profile. That run took 72 seconds, which matters for how you call the API.
What data you can get from Instagram
Each row is one result: a post, reel, comment, profile, hashtag or place, depending on resultsType. For posts and reels, these are the fields most people use:
| Field | What it holds |
|---|---|
type, productType | Media type (e.g. Video); productType is clips for reels |
shortCode, url | The post ID in the URL, and the link |
caption | Caption text |
hashtags, mentions | Hashtags and @mentions in the caption |
ownerUsername, ownerFullName | The account that posted it |
likesCount | Likes, or -1 when Instagram hides the count |
commentsCount | Number of comments |
videoPlayCount | Plays, on videos and reels |
videoDuration | Length in seconds |
timestamp | Upload time in UTC |
latestComments | A few recent comments with text, author, likes and time |
musicInfo | The audio track, and whether it is original audio |
isPinned, paidPartnership | Pinned on the profile; marked as a paid partnership |
Profile details add followersCount, followsCount, postsCount, verified and biography. Stories, a profile's mentions feed, nested comment replies and a second page of comments have come back empty, so they aren't part of the output. Private profiles can't be scraped.
How to scrape Instagram without code
- Open the Instagram Scraper in the Scrape.ly Store.
- Pick the Nat Geo reels preset. It fills in this input:
{
"resultsType": "reels",
"directUrls": [
"https://www.instagram.com/natgeo/"
],
"resultsLimit": 5
}- Replace the URL with the public profile, post or reel you want, and set the limit.
- Start the run and wait. Ours took 72 seconds for five reels.
- Export the results as JSON, CSV or Excel.
The input fields that matter most:
resultsType: one content type per run.postsreturns a feed,reelsreturns clips,detailsreturns the profile or hashtag metadata, andcommentsworks only with post or reel URLs. Defaultposts.directUrls: the Instagram URLs to scrape. When this list has entries, search is ignored.resultsLimit: how many posts, reels or comments to return per URL. Default 20.onlyPostsNewerThan: a UTC cutoff such as2026-10-01or a relative value like1 week. Older posts are dropped. Pinned posts stay unless you also setskipPinnedPosts.proxyConfiguration: the input schema says a residential proxy is required, because logged-out datacenter IPs are rate-limited with HTTP 429. With Scrapely Proxy on and no group chosen, the run uses the residential group, so leave the default alone.
To search instead, leave directUrls empty and use search with searchType (hashtag, profile or place) and searchLimit.
How to scrape Instagram with the API
Get your token from Settings → API & Integrations in the Scrape.ly dashboard and export it as SCRAPELY_TOKEN. The Actor API docs list every endpoint.
curl (asynchronous)
The synchronous endpoint waits at most 45 seconds, and this run took 72. A sync call would answer 408 while the run kept going, and calling again would start a second run. So start the run, wait for it, then fetch the items:
# 1. start the run; the response's data.id is the run ID
curl -X POST "https://api.scrape.ly/v2/actors/echofield~instagram-scraper/runs" \
-H "Authorization: Bearer $SCRAPELY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"resultsType": "reels", "directUrls": ["https://www.instagram.com/natgeo/"], "resultsLimit": 5}'
# 2. wait (up to 60 s per call; repeat until status is SUCCEEDED)
curl "https://api.scrape.ly/v2/actor-runs/RUN_ID?waitForFinish=60" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"
# 3. read the items (CSV here)
curl "https://api.scrape.ly/v2/actor-runs/RUN_ID/dataset/items?format=csv" \
-H "Authorization: Bearer $SCRAPELY_TOKEN"Replace RUN_ID with the data.id from step 1. Drop ?format=csv to get JSON. The dataset API covers paging for bigger runs.
Python
Install the Python client with pip install scrapely-client-python. call() waits for the run however long it takes, so the 72 seconds are not a problem here.
import os
from scrapely_client import ScrapelyClient
client = ScrapelyClient(os.environ["SCRAPELY_TOKEN"], api_url="https://api.scrape.ly")
run = client.actor("echofield/instagram-scraper").call(
run_input={
"resultsType": "reels",
"directUrls": ["https://www.instagram.com/natgeo/"],
"resultsLimit": 5,
}
)
print(run.status) # SUCCEEDED, FAILED, ABORTED or TIMED-OUT
for item in client.dataset(run.default_dataset_id).iterate_items():
print(item["url"], item.get("likesCount"), item.get("videoPlayCount"))JavaScript
Install the JavaScript client with npm install scrapely-client. call() waits here too.
import { ScrapelyClient } from 'scrapely-client';
const client = new ScrapelyClient({ token: process.env.SCRAPELY_TOKEN, baseUrl: 'https://api.scrape.ly' });
const run = await client.actor('echofield/instagram-scraper').call({
resultsType: 'reels',
directUrls: ['https://www.instagram.com/natgeo/'],
resultsLimit: 5,
});
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);MCP for AI agents
Scrape.ly runs a hosted MCP server at https://api.scrape.ly/mcp. In Cursor, add it to ~/.cursor/mcp.json:
{
"mcpServers": {
"scrapely": {
"url": "https://api.scrape.ly/mcp",
"headers": { "Authorization": "Bearer YOUR_TOKEN" }
}
}
}In Claude Code, run claude mcp add --transport http scrapely https://api.scrape.ly/mcp, then /mcp to sign in with OAuth. The agent uses search-actors, fetch-actor-details, call-actor and get-actor-output. call-actor waits up to 45 seconds, so on a run like this one the agent then polls get-actor-run until it finishes. Try: "Use scrapely to run echofield/instagram-scraper for the 5 latest reels on https://www.instagram.com/natgeo/ and give me a CSV of URL, caption, likes and plays."
A real run: Nat Geo reels, 5 reels
We ran the preset on 22 October 2026. It saved 5 reels in 71.8 seconds on 512 MB of memory and was charged $0.0189 in total. Every row has type "Video", so that column is left out:
| ownerUsername | caption | likesCount | commentsCount | videoPlayCount | timestamp | url |
|---|---|---|---|---|---|---|
| natgeo | No wrong answers to this question. #IndiaFromAbove is now streaming … | 13,554 | 78 | 569,078 | 2026-10-21T22:08:24.000Z | instagram.com/p/DexcZdvAHXT/ |
| natgeofamily | Let creativity run wild with the new Glow-in-the-Dark Marble Run from… | 7,274 | 18 | 749,952 | 2026-10-21T19:00:03.000Z | instagram.com/p/Dew3eLnCWRj/ |
| natgeo | Presented by @Rolex. These flamingos aren’t dancing—they’re “farming,… | 20,481 | 64 | 849,864 | 2026-10-21T16:04:09.000Z | instagram.com/p/DewyiAJRjgh/ |
| natgeoscience | The Fermi Paradox poses one of the most important questions about our… | 24,415 | 432 | 1,039,309 | 2026-10-21T13:01:27.000Z | instagram.com/p/Dewd1c3iRmI/ |
| natgeo | Don't let its stubby arms fool you—Koleken inakayali was an ambush pr… | 78,754 | 865 | 4,443,295 | 2026-10-20T22:05:09.000Z | instagram.com/p/Deu3BoCBbDP/ |
The accounts shown are National Geographic's own verified brand accounts. The full records also include latestComments, where we replaced each commenter's username with [commenter 1], [commenter 2] and so on, because they are private individuals.
The console shows why the run took a while:
2026-10-22T15:24:17.491Z [Scrapely] Container started (setup 0.8 s)
2026-10-22T15:24:19.029Z [scrapely.proxy_configuration] INFO Platform proxy access check succeeded.
2026-10-22T15:24:29.378Z INFO:instagram:Mobile Instagram request status=400 len=136
2026-10-22T15:24:30.937Z INFO:instagram:Rotated Instagram proxy session after a block or rate limit
2026-10-22T15:25:04.764Z INFO:instagram:Instagram warmup failed error=Timeout; retiring exit
2026-10-22T15:25:27.698Z [scrapely.actor] INFO Pushed 5 dataset items
2026-10-22T15:25:27.920Z [scrapely.actor] INFO [Status message]: Saved 5 results.
2026-10-22T15:25:28.518Z [Scrapely] Container state: status=exited exitCode=0 oomKilled=falseThe full log has five proxy-session rotations and one 20-second timeout before the data came through. The Actor rotates its session after a block or rate limit and keeps going, and the run still finished with all five reels. Two of the five rows were posted by natgeofamily and natgeoscience, not natgeo, even though the input was the natgeo profile. Filter on ownerUsername if you want one account's reels only. All five reels were posted within two days of the run, and plays ranged from 569,078 to 4,443,295.
What it costs
The Actor has one event price:
- Result: $0.002 per saved result: a post, reel, comment, profile, hashtag or place.
This run saved 5 results, so the result fees were 5 × $0.002 = $0.01. The run was charged $0.0189 in total because platform usage was added: $0.0065 of residential proxy traffic, $0.0024 of compute and under a tenth of a cent for dataset and key-value store writes. On this run, platform usage ($0.0089) came close to the result fees. Retries like the ones in the log add proxy traffic and compute time, so expect it to vary from run to run.
For 1,000 results you pay $2.00 in result fees, whether they are reels, posts or comments. Platform usage comes on top. Failed inputs are never saved and never charged. You can set a maximum charge for a run, and the scraper stops cleanly when it reaches it, keeping what it already saved.
Limits and common problems
- Runs can outlast the sync limit. Blocks and session rotations made this five-reel run take 72 seconds. Use the asynchronous flow or the clients, not the 45-second sync endpoint.
- Residential proxy only. The input schema says logged-out datacenter IPs get HTTP 429. Keep
proxyConfigurationon its residential default. - One content type per run.
resultsTypetakes one value. To get a profile's details and its reels, run twice. Comments work only with post or reel URLs. - Comments stop at the first page. You get the comments Instagram returns on a post's first page. Nested replies and a second page have come back empty, so don't plan a pipeline on them.
- Hidden counts read -1.
likesCountis-1when the account has hidden like and view counts. Filter those out before you average. - Bad URLs are skipped, not saved. A private profile, a URL that doesn't fit the chosen
resultsTypeor a blocked request is listed in the run'sOUTPUTrecord underfailedInputs. The rest of the run continues.
Is it legal to scrape Instagram?
Everything in this guide is visible to anyone without an Instagram account. Instagram's own rules still restrict it. Its Terms of Use say you can't access or collect information in an automated way without Instagram's express permission, whether or not you are logged in. They also say you can't sell, license or purchase data obtained from the service.
Brand accounts like National Geographic are one thing. Commenters, tagged users and most creators are private individuals, and their usernames, comments and photos are personal data. Privacy laws like the GDPR and CCPA then govern how you collect, store and use them. This is not legal advice: if you plan to scrape Instagram for a business, get advice from a lawyer for your case.
Alternatives
- The Instagram Platform API. Meta's official APIs serve Instagram professional accounts (business or creator). They cover accounts you own or manage, and accounts whose owners log in to your app and grant permissions. Serving accounts you don't own needs Advanced Access, which requires App Review and Business Verification. Hashtag search is available only with Facebook Login, through the Instagram Public Content Access feature. It is the better choice for your own account's posts and comments, or for a tool your clients connect to.
- Instaloader. An open-source Python tool that downloads pictures and videos with their captions and metadata. It suits archiving a few public profiles from your own machine, where you handle rate limits yourself.
- A headless browser. Playwright or Puppeteer with residential proxies gives you full control. You also have to keep up when Instagram moves data between page payloads and internal endpoints, which can break a scraper without any error.
FAQ
Can you scrape Instagram without logging in?
Yes, for public content. This Actor has no session-cookie input and reads only what logged-out visitors can see: public profiles, posts, reels, hashtags and first-page comments. Private profiles can't be scraped, and stories have come back empty.
How do I scrape Instagram reels?
Set resultsType to reels and put the profile URL in directUrls, as in the preset above. Each reel comes back with videoPlayCount, videoDuration, likesCount, commentsCount and musicInfo.
Can you scrape Instagram comments?
Yes. Set resultsType to comments and pass post or reel URLs. You get each comment's text, author, likes, reply count and time, from the first page of comments, at $0.002 per comment. Commenters are usually private individuals, so handle their data under privacy law.
Can you scrape Instagram followers?
Not as a list. Profile details (resultsType: details) return followersCount and followsCount, but this Actor doesn't return who the followers are.
How much does it cost to scrape Instagram?
$2.00 per 1,000 results in result fees, plus platform usage. Our five-reel run cost $0.0189 in total.




