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

Extract public Instagram posts and Reels for any hashtag, relevance-ranked as the Instagram app shows them, for about $0.24 per 1,000 items on Starter. 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
- **Features:** Limited permissions
- **Stats:** 89 total users, 26 monthly users, 100.0% 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?

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 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. Results are relevance-ranked, as the Instagram app shows them. Paid runs support up to 10,000 items per hashtag, subject to availability, at about $0.24 per 1,000 items on Starter. No authentication or proxy setup.

### What this Actor does

- Accepts one or more actual Instagram hashtags
- Collects public posts and Reels for each hashtag, relevance-ranked as the Instagram app shows them
- Returns up to 10,000 media rows per hashtag in each paid run, subject to availability
- Labels every row with `media_type` and `product_type`, so you can separate posts and Reels after export
- Supports resumable single-hashtag paid exports
- 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. 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
}
```

### 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. Each hashtag returns up to this many posts and Reels, subject to availability. Plan-specific effective limits are detailed in Pricing. |
| `continuationToken` | Optional short-lived secret returned by a previous paid run. Requires the same single hashtag. 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

Illustrative dataset item; optional facts appear only when observed:

```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,
  "display_url": "https://...",
  "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; explicit `null` when hidden, omitted when unobserved; zero remains zero |
| `comment_count` | Public comment count when observed |
| `play_count` | Public play count when available |
| `view_count` | Public view count when available |
| `child_media_count` | Number of children when a child list was observed |
| `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 when observed |
| `owner_username` | Current public owner username when observed |
| `owner_full_name` | Public owner display name when observed |
| `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.

Unknown facts are not synthesized as false, zero, or empty lists. Observed empty values remain explicit. Hidden like/view counts have explicit flags. Supplied locations, rich owner/coauthor profiles, user tags, full carousel children, accessibility captions, and audio metadata are retained alongside the fields above.

### 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.

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:

`OUTPUT` uses `schemaVersion: 2`: `status` is `SUCCEEDED` for completed work and graceful stops, or `FAILED` for internal faults (`RUNNING` denotes a checkpoint). Check `outcome` (`COMPLETED`, `NO_RESULTS`, `PARTIAL`, `INPUT_REJECTED`, `POLICY_REJECTED`, `UPSTREAM_UNAVAILABLE`, `DEPENDENCY_UNAVAILABLE`, `LIMIT_REACHED`, `INTERNAL_ERROR`) and `message`/`issues`; platform success does not guarantee data. Runtime input/policy rejections and external outages finish normally; confirmed rows remain available. Ambiguous writes or charges use `reconciliation: "unknown"`. External reporting outages can leave summaries unavailable; platform-enforced aborts and resource failures remain outside this guarantee.

```json
{
  "schemaVersion": 2,
  "outcome": "COMPLETED",
  "status": "SUCCEEDED",
  "stopReason": null,
  "isPaying": true,
  "requestedHashtags": 1,
  "resultsLimitPerHashtag": 200,
  "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>"
    }
  ]
}
```

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. Tokens expire after 15 minutes and are authenticated, product-specific, and hashtag-bound.

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

Always use the newest token. When the previous run stopped partway through a page, the continuation reads that page again, and Instagram may rank different media there. Media already delivered in the same token chain are skipped and never charged twice. A resumed run charges one new source event and charges only newly persisted rows.

### Limitations

This Actor:

- Returns media in Instagram's relevance order, as the Instagram app shows them, not as a chronological feed or a complete historical archive; results can include media that are months or years old
- Returns posts and Reels together; most hashtags return mostly Reels
- Returns up to 10,000 media rows per hashtag in each paid run, subject to availability
- 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, the same media across repeated runs, permanent CDN URLs, or that counts hidden by Instagram will be available
- May return fewer rows when Instagram shows few media for a hashtag, 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. Posts and Reels come together in one dataset, in Instagram's relevance order. Reels have `product_type: "clips"` and `media_type: "video"`, so you can filter them after export.

#### 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`):

Posts and Reels returned for each hashtag, up to 10,000, subject to availability. Plan-specific effective limits are detailed in Store Pricing.

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

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

## Actor input object example

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

# 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
};

// 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,
}

# 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
}' |
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/GUmSQfEE2oHf7YmKu/openapi.json
