# Instagram Scraper| Posts & Comments & Reels & Details (`amrhassan25/instagram-posts-comments-scraper`) Actor

Scrape Instagram posts, reels, comments, profiles, hashtags and places — no login, no cookies, no account at risk. Get every post with its comments in one run, reel play counts included. Drop-in compatible with the official Instagram Scraper. Errors are never charged.

- **URL**: https://apify.com/amrhassan25/instagram-posts-comments-scraper.md
- **Developed by:** [Amr Abdo](https://apify.com/amrhassan25) (community)
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.50 / 1,000 results

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## Instagram Scraper

**Instagram Scraper** gets public Instagram data without an account: posts, reels, **every public comment**, and profile, hashtag and place details. Paste Instagram URLs, usernames or search terms. You get captions, likes, comment counts, video play counts, video URLs, carousel images, tagged users, co-authors, sponsors, music and locations, exported as JSON, CSV or Excel, or through the Apify API.

- 🔓 **No login, no cookies, no account at risk.** It reads Instagram the way a logged-out visitor sees it, so no account can be banned.
- 💬 **Posts and their comments in one run.** Set *Comments per post* and each post arrives with its comments inside it. You don't need a second scraper or a dataset join.
- 🎬 **Real reel play counts.** Video posts carry `videoPlayCount` and `videoDuration`, even when you scrape a profile's regular feed.
- 🧩 **Drop-in replacement for the official Instagram Scraper.** The input and output fields are the same (`directUrls`, `resultsType`, `shortCode`, `likesCount`, `latestComments`, `childPosts`, …), so existing spreadsheets, Zaps and code keep working.
- 🎯 **You pay only for what you asked for.** Errors, retries and blocked inputs are free, and *Only posts newer than* stops the scrape at the first older post instead of charging you for posts you filtered out.
- 🛠️ **Self-repairing.** When Instagram changes its internal queries, the scraper re-learns them during the run instead of failing.
- ⚡ **Fast and light.** It uses plain HTTP with no browser, so runs finish quickly on 512 MB of memory.
- ♻️ **Safe under migrations.** If Apify moves your run to another server, the run continues where it stopped and nothing is delivered or charged twice.

### What data can you extract from Instagram?

| Posts & reels | Comments | Profiles | Hashtags & places |
|---|---|---|---|
| Caption, hashtags, mentions | Comment text | Username, full name, bio | Hashtag size (e.g. 385M posts) |
| Likes, comments count | Author username & picture | Followers, following, posts count | Related hashtags / searches |
| Video play count & duration | Comment likes | Verified, private account | Place name, category, address |
| Image, video and carousel URLs | Timestamp | Website link | Coordinates, post count |
| Date, location, tagged users | Direct comment URL | Profile picture (HD) | Top and recent posts |
| Co-authors, sponsors, music, pinned | Post URL | Latest posts | |

### Which Instagram URLs can I scrape?

| Paste this | Content to scrape | You get |
|---|---|---|
| Profile: `instagram.com/natgeo` or just `natgeo` | **Posts** | The profile's posts, newest first, with play counts joined in for videos |
| | **Reels** | The profile's reels with play counts, captions, dates and video URLs |
| | **Details** | Bio, followers, following, posts count, links, verified/private, latest posts |
| Post or reel: `/p/…`, `/reel/…` | **Posts** / **Reels** / **Details** | The full post with its first comments |
| | **Comments** | Every public top-level comment |
| Hashtag: `/explore/tags/crossfit/` | **Posts** / **Reels** | Instagram's top reels for the hashtag, each completed with date, likes and comment count |
| | **Details** | Size, description, 50 related searches, top posts |
| Place: `/explore/locations/7538318/` | **Posts** / **Reels** | The place's recent and top posts |
| | **Details** | Name, category, coordinates, address, post count, top posts |

**Search instead of URLs:** enter terms like `travel, crossfit` and choose one of two search types:

- *Hashtags* returns the term plus the related searches Instagram suggests.
- *Profiles* returns the exact account plus the creators of the top reels for the term.

Each match is then scraped with the *Content to scrape* you chose.

### How to scrape Instagram posts and comments

1. Click **Try for free** and sign in to Apify. The free plan includes monthly credit.
2. Paste one or more Instagram profile, post, hashtag or place URLs into **Instagram URLs**.
3. Choose **Content to scrape**: Posts, Reels, Comments or Details.
4. Optionally set **Comments per post** to get comments together with each post, and **Only posts newer than** to get recent posts only.
5. Click **Start**, then download the results as JSON, CSV, Excel or HTML, or send them to Google Sheets.

### How much does it cost to scrape Instagram?

You pay per result, and higher Apify plans get lower prices. One result is one post, reel, comment, profile, hashtag or place, and that includes each comment nested inside a post through *Comments per post*. There is no start fee and no separate charge for proxies or compute.

| Apify plan | Free | Starter | Scale | Business |
|---|---|---|---|---|
| Price per 1,000 results | $2.70 | $2.30 | $1.90 | $1.50 |

| Example (Starter plan) | Results | Price |
|---|---|---|
| 1,000 posts from a few profiles | 1,000 | $2.30 |
| 100 posts with 20 comments each | 100 + 2,000 | $4.83 |
| Details of 500 profiles | 500 | $1.15 |

Apify's free monthly credit covers about 1,800 results. Rows for inputs that could not be scraped are free. If you set a spending limit, the run stops cleanly and keeps everything it collected up to that point.

The first ~15 comments that Instagram includes with a single post URL are part of that post. They are **not** charged separately unless you ask for comments with *Comments per post*.

### Input example

```json
{
    "directUrls": ["https://www.instagram.com/natgeo/"],
    "resultsType": "posts",
    "resultsLimit": 50,
    "commentsPerPost": 20,
    "onlyPostsNewerThan": "30 days",
    "skipPinnedPosts": true
}
```

- **Results limit per URL** sets how many posts, reels or comments to return for each URL.
- **Comments per post** attaches up to this many comments to each post (`0` turns it off).
- **Only posts newer than** takes a date (`2026-09-01`) or a period (`3 days`, `2 weeks`, `6 months`), in UTC. On profiles the scrape *stops* at the first older post, so you never pay for posts you filtered out.
- **Skip pinned posts** leaves out pinned posts, which otherwise appear first even when they are old.

### Output example (a post)

This is a real record from `natgeo` with *Comments per post* set to 5, trimmed to one comment and with shortened URLs:

```json
{
    "inputUrl": "https://www.instagram.com/natgeo/",
    "id": "3993285920611830169",
    "type": "Video",
    "shortCode": "DdrAGMwowmZ",
    "url": "https://www.instagram.com/p/DdrAGMwowmZ/",
    "caption": "Crossing the Okavango Delta by mekoro (traditional canoes us…",
    "hashtags": [],
    "mentions": [
        "debeersgroup"
    ],
    "commentsCount": 87,
    "likesCount": 27428,
    "videoPlayCount": 859965,
    "videoDuration": 81.292,
    "videoUrl": "https://scontent-hbe1-2.cdninstagram.com/…Jy0LTKySwq5ofw.mp4",
    "displayUrl": "https://scontent-hbe1-2.cdninstagram.com/…216932702022_n.jpg",
    "timestamp": "2026-09-24T13:35:32.000Z",
    "ownerUsername": "natgeo",
    "ownerFullName": "National Geographic",
    "ownerId": "787132",
    "productType": "clips",
    "isPinned": false,
    "isSponsored": true,
    "taggedUsers": [],
    "coauthorProducers": [],
    "childPosts": [],
    "musicInfo": null,
    "locationName": null,
    "firstComment": "De beers?😂😂😂😂",
    "latestComments": [
        {
            "id": "18123574573924680",
            "text": "De beers?😂😂😂😂",
            "ownerUsername": "commenter_username",
            "timestamp": "2026-09-24T23:42:05.000Z",
            "likesCount": 0,
            "commentUrl": "https://www.instagram.com/p/DdrAGMwowmZ/c/18123574573924680/"
        }
    ],
    "scrapedCommentsCount": 5
}
```

Comments, profiles, hashtags and places each have their own record shape. The dataset has a ready-made view for each: **Posts & reels**, **Comments**, **Profiles** and **Inputs that could not be scraped**.

### Use the Instagram scraper through the API and integrations

- **API:** start runs and download results from any language. The **API** tab has ready-made code for Node.js, Python and cURL.
- **Scheduling:** run it daily or hourly to monitor profiles, hashtags or competitors. Set *Only posts newer than* to your schedule interval (e.g. `1 day`) so every run returns only new posts.
- **Integrations:** send results to Google Sheets, Make, Zapier, n8n, Slack, Airbyte or a webhook.
- **AI agents:** the Actor can be called as a tool through the Apify MCP server.

### What Instagram does not show logged-out visitors

This scraper never logs in, so it gets exactly what an incognito browser sees. A few things are out of reach, and each one returns a clear error row instead of failing silently:

- **Mentions / tagged posts:** the Tagged tab requires login. To find posts about a brand, scrape its hashtag instead.
- **Place search:** Instagram's search box refuses logged-out visitors. Paste place URLs instead.
- **Replies to comments:** only top-level comments are public, and reply counts are hidden too.
- **A few broad or sensitive keywords** such as `#fitness` or `#food`: Instagram shows logged-out visitors no posts for them. You get an error row saying so; more specific hashtags (`#crossfit`, `#gym`) work.
- **Private profiles:** details are returned, but posts are not.
- **Numeric profile IDs:** only the 17-digit `1784…` account ID can be resolved. For other numeric IDs, use the username.
- **Depth limits set by Instagram:** hashtag pages show about 50 top reels, and a place shows about 18 recent posts and 50 top posts. Profiles and comments have no such limit.

Counts are a snapshot taken at the moment of the run, as seen by logged-out visitors. They can be lower than what a logged-in account sees, because engagement from private accounts is hidden.

### Tips

- Leave the proxy on **Residential** (the default). Instagram is far less willing to answer datacenter IPs.
- Use the **Comments** view of the dataset to export comments on their own, or *Comments per post* to keep each post and its comments together.
- To scrape many posts' comments, paste all the post URLs into one run rather than starting one run per post.

### FAQ

#### Do I need an Instagram account or cookies?

No. The scraper never logs in and never asks for cookies or a session ID, so no Instagram account can be banned or checkpointed because of it.

#### Is it legal to scrape Instagram?

This scraper collects only data that Instagram shows publicly to anyone without an account. Public data can still be personal data under laws such as the GDPR, so scrape only what you have a legitimate reason to process. If you are unsure, ask a lawyer.

#### Can I scrape all comments from an Instagram post?

Yes. Choose **Comments**, paste the post or reel URL, and set **Results limit per URL** as high as you need. All public top-level comments are returned; replies to comments are visible only to logged-in users.

#### How is this different from the official Instagram Scraper?

It uses the same input and output fields and the same per-result prices, so you can switch without changing your integrations or your budget. It also gets each post with up to as many comments as you want in one run, stops early on date filters so you never pay for filtered-out posts, and repairs itself when Instagram changes its internal queries. What it cannot do is anything that needs a login: tagged posts, place search and comment replies.

#### What happens when Instagram changes its website?

The scraper detects when Instagram changes its internal queries and re-learns them automatically during the run. If something still breaks, open an issue on the **Issues** tab and it will be fixed quickly.

#### Why do I see fewer likes or comments than in the Instagram app?

Logged-out visitors don't see engagement from private accounts, and some creators hide like counts (returned as `-1`). The numbers are what Instagram shows publicly at the moment of the run.

#### I found a bug or need a feature

Open an issue on the **Issues** tab with the input you used and the run link. Feature requests are welcome.

# Actor input Schema

## `directUrls` (type: `array`):

Profiles (<code>instagram.com/natgeo</code> or just <code>natgeo</code>), posts and reels (<code>/p/…</code>, <code>/reel/…</code>), hashtags (<code>/explore/tags/…</code>) and places (<code>/explore/locations/…</code>). What each URL can return depends on its type — see the README table.

## `resultsType` (type: `string`):

<strong>Posts</strong>: feed posts (from a profile, hashtag or place; or one post URL). <strong>Reels</strong>: reels with play counts. <strong>Comments</strong>: every public comment on a post or reel URL. <strong>Details</strong>: profile, hashtag or place metadata.

## `resultsLimit` (type: `integer`):

Maximum posts, reels or comments to return for each URL. Comments nested with <em>Comments per post</em> do not count toward this limit.

## `commentsPerPost` (type: `integer`):

Get posts <strong>and</strong> their comments in one run: each post carries up to this many comments in <code>latestComments</code>. Every nested comment counts as one result. <code>0</code> turns it off.

## `onlyPostsNewerThan` (type: `string`):

Skip anything older than this (UTC). A date like <code>2026-09-01</code> or <code>2026-09-01T13:00:00</code>, or a period like <code>3 days</code>, <code>2 weeks</code>, <code>6 months</code>. For profiles and places the scrape stops as soon as posts get older, so older posts are never paid for.

## `skipPinnedPosts` (type: `boolean`):

Leave out the posts and reels a profile has pinned to the top of its grid.

## `search` (type: `string`):

Used only when no URLs are given. Comma-separated, e.g. <code>travel, fitness</code>. Hashtags without the <code>#</code>.

## `searchType` (type: `string`):

<strong>Hashtags</strong>: the term plus the related searches Instagram suggests for it. <strong>Profiles</strong>: the exact account (if it exists) plus the creators of the top reels for the term. Each match is then scraped using <em>Content to scrape</em>.

## `searchLimit` (type: `integer`):

How many hashtags or profiles to take from each search term.

## `maxConcurrency` (type: `integer`):

How many requests run at once. The default is fast and safe; lower it only if you see many retries in the log.

## `proxyConfiguration` (type: `object`):

Residential proxies are recommended. Instagram answers anonymous traffic best from residential IPs.

## Actor input object example

```json
{
  "directUrls": [
    "https://www.instagram.com/natgeo/",
    "https://www.instagram.com/p/Ddqj4u_DAwS/"
  ],
  "resultsType": "posts",
  "resultsLimit": 20,
  "commentsPerPost": 0,
  "skipPinnedPosts": false,
  "searchType": "hashtag",
  "searchLimit": 10,
  "maxConcurrency": 8,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}
```

# Actor output Schema

## `results` (type: `string`):

All scraped items.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "directUrls": [
        "https://www.instagram.com/natgeo/"
    ],
    "resultsType": "posts",
    "resultsLimit": 20,
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("amrhassan25/instagram-posts-comments-scraper").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = {
    "directUrls": ["https://www.instagram.com/natgeo/"],
    "resultsType": "posts",
    "resultsLimit": 20,
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("amrhassan25/instagram-posts-comments-scraper").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "directUrls": [
    "https://www.instagram.com/natgeo/"
  ],
  "resultsType": "posts",
  "resultsLimit": 20,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call amrhassan25/instagram-posts-comments-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,amrhassan25/instagram-posts-comments-scraper"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/8A7jw72cS6TVUdKuM/builds/odEb9ZdrmcEY59T8d/openapi.json
