# Instagram Hashtag Scraper | $0.24/1K on Starter (`publicsignallabs/instagram-hashtag-scraper`) Actor

Extract recent public Instagram hashtag posts and reels for about $0.24 per 1,000 items on Starter. Choose posts, reels, or both. Supports Console, CLI, API, and integrations; no login, cookies, browser, or proxy setup.

- **URL**: https://apify.com/publicsignallabs/instagram-hashtag-scraper.md
- **Developed by:** [Public Signal Labs](https://apify.com/publicsignallabs) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 11 total users, 8 monthly users, 91.8% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.22 / 1,000 hashtag media items

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?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
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.
Actors are written with capital "A".

## 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.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

## Instagram Hashtag Scraper | $0.24/1K on Starter

Turn Instagram hashtags into structured posts and reels for content research, trend discovery, campaign tracking, and social media intelligence. Paid runs support up to 10,000 items per hashtag at about $0.24 per 1,000 items on Starter. Choose posts, reels, or both—no authentication or proxy setup.

### What this Actor does

- Accepts one or more actual Instagram hashtags
- Collects recent images, feed videos, and carousels, recent reels, or both
- Returns up to 10,000 media rows per hashtag in each paid run
- Supports resumable single-hashtag paid exports with exact mid-page checkpoints
- Works without Instagram credentials, cookies, session IDs, browsers, or proxy configuration
- Separates media rows, run status, continuation metadata, and aggregate reconciliation metrics

Use it for public content discovery, campaign monitoring, creator research, trend analysis, and repeatable data pipelines where an actual hashtag is the source boundary.

### Quick start

1. Enter one or more hashtags. A single leading `#` is optional.
2. Choose posts, reels, or both, then set the maximum results for each hashtag.
3. Run the Actor, then preview or export the default dataset as JSON, CSV, or Excel.

```json
{
  "hashtags": ["artificialintelligence"],
  "resultsLimit": 200,
  "getPosts": true,
  "getReels": true
}
```

### Input

| Field | Rules |
| --- | --- |
| `hashtags` | Required list of actual hashtags. A single leading `#` is optional. Letters, numbers, and underscores are accepted after Unicode normalization. URLs, spaces, and other punctuation are rejected. The schema accepts up to 50 unique hashtags; plan-specific limits are detailed in Pricing. |
| `resultsLimit` | Required integer per hashtag from 25 through 10,000. Default and Store prefill: 200. Plan-specific effective limits are detailed in Pricing. |
| `getPosts` | Boolean, default `true`. Include recent feed images, carousels, and feed videos. |
| `getReels` | Boolean, default `true`. Include recent reels. At least one media toggle must be `true`. |
| `continuationToken` | Optional short-lived secret returned by a previous paid run. Requires the same single hashtag and the same `getPosts`/`getReels` selection. It expires after 15 minutes. Every continuation run incurs a new source event. |

This Actor searches actual hashtags only. It does not accept arbitrary keywords, profile URLs, direct post URLs, or date filters.

### Dataset rows

Every charged dataset item has exactly this shape:

```json
{
  "hashtag_scrape": "artificialintelligence",
  "id": "1234567890123456789",
  "short_code": "ExampleCode",
  "url": "https://www.instagram.com/p/ExampleCode/",
  "caption": "Example public caption",
  "timestamp": "2026-08-25T10:00:00Z",
  "media_type": "image",
  "product_type": "feed",
  "like_count": 125,
  "comment_count": 4,
  "play_count": null,
  "view_count": null,
  "child_media_count": 0,
  "display_url": "https://...",
  "video_url": null,
  "owner_id": "9876543210987654321",
  "owner_username": "example_creator",
  "owner_full_name": "Example Creator",
  "owner_is_verified": false,
  "owner_profile_pic_url": "https://..."
}
```

| Field | Meaning |
| --- | --- |
| `hashtag_scrape` | Normalized source hashtag without `#` |
| `id` | Stable Instagram media ID represented as a string |
| `short_code` | Instagram post or reel shortcode |
| `url` | Public Instagram post or reel URL constructed from the shortcode |
| `caption` | Public caption text; empty string when absent |
| `timestamp` | UTC ISO-8601 publication timestamp |
| `media_type` | Normalized `image`, `video`, or `carousel` |
| `product_type` | Normalized Instagram product type, such as `feed`, `clips`, `igtv`, or `carousel_container` |
| `like_count` | Public like count; `null` when hidden or unavailable; zero remains zero |
| `comment_count` | Public comment count; `null` when unavailable |
| `play_count` | Public play count when available |
| `view_count` | Public view count when available |
| `child_media_count` | Number of carousel children; zero for non-carousels |
| `display_url` | Selected external image or thumbnail URL; it may expire |
| `video_url` | Selected external video URL when available; it may expire |
| `owner_id` | Public owner ID represented as a string; empty when unavailable |
| `owner_username` | Current public owner username; empty when unavailable |
| `owner_full_name` | Public owner display name; empty when unavailable |
| `owner_is_verified` | Whether the owner is verified |
| `owner_profile_pic_url` | External owner image URL when available; it may expire |

The same media can legitimately appear once for each requested hashtag because `hashtag_scrape` records customer-visible provenance. Duplicate media IDs are removed within each hashtag during a run.

### Pricing

Billing uses two transparent events:

1. one **hashtag source** event for each hashtag successfully validated and processed in a run, including a valid hashtag with no current results;
2. one **hashtag media item** event for each persisted dataset row.

The source event is `$0.0015` per individual hashtag. Apify displays this normalized as `$1.50 / 1,000` source events; it does **not** mean one hashtag costs $1.50. It covers starting and validating that hashtag extraction independently of how many rows are available. Selecting posts, reels, or both does not change the source-event price.

Validation failures and missing or rejected hashtags do not incur a source or row event. If the run reaches its spending limit, it stops before storing an uncharged row.

| Plan | Source event | Dataset item | One hashtag / 1,000 rows |
| --- | ---: | ---: | ---: |
| Free | $0.0015 | $0.00024 | $0.2415 |
| Starter | $0.0015 | $0.00024 | $0.2415 |
| Scale | $0.0015 | $0.00023 | $0.2315 |
| Business | $0.0015 | $0.00022 | $0.2215 |

Starter examples: one hashtag returning 25 rows costs $0.0075; 60 rows costs $0.0159; 100 rows costs $0.0255; 1,000 rows costs $0.2415. Multiple hashtags are priced independently. Every continuation run incurs another source event because it is a new source/run operation.

#### FREE demo limits

FREE Apify accounts can run this Actor up to 5 times per UTC calendar month. Each admitted FREE run accepts exactly one hashtag, returns up to 10 posts or reels, and cannot submit or receive a continuation token. Console, CLI, API, schedules, webhooks, MCP, and other Apify launch methods share the same account allowance. A run counts once admitted even when it is later aborted or unsuccessful, and resurrecting it does not start another extraction. Creating another task or API token does not reset the allowance. Paid Apify users are not subject to these demo limits.

### Run summary

Run status, source charges, row counts, failures, continuation tokens, and non-sensitive FREE admission metadata are stored in the default key-value store's `OUTPUT` record rather than mixed into the dataset:

Allowance exhaustion and replay complete the Apify run successfully, while `OUTPUT.status` remains `FAILED`; the stable `stopReason`/`freeTier.outcome` remains machine-readable, and identity/quota verification errors still fail the platform run.

```json
{
  "status": "SUCCEEDED",
  "stopReason": null,
  "isPaying": true,
  "requestedHashtags": 1,
  "resultsLimitPerHashtag": 200,
  "getPosts": true,
  "getReels": true,
  "deliveredCount": 200,
  "chargedCount": 200,
  "sourceChargedCount": 1,
  "sources": [
    {
      "inputIndex": 0,
      "hashtag": "artificialintelligence",
      "status": "succeeded",
      "deliveredCount": 200,
      "chargedCount": 200,
      "sourceCharged": true
    }
  ],
  "continuations": [
    {
      "inputIndex": 0,
      "hashtag": "artificialintelligence",
      "hasNextPage": true,
      "nextContinuationToken": "<secret token>"
    }
  ]
}
```

`status` can be `SUCCEEDED`, `PARTIAL`, `FAILED`, or `CHARGE_LIMIT_REACHED`. Inspect each source entry even when the overall run completes. Aggregate non-PII request, retry, page, duplicate, source-charge, row-charge, storage-stop, and timing metrics are stored separately in `AUDIT`.

Admitted FREE runs include a `freeTier` object with the UTC month, claimed slot, remaining allowance, effective result limit, and policy version. Rejected FREE runs use stable reasons such as `free_monthly_limit`, `free_run_already_consumed`, or `free_quota_unavailable`. The record never contains an Apify user ID, API token, or internal quota-storage identifier.

### Resumable paid exports

When `hasNextPage` is true, paying users can read `nextContinuationToken` from `OUTPUT.continuations` and start another run with the same single hashtag and media-toggle selection. Tokens expire after 15 minutes and are authenticated, product-specific, hashtag-bound, and selection-bound.

```json
{
  "hashtags": ["artificialintelligence"],
  "resultsLimit": 1000,
  "getPosts": true,
  "getReels": true,
  "continuationToken": "<token from OUTPUT>"
}
```

Always use the newest token. A continuation can read the current page again when the previous run stopped partway through it; rows before the authenticated checkpoint are skipped. A resumed run charges one new source event and charges only newly persisted rows.

### Limitations

This Actor:

- Returns recent media ordering exposed for each hashtag, not a complete historical archive
- Does not offer arbitrary keyword search, profiles, direct post lookups, date filtering, comments, transcripts, analytics, or media downloads
- Does not bypass private-account or restricted-content access controls
- Cannot guarantee stable ordering, permanent CDN URLs, or that counts hidden by Instagram will be available
- May return fewer rows when a hashtag has little current media, a source becomes unavailable, or a run reaches its spending limit
- Can return public media that later changes or is removed at its source

### API and CLI use

Call the Actor through the standard Apify Actor Runs API. Read media from the run's default dataset and reconciliation metadata from the `OUTPUT` and `AUDIT` key-value-store records.

With the current Apify CLI:

```bash
apify actors call publicsignallabs/instagram-hashtag-scraper \
  --input '{"hashtags":["artificialintelligence"],"resultsLimit":200}' \
  --output-dataset
```

The same Actor can be called with Apify's JavaScript or Python clients, REST API, schedules, webhooks, MCP, and platform integrations. Plan-specific demo limits are detailed in Pricing.

### Responsible use

Collect and use public data only where you have a lawful purpose. Respect privacy, platform rules, and applicable data-protection law. Minimize retained personal data, secure exports, and delete records when they are no longer needed.

This Actor is unofficial and is not affiliated with or endorsed by Instagram or Meta.

### FAQ

#### Does it require an Instagram account?

No. The Actor does not require Instagram login credentials, cookies, or a session ID.

#### Are arbitrary keywords supported?

No. Submit actual hashtags only. Values with spaces, URLs, or punctuation other than underscore are rejected.

#### Are reels included?

Yes. The Actor processes the hashtag's recent post and reel surfaces, normalizes videos as `media_type: "video"`, and uses `product_type: "clips"` for reels when returned.

#### Can one run process multiple hashtags?

The schema accepts up to 50 unique hashtags. Plan-specific FREE demo limits are detailed in Pricing. Continuation runs require one hashtag because a token is bound to that source.

#### How do I export the results?

Open the run's default dataset in Apify Console and choose JSON, CSV, Excel, XML, or another supported format. Programmatic workflows can read the same dataset through the API.

### Support

Use the **Issues** tab on this Actor's Apify Store page. Include the run ID, expected result, and observed result. Never include continuation tokens, API tokens, cookies, or other credentials.

# Actor input Schema

## `hashtags` (type: `array`):

Actual hashtags only. A single leading # is optional. Letters, numbers, and underscores are accepted; URLs, spaces, and other punctuation are rejected. The schema accepts up to 50 unique values; plan-specific limits are detailed in Store Pricing.

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

Recent media returned for each hashtag in this run. Schema range: 25–10,000; plan-specific effective limits are detailed in Store Pricing.

## `getPosts` (type: `boolean`):

Include recent feed posts: images, carousels, and feed videos.

## `getReels` (type: `boolean`):

Include recent reels. At least one of Get posts or Get reels must be enabled.

## `continuationToken` (type: `string`):

Optional short-lived token from an earlier paid run. Use it with the same single hashtag and the same Get posts/Get reels selection. Every resumed run incurs a new source event.

## Actor input object example

```json
{
  "hashtags": [
    "artificialintelligence"
  ],
  "resultsLimit": 200,
  "getPosts": true,
  "getReels": true
}
```

# Actor output Schema

## `posts` (type: `string`):

Charged media rows from the default dataset, ready for preview or export.

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

Run status, FREE policy outcome, delivered and charged counts, source-event outcomes, and continuation tokens.

## `audit` (type: `string`):

Aggregate request, retry, source-charge, row-charge, duplicate, and timing metrics.

# 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 = {
    "hashtags": [
        "artificialintelligence"
    ],
    "resultsLimit": 200,
    "getPosts": true,
    "getReels": true
};

// Run the Actor and wait for it to finish
const run = await client.actor("publicsignallabs/instagram-hashtag-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 = {
    "hashtags": ["artificialintelligence"],
    "resultsLimit": 200,
    "getPosts": True,
    "getReels": True,
}

# Run the Actor and wait for it to finish
run = client.actor("publicsignallabs/instagram-hashtag-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 '{
  "hashtags": [
    "artificialintelligence"
  ],
  "resultsLimit": 200,
  "getPosts": true,
  "getReels": true
}' |
apify call publicsignallabs/instagram-hashtag-scraper --silent --output-dataset

```

## MCP server setup

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