# Instagram Scraper — Posts, Reels, Hashtags, Locations & Audio (`yugenox/instagram-scraper`) Actor

Scrape Instagram posts and reels from profiles, reels tabs, hashtags, keywords, locations, audio pages and post URLs. Likes, comments, plays, captions, media URLs, owner, co-authors, tagged users, location and music — no login, no cookies.

- **URL**: https://apify.com/yugenox/instagram-scraper.md
- **Developed by:** [Yugenox Corp](https://apify.com/yugenox) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.90 / 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.

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 — Posts, Reels, Comments, Profiles, Hashtags & Locations

Scrape public Instagram **posts, reels, comments, profiles, hashtags, locations and audio**. You get likes, comments, plays, captions, media URLs, owners with follower counts, co-authors, tagged users, sponsors, music and locations. Add-ons include the latest comments, video transcripts, Instagram's AI summaries, business details, contact info and related accounts.

- 🔑 **No Instagram login, no cookies.** Paste URLs and run.
- ⚡ **Fast.** About 1,000 fully detailed posts per minute.
- 💰 **One simple price.** $1.90 per 1,000 results with add-ons included; transcripts are billed per minute. No monthly fees.
- 🛡️ **Built to keep running.** It rotates IPs by itself and adapts when Instagram changes its web app.
- 🧭 **Discovery built in.** Find similar accounts, expand hashtags into related keywords, and filter by followers, verified or business accounts.

### What you can scrape

| Input | Example | What you get |
|---|---|---|
| 👤 Profile | `https://www.instagram.com/nasa/` or `nasa` | The profile's posts, newest first, as deep as the profile goes |
| 🎬 Reels tab | `https://www.instagram.com/nasa/reels/` | The profile's reels, with play counts |
| #️⃣ Hashtag | `https://www.instagram.com/explore/tags/travel/` or `#travel` | Top posts for the hashtag |
| 🔍 Keyword | `keywords: ["toronto"]` or `/explore/search/keyword/?q=toronto` | Top posts for the keyword |
| 📍 Location | `https://www.instagram.com/explore/locations/213131048/` | Top and most recent posts at the place |
| 🎵 Audio | `https://www.instagram.com/reels/audio/271328201351336/` | Reels using that sound |
| 🖼️ Post or reel | `https://www.instagram.com/p/DRvit9Ejgel/` or a `/share/` link | That post, or its comments |
| 🔢 User ID | `528817151` | That profile's posts |

#### Three result types (`resultsType`)

- **posts** (default): posts and reels, one row each.
- **details**: one row per source:
  - **Profiles**: bio, all bio links, followers and following, reels count, highlights, category (e.g. "Bakery"), account type (personal, business or creator), Threads username, HD profile picture, **emails and phones found in the bio**, and optionally up to 50 **related accounts**.
  - **Hashtags and keywords**: Instagram's topic description with sources, plus up to 100 related keywords.
  - **Locations**: category, coordinates, address, price range, opening status, the place's Instagram account and its post count.
- **comments**: the comments on each post (text, author, likes, date), from post URLs or from every post a profile, hashtag or location returns.

#### Add-ons for posts

| Option | Adds |
|---|---|
| `commentsPerPost` | `latestComments`: the newest N comments on each post |
| `includeTranscript` | `transcript` and `transcriptLanguage`: speech-to-text for every video, in any language (up to 15 minutes; $0.004 per minute) |
| `includeAiSummary` | `aiTitle` and `aiSummary`: Instagram's own AI description of the post |
| `includeVideoViews` | `video.viewCount`: Instagram's "views" metric, alongside `video.playCount` |
| `includeDetails` | The profile, keyword and place rows described above, alongside the posts |

#### Discovery and filters

- `scrapeRelatedProfiles`: also scrape up to N accounts similar to each profile you give. Useful for finding competitors or lookalike creators.
- `expandRelatedKeywords`: go past Instagram's ~60 top posts per hashtag by also pulling related keywords.
- `minFollowers`, `maxFollowers`, `verifiedOnly`, `businessOnly`, `withContactOnly` and `skipPinnedPosts`: rows that don't match are skipped and not billed.

### Input

| Field | Type | Description |
|---|---|---|
| `startUrls` | array | Instagram URLs, handles or #hashtags (see table above) |
| `keywords` | array | Keywords to search. Each keyword is a separate query |
| `maxItems` | integer | Maximum number of posts across the whole run |
| `resultsType` | string | `posts` (default), `details` or `comments` |
| `maxItemsPerQuery` | integer | Maximum number of items per URL or keyword |
| `until` | string | Only posts created on or after this date (`YYYY-MM-DD`) or within a period like `7 days` or `3 months`. Profile scraping stops as soon as it reaches older posts, so you don't pay for them |
| `includeDetails` | boolean | Adds profile, keyword and place rows alongside the posts |
| `commentsPerPost` / `maxComments` | integer | Latest comments attached to each post / comments per post in comments mode |
| `includeTranscript`, `includeAiSummary`, `includeVideoViews` | boolean | Post add-ons (see above) |
| `includeRelatedProfiles`, `scrapeRelatedProfiles`, `expandRelatedKeywords` | | Discovery (see above) |
| `minFollowers`, `maxFollowers`, `verifiedOnly`, `businessOnly`, `withContactOnly`, `skipPinnedPosts` | | Filters |
| `customMapFunction` | string | JavaScript function that transforms each item (see below) |
| `maxConcurrency` | integer | Number of parallel requests (default 20) |

```json
{
  "startUrls": ["https://www.instagram.com/nasa/", "https://www.instagram.com/explore/tags/travel/"],
  "keywords": ["toronto"],
  "until": "2026-09-01",
  "maxItems": 200
}
```

### Output

One row per post (`dataType: "post"`):

```json
{
  "dataType": "post",
  "id": "3991849403537918302_13460080",
  "pk": "3991849403537918302",
  "code": "Ddl5eH-u4le",
  "url": "https://www.instagram.com/reel/Ddl5eH-u4le/",
  "createdAt": "2026-09-22T14:00:04.000Z",
  "caption": "Just a normal day for @caitlinclark22 …",
  "hashtags": [],
  "mentions": ["caitlinclark22"],
  "likeCount": 25582,
  "commentCount": 487,
  "mediaType": "video",
  "productType": "clips",
  "isVideo": true,
  "isCarousel": false,
  "isPinned": false,
  "isPaidPartnership": false,
  "isLikeAndViewCountsDisabled": false,
  "commentsDisabled": false,
  "owner": {
    "id": "13460080", "username": "nike", "fullName": "Nike", "isVerified": true, "isPrivate": false,
    "profilePicUrl": "https://…", "followerCount": 291000000, "followingCount": 266,
    "biography": "…", "externalUrl": "https://…"
  },
  "coowners": [{ "id": "306787899", "username": "nikebasketball", "fullName": "Nike Basketball", "isVerified": true }],
  "taggedUsers": [{ "id": "1466972266", "username": "caitlinclark22", "fullName": "Caitlin Clark", "isVerified": true }],
  "location": { "id": "213131048", "name": "Berlin, Germany", "slug": "berlin-germany", "address": null, "city": null, "lat": 52.518, "lng": 13.401 },
  "audio": { "id": "…", "title": "Original audio", "artist": "nike", "isOriginal": true },
  "image": { "url": "https://…", "width": 1080, "height": 1920 },
  "video": { "url": "https://….mp4", "duration": 30.03, "playCount": 915165, "width": 1080, "height": 1920 },
  "carousel": [],
  "carouselCount": null,
  "accessibilityCaption": "Video by Nike on September 22, 2026.",
  "sponsors": [],
  "engagementRate": 0.0113,
  "latestComments": [{ "id": "18195039400344668", "text": "Nike & Caitlin have revealed…", "createdAt": "2026-09-22T14:21:03.000Z", "likeCount": 12, "owner": { "username": "…" } }],
  "transcript": "Caitlyn Clark is just a normal girl from Iowa…",
  "transcriptLanguage": "en",
  "aiTitle": "Normal Life of Iowa's Caitlin Clark",
  "aiSummary": "…",
  "source": { "type": "user", "input": "https://www.instagram.com/nike/" }
}
```

Carousel posts list every slide in `carousel` (`type`, `url`, `videoUrl`, `width`, `height`).

Fields that are always present are `id`, `code`, `url`, `createdAt` and `owner.username`. Fields that can be `null` include:

- `likeCount`, when the creator hid counts
- `video.playCount`, on some feed videos where Instagram doesn't expose plays
- `location`, `audio` and `video`, when they don't apply to the post
- `isPinned` and `isPaidPartnership`, when Instagram doesn't report them for that post

### Pricing

**One flat price: $1.90 per 1,000 results ($0.0019 each).** A result is any saved row: a post, a comment, or a profile, place or keyword row.

- **Add-ons are included at no extra cost:** latest comments on each post, AI summaries and video view counts.
- **Video transcripts** (optional) cost **$0.004 per started minute** of audio, so a typical 30-second reel adds $0.004. Reels set to a licensed song have no speech to transcribe; they're skipped and not charged.
- **You only pay for rows you get.** Queries that find nothing, login-only sources and rows removed by your filters cost nothing.

**Examples:**

- 1,000 posts from any mix of profiles, hashtags and locations: **$1.90**
- 100 profiles in details mode, with bio, category, contacts and related accounts: **$0.19**
- 500 comments: **$0.95**

Free Apify plans are limited to 10 results per run.

### Good to know

- **Hashtags and keywords.** Instagram shows logged-out visitors top posts only for popular terms (e.g. `travel`, `nyc`, `toronto`), typically up to about 60 posts. For terms Instagram keeps behind a login, the run logs that the term isn't public and charges nothing.
- **Locations** return Instagram's top and most recent posts for the place, typically about 70.
- **Profiles** page through the whole public feed, newest first.
- **Private accounts** have no public posts. They are skipped with a note in the log.
- **Comments** come newest first. Replies to comments are only visible to logged-in accounts.
- **Stories, tagged posts, follower lists and profile search** are only visible to logged-in accounts, so they aren't available. The `getStories` and `handles` inputs are accepted for compatibility and skipped at no charge.

### Custom map function

Transform each item before it is saved, e.g. to compute engagement or slim the output:

```javascript
(item) => ({
  ...item,
  engagementRate: item.owner?.followerCount ? +(((item.likeCount || 0) + (item.commentCount || 0)) / item.owner.followerCount * 100).toFixed(3) : null,
  username: item.owner?.username,
  video: undefined,
  carousel: undefined,
})
```

- It must be a single, non-async JavaScript function that returns an object.
- It is for transformation, not filtering. Returning `{}` saves `{ "noResults": true }`.
- Date operations are rejected (`new Date`, `Date.now`). Use `until` to filter by date instead.
- If the function is unusable, the run keeps going and saves your original items. The log shows a warning starting with `Your "customMapFunction" input was rejected:` that says why.

### FAQ

**Do I need an Instagram account or cookies?** No.

**How fresh is the data?** It's live. Every run reads Instagram at that moment.

**Can I schedule it?** Yes. Use Apify schedules together with `until` to collect only new posts each day.

**Can I use it from code or an AI agent?** Yes, through the Apify API, the Python and Node.js clients, webhooks, or MCP.

**Is it legal to scrape Instagram?** This Actor only collects publicly available data: posts, reels and profiles from public Instagram accounts, which anyone can see without logging in. Collecting publicly available data is generally legal, but you're responsible for how you use it. Results can include usernames, profile details, captions and comments from public accounts, and that counts as personal data. You must follow privacy laws such as GDPR, PIPEDA and CCPA, as well as Instagram's terms. If you're unsure, check with a lawyer. More on this: [Is web scraping legal?](https://blog.apify.com/is-web-scraping-legal/)

**Does it access any private data?** No. Everything comes from pages Instagram shows to any visitor without logging in. It never uses a login, never touches private or restricted accounts, and never reaches password-protected areas. Private accounts are never accessed.

# Actor input Schema

## `startUrls` (type: `array`):

Profiles (https://www.instagram.com/nasa/), reels tabs (/nasa/reels/), hashtags (/explore/tags/travel/), locations (/explore/locations/213131048/), audio (/reels/audio/<id>/), keyword search (/explore/search/keyword/?q=toronto), posts and reels (/p/<code>/), and /share/ links. Bare handles (nasa), #hashtags and numeric user IDs work too.

## `keywords` (type: `array`):

Search posts by keyword. Each keyword runs its own search.

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

Posts: posts and reels from each source. Details: one row per profile (bio, followers, category, business type, contacts, related accounts), hashtag/keyword (topic description, related keywords) or location. Comments: the comments of each post found (or of the post URLs you give).

## `maxItems` (type: `integer`):

Maximum number of posts across the whole run. Leave empty for no limit.

## `maxItemsPerQuery` (type: `integer`):

Cap for each individual profile, hashtag, keyword, location or audio. Leave empty for no per-source limit.

## `until` (type: `string`):

A date (YYYY-MM-DD) or a period like "7 days", "2 weeks", "3 months". On profiles, scraping stops as soon as older posts are reached.

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

Leave out posts pinned to the top of a profile (they are often old).

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

Attach up to this many of the newest comments (text, author, likes, date) to each post as latestComments. 0 = none. Included in the price.

## `maxComments` (type: `integer`):

When What to scrape = Comments: how many comments to collect per post.

## `includeTranscript` (type: `boolean`):

Transcribe the speech in every video and reel (any language, up to 15 minutes). Billed per started minute of audio ($0.004/min). Reels set to a licensed song are skipped free.

## `includeAiSummary` (type: `boolean`):

Add Instagram's own AI-written title and summary of each post (aiTitle, aiSummary).

## `includeVideoViews` (type: `boolean`):

Add video.viewCount (Instagram's "views" metric, which differs from plays). Adds one small request per video.

## `includeDetails` (type: `boolean`):

In Posts mode, also save one details row per profile, hashtag/keyword and location. Rows carry dataType "profile" / "keyword" / "place"; posts carry "post".

## `includeRelatedProfiles` (type: `boolean`):

Add up to 50 similar accounts Instagram suggests (relatedProfiles) to each profile row.

## `scrapeRelatedProfiles` (type: `integer`):

For each profile you give, also scrape up to this many of its related accounts (one level deep). Great for finding similar creators or competitors.

## `expandRelatedKeywords` (type: `integer`):

Instagram shows about 60 top posts per hashtag or keyword. Set this to also pull posts from up to N related keywords, for many more results.

## `minFollowers` (type: `integer`):

Only keep posts / profiles whose owner has at least this many followers.

## `maxFollowers` (type: `integer`):

Only keep posts / profiles whose owner has at most this many followers.

## `verifiedOnly` (type: `boolean`):

Only keep posts / profiles from verified accounts.

## `businessOnly` (type: `boolean`):

Profile rows only: keep business and creator accounts.

## `withContactOnly` (type: `boolean`):

Profile rows only: keep profiles that list an email or phone number in their bio.

## `customMapFunction` (type: `string`):

Optional JavaScript function that transforms each post, e.g. (item) => ({ ...item, username: item.owner?.username }). For transformation only, not filtering. If the function is unusable, it is ignored with a warning and original posts are saved.

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

How many requests run in parallel. Higher is faster.

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

Apify datacenter proxy works well and is the default. Blocked IPs are rotated automatically, with a residential fallback.

## `getStories` (type: `boolean`):

Stories are only visible to logged-in Instagram accounts, so they are not available in this scraper. Accepted for input compatibility; no charge.

## `handles` (type: `array`):

Accepted for input compatibility (see Get stories).

## `userIds` (type: `array`):

Numeric Instagram user IDs to scrape as profiles. (Also the stories input, which is not available.)

## Actor input object example

```json
{
  "startUrls": [
    "https://www.instagram.com/nasa/",
    "https://www.instagram.com/explore/tags/travel/"
  ],
  "resultsType": "posts",
  "maxItems": 50,
  "skipPinnedPosts": false,
  "commentsPerPost": 0,
  "maxComments": 50,
  "includeTranscript": false,
  "includeAiSummary": false,
  "includeVideoViews": false,
  "includeDetails": false,
  "includeRelatedProfiles": false,
  "scrapeRelatedProfiles": 0,
  "expandRelatedKeywords": 0,
  "verifiedOnly": false,
  "businessOnly": false,
  "withContactOnly": false,
  "maxConcurrency": 20,
  "proxyConfiguration": {
    "useApifyProxy": true
  },
  "getStories": false
}
```

# Actor output Schema

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

All scraped posts and reels.

## `run` (type: `string`):

Status and statistics for this run.

# 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 = {
    "startUrls": [
        "https://www.instagram.com/nasa/",
        "https://www.instagram.com/explore/tags/travel/"
    ],
    "maxItems": 50,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("yugenox/instagram-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 = {
    "startUrls": [
        "https://www.instagram.com/nasa/",
        "https://www.instagram.com/explore/tags/travel/",
    ],
    "maxItems": 50,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("yugenox/instagram-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 '{
  "startUrls": [
    "https://www.instagram.com/nasa/",
    "https://www.instagram.com/explore/tags/travel/"
  ],
  "maxItems": 50,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call yugenox/instagram-scraper --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,yugenox/instagram-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/JWobb5RZ2tA5WckR1/builds/jm4ykCNo8BC8ihnEO/openapi.json
