# Instagram Scraper (`kaix/instagram-scraper`) Actor

Collect public Instagram profiles, posts, reels, hashtags, places, search results, and tagged posts through anonymous web requests.

- **URL**: https://apify.com/kaix/instagram-scraper.md
- **Developed by:** [Kai](https://apify.com/kaix) (community)
- **Stats:** 1 total users, 0 monthly users, 25.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.80 / 1,000 contents

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
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

Collect public Instagram profiles, posts, reels, and places as structured data. Search for profiles, hashtags, and places, read available posts, or fetch a known post. Each result is one item in the default dataset.

You do not need an Instagram account or login cookies. Collection uses public Instagram data. Instagram can still block a request, even for public content.

Profile posts and tagged posts can continue across pages when Instagram permits access. Profile reels, place posts, and hashtag posts use one public page. Hashtag results include only posts whose full caption contains the exact hashtag. These results are a limited sample, not a complete hashtag feed.

### Use cases

- Creator research: compare public profile details and available engagement counts.
- Brand monitoring: collect posts from known public accounts.
- Content research: collect captions, hashtags, images, reels, and carousel media.
- Location research: collect details and posts from known places.
- Reporting: export results for analysis in a spreadsheet or another application.

### Data you can collect

- Profiles: username, name, biography, links, profile image, follower and post counts, account flags, and available related profiles.
- Posts and reels: caption, author, posting time, available like, comment, view, and play counts, media links, dimensions, and video duration.
- Carousels: images and videos in their original order, inside one post item.
- Post context: hashtags, text mentions, tagged users, co-authors, location, music details, and comment previews when Instagram supplies them.
- Places: name, coordinates, address, city, country, website, category, and available post count.
- Hashtags: name, post count, and available profile image.

A field can be missing or `null` when Instagram does not supply it. Full comment threads, replies, Stories, audio lookup, and private account data are not supported.

### Choose how to collect

Set one `mode` and put its targets in the `targets` list.

| What you want | Set `mode` to | Put in `targets` |
|---|---|---|
| Profile details | `profile` | Usernames or profile URLs |
| One or more known posts or reels | `post` | Post/reel URLs, shortcodes, or numeric media IDs |
| Posts from a profile | `posts` | Usernames or profile URLs |
| Reels from a profile | `reels` | Usernames or profile/reels URLs |
| Available posts with an exact hashtag | `hashtag` | Hashtags or hashtag URLs |
| Hashtag details | `hashtagDetails` | Hashtags or hashtag URLs |
| Place details | `place` | Place IDs or place URLs |
| Posts shown on a place page | `placePosts` | Place IDs or place URLs |
| Profiles, hashtags, or places that match a phrase | `search` | Search phrases; select `searchType` and `searchResults` |
| Posts that tag an account | `mentions` | Usernames or profile URLs |

`mentions` mode collects posts that tag the account. It does not search for text mentions in captions. Place pages can include posts from the surrounding area; each post keeps its own location when available.

Use `@123` for a username that contains only digits. Numeric profile IDs are not supported. In `post` mode, a target that contains only digits is treated as a media ID.

### Start a run

1. Open the Actor's **Input** tab in Apify Console.
2. Select a mode and enter its targets, or use one of the JSON examples below.
3. Set the maximum results and check the proxy settings.
4. Select **Start**.
5. Open **Output** to view the results. Select **Export** to download them.

For Console instructions, see Apify's [run guide](https://docs.apify.com/actors/running).

#### Read profile details

```json
{
  "mode": "profile",
  "targets": ["instagram", "nasa"],
  "maxItems": 2
}
```

#### Collect recent posts

Collect up to 10 posts from the profile's public page. Keep posts from the last seven days and omit posts marked as pinned.

```json
{
  "mode": "posts",
  "targets": ["instagram"],
  "maxItems": 10,
  "onlyNewerThan": "7 days",
  "skipPinnedPosts": true,
  "addParentData": true
}
```

#### Collect reels and save media files

```json
{
  "mode": "reels",
  "targets": ["instagram"],
  "maxItems": 10,
  "downloadMedia": true
}
```

#### Fetch a known post

Replace the URL with the post or reel you need.

```json
{
  "mode": "post",
  "targets": ["https://www.instagram.com/p/DZxvMgyH8yR/"],
  "maxItems": 1
}
```

#### Read place details

```json
{
  "mode": "place",
  "targets": ["213385402"],
  "maxItems": 1
}
```

#### Search for a public profile

Search by a phrase, then collect details for the first matching public profile.

```json
{
  "mode": "search",
  "targets": ["national geographic"],
  "searchType": "profile",
  "searchResults": "details",
  "searchLimit": 1,
  "maxItems": 1
}
```

Use `searchType: "place"` to find places or `searchType: "hashtag"` to find hashtags. Set `searchResults` to `posts` or `reels` to collect available media from the matches. Profile search also accepts `mentions` for tagged posts. Search reads one batch of available matches; it does not return every match. A phrase can have no matches. A public page can have no posts that meet your filters.

### Input

Both `mode` and `targets` are required. Invalid targets or incompatible options stop the run before collection.

| Field | Type | Default | Behaviour |
|---|---|---|---|
| `mode` | string | Required | One mode from the selection table. |
| `targets` | string\[] | Required | 1–100 targets of the same type. Duplicate targets are removed. |
| `maxItems` | integer | `100` | Maximum saved items across the run. Range: 1–10,000. |
| `maxItemsPerTarget` | integer | `100` | Maximum saved items for each input target. Range: 1–1,000. A search query is one target. |
| `maxRequests` | integer | `500` | Maximum request attempts. Range: 1–10,000. Includes connection setup, retries, detail checks, and downloads. |
| `onlyNewerThan` | string | None | Keep posts after a UTC date, timestamp, or relative time such as `7 days`. |
| `skipPinnedPosts` | boolean | `false` | Omit posts marked as pinned. |
| `onlyReels` | boolean | `false` | Keep only posts identified as reels. |
| `addParentData` | boolean | `false` | Add the source profile, hashtag, or place identity to post results. |
| `addProfileStatistics` | boolean | `false` | Add statistics from a sample of posts. Profile detail output only. |
| `statisticsLimit` | integer | `12` | Maximum posts in the statistics sample. Range: 1–100. |
| `searchType` | string | `hashtag` | `profile`, `hashtag`, or `place`. `user` is an alias for `profile`. Search mode only. |
| `searchResults` | string | `details` | `details`, `posts`, or `reels`. Profile search also accepts `mentions`. |
| `searchLimit` | integer | `10` | Maximum matches to process for each search query. Range: 1–250. |
| `downloadMedia` | boolean | `false` | Save available post, reel, and carousel media files. |
| `maxMediaBytes` | integer | `26214400` | Maximum bytes per media file. Default: 25 MiB. Range: 1–104,857,600 bytes. |
| `proxyConfiguration` | object | `{"useApifyProxy":true,"apifyProxyGroups":["RESIDENTIAL"]}` | Use Apify Proxy, supply HTTP/HTTPS proxy URLs, or set `useApifyProxy` to `false`. |

#### Filters and statistics

Dates, pinned-post exclusion, reel filters, and downloads apply to post output. They cannot be used with profile, hashtag, or place detail output. Posts with missing dates are excluded when a date filter is set. Relative dates use the start time of the original run, including after a restart. A month means 30 days; a year means 365 days.

Profile statistics use the first available posts, up to `statisticsLimit`. The result includes `sampleSize`, `averageLikes`, `averageComments`, and `engagementRate`. Engagement rate is `(average likes + average comments) / followers × 100`. Missing counts produce `null` values. These statistics describe the sample; they do not measure reach or impressions.

#### Proxies and costs

Apify Residential Proxy is enabled by default. Direct cloud requests and the default data-center proxy were redirected to login in the latest checks. A proxy does not guarantee access to Instagram. If you supply several custom proxy URLs, the Actor uses the first one.

A result can require several requests. Use `maxItems` to limit saved results and `maxRequests` to limit collection work. Proxy traffic, media transfer, and file storage can add costs.

### Output

The default dataset contains one item per profile, post, hashtag, or place. The `recordType` field identifies its type. Reels and carousels use `recordType: "post"`.

View the dataset in Apify Console or export it as JSON, CSV, Excel, XML, or HTML. JSON keeps nested objects and arrays, such as carousel media and comment previews. See Apify's [dataset guide](https://docs.apify.com/storage/dataset) for export options.

#### Output at a glance

| Group | Main fields |
|---|---|
| Every item | `recordType`, `schemaVersion`, `id`, `inputUrl`, `url`, `scrapedAt` |
| Profile identity and links | `username`, `fullName`, `biography`, `externalUrl`, `bioLinks`, `profilePicUrl` |
| Profile counts and flags | `followersCount`, `followingCount`, `postsCount`, `isPrivate`, `isVerified`, `isBusinessAccount`, `categoryName` |
| Optional profile data | `relatedProfiles`, `statistics` |
| Post content and author | `shortCode`, `caption`, `timestamp`, `author`, `hashtags`, `mentions`, `taggedUsers`, `coauthors` |
| Post counts | `likesCount`, `commentsCount`, `viewCount`, `playCount`, `shareCount`, `reshareCount` |
| Post media | `mediaType`, `productType`, `displayUrl`, `videoUrl`, `dimensions`, `videoDuration`, `childPosts` |
| Available post context | `location`, `musicInfo`, `firstComment`, `latestComments`, `isPinned`, `isSponsored`, `isCommentsDisabled`, `accessibilityCaption` |
| Hashtag details | `name`, `postsCount`, `profilePicUrl`, `relatedTags`, `postsPerDay` |
| Place details | `name`, `latitude`, `longitude`, `address`, `city`, `country`, `website`, `category`, `postsCount` |
| Added source and files | `parentData`, `downloads` |

IDs are strings. Dates use UTC ISO 8601. `scrapedAt` is the collection time; a post's `timestamp` is its posting time. Unavailable counts are `null`. If the full post page omits a count, the Actor keeps an available count from the public feed. A known zero stays `0`. Views and plays are separate counts.

This example uses fictional values to show a post item. It is not a live result.

```json
{
  "schemaVersion": 1,
  "recordType": "post",
  "id": "1",
  "inputUrl": "https://www.instagram.com/example_creator/",
  "url": "https://www.instagram.com/p/B/",
  "scrapedAt": "2026-09-24T10:00:00.000Z",
  "shortCode": "B",
  "mediaType": "image",
  "productType": "feed",
  "timestamp": "2026-09-23T09:00:00.000Z",
  "caption": "A sample photo #travel",
  "likesCount": 42,
  "commentsCount": 3,
  "viewCount": null,
  "playCount": null,
  "author": {
    "id": "10",
    "username": "example_creator",
    "fullName": "Example Creator",
    "profilePicUrl": null,
    "isVerified": false,
    "isPrivate": false
  },
  "displayUrl": "https://example.com/photo.jpg",
  "videoUrl": null,
  "dimensions": { "width": 1080, "height": 1080 },
  "videoDuration": null,
  "childPosts": [],
  "hashtags": ["travel"],
  "mentions": [],
  "downloads": []
}
```

#### Carousels, previews, and media files

A carousel counts as one result. Its ordered `childPosts` array contains each image or video, its URL, dimensions, and available duration. Available comment previews stay inside the post's `latestComments` array. These previews are not complete comment threads.

With `downloadMedia: true`, available media files are saved in the run's key-value store. Each `downloads` entry contains the media ID, file type, source URL, storage key, and download URL. Videos can also include a poster image. Files above `maxMediaBytes` are rejected. Source media URLs can expire, so save files you need to keep.

### Collection behaviour

#### Limits and duplicate results

For profile posts, the Actor requests more pages until it reaches a selected limit or the end of the available feed. Instagram can refuse a later page. If the first feed request fails, the Actor can use posts from the public profile page when that page contains valid data. This fallback is limited to one page.

Reel feeds and place feeds also use one public page. Profile and reel pages currently supply up to 12 posts; place pages can supply a different count. When this page contains only part of the feed, saved results are partial. Increasing the result limit does not remove that page limit. Filters and duplicate removal can reduce the number of saved results.

Each record type and ID is saved once across all input targets. If the same post appears under two targets, it keeps the first target's `inputUrl`. It does not count again under the second target. `maxItems` and `maxItemsPerTarget` count saved items after filtering.

#### Access and unsupported features

Only public profiles and media are collected. If the Actor cannot confirm that an account is public, it does not save its profile or posts.

The Actor does not accept account cookies or offer login. It does not collect full comment threads, replies, Stories, standalone audio details, or profiles by numeric ID. Music fields and comment previews can still appear when Instagram supplies them with a post.

#### Missing or partial results

Saved results remain available when a later request fails. Open **Run summary**, the `OUTPUT` record in the run's key-value store, to see the saved count and the reason collection stopped for each target.

Check that the target exists and is public. Check your date filters and result, request, and budget limits. A valid target can return no results. If Instagram temporarily refuses access, try a smaller run later. A retry does not guarantee access.

#### Restart an interrupted run

Use the same input and storage to resume an interrupted run. Previously saved items are kept and are not saved again. Relative dates use the original start time. Request counts continue from the saved total.

Restarting does not retry targets already marked complete, partial, or failed. Start a new run to retry those targets or change the input.

# Actor input Schema

## `mode` (type: `string`):

Choose the data to collect. Hashtag posts are a limited sample with an exact caption match. Profile reels and place posts use one public page.

## `targets` (type: `array`):

Use usernames or profile URLs; post shortcodes, media IDs or URLs; exact hashtags; place IDs or URLs; or search phrases. Numeric profile IDs are not supported. Use @123 for a numeric username.

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

Keyword search mode only. Choose the type of matches.

## `searchResults` (type: `string`):

Return matched details, posts, or reels. Tagged posts require profile search.

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

Maximum source matches to resolve for each query. Instagram can return fewer matches.

## `onlyNewerThan` (type: `string`):

Optional UTC date (2026-09-01), ISO timestamp, or duration such as 7 days. Applies to posts. Missing timestamps are excluded. Relative dates use the first run start time.

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

Omit posts marked as pinned. Continue through all available pages.

## `addParentData` (type: `boolean`):

Add the source profile, hashtag, or place identity to each result.

## `addProfileStatistics` (type: `boolean`):

Compute average likes, comments, and engagement rate from a bounded profile post sample. Profile detail output only.

## `statisticsLimit` (type: `integer`):

Maximum profile posts in the statistics sample. Missing counts produce null averages.

## `downloadMedia` (type: `boolean`):

Save post, reel, and carousel media to the key-value store. Add download links to the result. Data transfer and storage can have a cost.

## `maxMediaBytes` (type: `integer`):

Reject a media file above this size. The default is 25 MiB.

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

Maximum rows to save in the full run. A carousel counts as one row.

## `maxItemsPerTarget` (type: `integer`):

Maximum rows to save for each target.

## `maxRequests` (type: `integer`):

Maximum HTTP attempts across the full run and its restarts. Includes anonymous session setup, retries, detail and privacy checks, and media downloads.

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

Use Apify Residential Proxy by default, supply HTTP or HTTPS proxy URLs, or disable the proxy. Proxy use can have a cost. The Actor keeps one proxy session for the run.

## `onlyReels` (type: `boolean`):

Keep only media identified as reels. Use with hashtag or place posts, profile feeds, or direct posts.

## Actor input object example

```json
{
  "mode": "profile",
  "targets": [
    "https://www.instagram.com/instagram/"
  ],
  "searchType": "hashtag",
  "searchResults": "details",
  "searchLimit": 10,
  "skipPinnedPosts": false,
  "addParentData": false,
  "addProfileStatistics": false,
  "statisticsLimit": 12,
  "downloadMedia": false,
  "maxMediaBytes": 26214400,
  "maxItems": 100,
  "maxItemsPerTarget": 100,
  "maxRequests": 500,
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  },
  "onlyReels": false
}
```

# Actor output Schema

## `items` (type: `string`):

Profile, post, hashtag, or place rows for the selected mode. Carousel media stay in the parent post row. Missing or hidden metrics are null.

## `summary` (type: `string`):

The OUTPUT record contains per-target results and explains limits or failures.

# 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 = {
    "mode": "profile",
    "targets": [
        "https://www.instagram.com/instagram/"
    ],
    "proxyConfiguration": {
        "useApifyProxy": true,
        "apifyProxyGroups": [
            "RESIDENTIAL"
        ]
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("kaix/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 = {
    "mode": "profile",
    "targets": ["https://www.instagram.com/instagram/"],
    "proxyConfiguration": {
        "useApifyProxy": True,
        "apifyProxyGroups": ["RESIDENTIAL"],
    },
}

# Run the Actor and wait for it to finish
run = client.actor("kaix/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 '{
  "mode": "profile",
  "targets": [
    "https://www.instagram.com/instagram/"
  ],
  "proxyConfiguration": {
    "useApifyProxy": true,
    "apifyProxyGroups": [
      "RESIDENTIAL"
    ]
  }
}' |
apify call kaix/instagram-scraper --silent --output-dataset

```

## MCP server setup

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