# Instagram Hashtag Scraper (`apidojo/instagram-hashtag-scraper`) Actor

Best posts & reels hashtag scraper! $0.016 / hashtag gets you 60 items FREE, then $0.0004 / additional item. No authentication, no proxy needed. Perfect for content research and social media intelligence! ⚡

- **URL**: https://apify.com/apidojo/instagram-hashtag-scraper.md
- **Developed by:** [API Dojo](https://apify.com/apidojo) (community)
- **Categories:** Social media, Developer tools, Automation
- **Features:** Limited permissions
- **Stats:** 4,590 total users, 513 monthly users, 100.0% runs succeeded, 55 bookmarks
- **User rating**: 3.39 out of 5 stars

## Pricing

from $0.39 / 1,000 dataset 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: Your Ultimate Hashtag Research Tool

Introducing the Instagram Hashtag Scraper, the premier tool for extracting posts and reels from Instagram hashtags. This high-performance scraper excels at rapidly collecting hashtag-based content from [Instagram.com](https://instagram.com), making it perfect for social media managers, content creators, and marketers seeking hashtag insights. With blazing-fast performance and cost-effective event-based pricing starting at just **$0.016 per hashtag** (first 60 posts included!), this tool delivers exceptional value for comprehensive hashtag analysis.

### ℹ️ Disclaimer

We are professionals specializing in data extraction. This actor is exceptionally fine-tuned for scraping [Instagram](https://instagram.com), providing you with a comprehensive suite of tools. Moreover, we provide top-tier maintenance and exceptional support. Pure data - at your fingertips. You name it, we get it.

### 🐉 Features and Functionality

- No Authentication, no cookies. Just pure data. 🛡️
- **Event-based pricing**: Only pay for what you scrape. 💰
- **First 60 posts included**: Each hashtag query includes 60 posts for free! 🎁
- **Hashtag-focused**: Scrape posts and reels by hashtag or keyword. 📱
- **Flexible filtering**: Choose between posts, reels, or both. 🎯
- No extra costs, no proxy needed. 🐉
- Simple Output, super fast. 💨
- Plug and play for AI tools like Flowise, Langchain, etc. 🧠

### 💰 Pricing Model

Our transparent event-based pricing ensures you only pay for what you use:

#### Event Costs

- **Keyword Query**: $0.016 per hashtag/keyword search
  - First 60 posts/reels (2 pages) are included in this price
  - Covers each hashtag or keyword search you perform
- **Dataset Items**: $0.0004 per additional post/reel
  - Only charged for items beyond the first 60 included posts

#### Cost Examples

- **60 posts from a hashtag**: $0.016 (1 query, no additional charges!)
- **1,000 posts from a hashtag**: $0.39 (1 query + 940 additional items)
- **10,000 posts from a hashtag**: $4.00 (1 query + 9,940 additional items)
- **Multiple hashtags (5 hashtags, 2,000 total posts)**: $0.86 (5 queries + 1,700 additional items)

#### 💡 Pro Tip

Each hashtag query includes the first 60 posts for free! This makes small-scale hashtag research incredibly cost-effective - perfect for testing and analysis.

**Free users**: Limited to **5 runs per month**, each capped at **10 items**.

### 🆓 Demo Mode & Free Users

Users on the Free Plan can use the actor only in Demo Mode. **Free users can run the actor up to 5 times per month**, with each run capped at a maximum of 10 items — just enough to test it out. To use this actor without limitations, subscribe to a paid plan on Apify. [Subscribe here](https://apify.com/pricing?fpr=yhdrb).

### 🎎 Who needs this?

The Instagram Hashtag Scraper is engineered to deliver outstanding efficiency, rapid performance, and affordability for a wide variety of users:

- **Social Media Managers & Content Creators:** Track trending hashtags, analyze hashtag performance, and discover content ideas by exploring what's popular under specific hashtags. Perfect for content planning, competitor analysis, and understanding hashtag reach and engagement patterns.

- **Digital Marketing Agencies:** Use hashtag data to develop targeted marketing strategies, identify influencer partnerships, and track campaign hashtag performance. Essential for creating data-driven social media campaigns and measuring hashtag ROI across different client accounts.

- **Brand Monitoring & Market Research:** Monitor brand-related hashtags, track competitor hashtag usage, and analyze consumer sentiment around specific topics or campaigns. Valuable for reputation management, trend analysis, and understanding brand perception in the market.

- **E-commerce & Product Research:** Discover trending products, analyze customer feedback through hashtag content, and identify market opportunities by exploring product-related hashtags. Perfect for dropshipping research, product validation, and competitor analysis.

- **Influencer Marketing Professionals:** Find potential brand ambassadors by analyzing hashtag usage, track influencer content performance, and discover micro-influencers in specific niches. Essential for building comprehensive influencer databases and measuring campaign effectiveness.

- **Academic Researchers & Data Scientists:** Collect large-scale social media data for research projects, sentiment analysis, and trend forecasting. Ideal for studying social behavior, cultural trends, and digital communication patterns through hashtag analysis.

### 🍜 Output Example

```json
{
  "id": "3245142029192513970_62815273217",
  "code": "C0JD3tntcmy",
  "url": "https://www.instagram.com/p/C0JD3tntcmy/",
  "createdAt": "2023-11-27T07:48:34.000Z",
  "likeCount": 114,
  "commentCount": 5,
  "isPinned": false,
  "isLikeAndViewCountsDisabled": false,
  "isPaidPartnership": false,
  "caption": "#dogs #love Na zajęciach z Pomkami nie brakowało buziaków i przytulasów 🥰🤗 \n\n#pomeranian #pomeranianpuppies #szpicminiaturowy #szpic #bydgoszcz #warsztaty #pieski #psieżycie #psieszczęście #psiezabawy #usmiech #szczęście #szczeniaki #pieseły",
  "owner": {
    "id": "62815273217",
    "username": "jogi.lapki.bydgoszcz",
    "fullName": "Joga z pieskami 📍Bydgoszcz🐾",
    "profilePicUrl": "https://scontent-fra3-2.cdninstagram.com/v/t51.2885-19/400119638_1273742020004099_7576288759792512400_n.jpg",
    "isPrivate": false,
    "isVerified": false
  },
  "coowners": [
    {
      "id": "11830955",
      "username": "taylorswift",
      "fullName": "Taylor Swift",
      "profilePicUrl": "https://scontent-cdg4-1.cdninstagram.com/v/t51.2885-19/558299267_18598352038054956_7239389867355254960_n.jpg?stp=dst-jpg_e0_s150x150_tt6&efg=eyJ2ZW5jb2RlX3RhZyI6InByb2ZpbGVfcGljLmRqYW5nby4xMDgwLmMyIn0&_nc_ht=scontent-cdg4-1.cdninstagram.com&_nc_cat=1",
      "isPrivate": false,
      "isVerified": true
    }
	],
  "location": {
    "id": "215927995",
    "name": "Bydgoszcz, Poland",
    "slug": "Bydgoszcz",
    "address": "",
    "city": "",
    "lat": 53.1222,
    "lng": 17.9986
  },
  "isCarousel": false,
  "isVideo": true,
  "video": {
    "id": "235268832770811v",
    "url": "https://scontent-fra5-1.cdninstagram.com/o1/v/t16/f1/m69/GICWmACmUiQOyEkBAIXvggE-hRNYbpR1AAAF.mp4",
    "width": 1078,
    "height": 1916,
    "duration": 28.281,
    "playCount": 3321
  },
  "image": {
    "url": "https://scontent-fra5-1.cdninstagram.com/v/t51.2885-15/404322568_7096724227032530_1699247048939566807_n.jpg",
    "width": 1080,
    "height": 1920
  },
  "hashtags": ["dogs", "love", "pomeranian", "pomeranianpuppies", "szpicminiaturowy"]
}
```

### 🍚 Input Parameters

| Field | Type | Description | Default value |
| ----- | ---- | ----------- | ------------- |
| startUrls | array | Instagram hashtag search URLs. Paste hashtag search URLs and get results immediately. | `[]` |
| keyword | string | Search keyword for hashtag discovery. The scraper will search for posts containing this keyword. | `null` |
| getReels | boolean | Include reels in the scraping results. Set to false to exclude reels. | `true` |
| until | string | Date filter-only posts created on or after this date (YYYY-MM-DD). Works most reliably when scraping **posts only** (`getPosts: true`, `getReels: false`), where results come back in date order. For reels, or a mix of reels and posts, results are only roughly ordered by date, so a few items near the cutoff may be slightly off. | `null` |
| getPosts | boolean | Include regular posts in the scraping results. Set to false to exclude posts. | `true` |
| maxItems | number | Maximum number of items that you want to receive as output | `Infinity` |
| customMapFunction | string | Synchronous JavaScript function that transforms each output post or reel, for example to add computed fields or remove unnecessary data. Runs in a sandbox with plain JavaScript only and about 1 second per item. Not intended for filtering. See [Custom Map Function](#-custom-map-function). | `null` |
| outputConnector | string | MCP connector to deliver the results to — pick one (see [Send results straight into Notion, Todoist and more](#-send-results-straight-into-notion-todoist-and-more-mcp-connectors)). | `null` |
| deliverTarget | string | Where the connector writes — paste the URL or ID (Notion example: `https://www.notion.so/My-Posts-24f8a1b2c3d44e5f8a9b0c1d2e3f4a5b`); some services need none. | `null` |
| deliverMode | string | `perPost` (one record per scraped item) or `summary` (one roll-up per run). | `perPost` |
| deliverMaxItems | number | Optional cap on how many records `perPost` delivers (ignored in `summary`). | `null` |

### 🧩 Custom Map Function

Transform output using the `customMapFunction` parameter. This JavaScript function receives each post (or reel) object and returns your desired format-add engagement metrics, flatten owner data, or drop fields you do not need.

**Important:** Custom map function is for data transformation-**not for filtering**. Filtering items may result in automatic restrictions. Returning an empty object does not remove the item from the dataset-it is saved as `{ "noResults": true }` instead.

#### Example: Engagement and Owner Flattening

```javascript
(object) => ({
  ...object,
  engagementTotal: (object.likeCount || 0) + (object.commentCount || 0),
  username: object.owner?.username,
  isVerified: object.owner?.isVerified,
  hasLocation: !!object.location,
  locationName: object.location?.name,
  video: undefined,
  image: undefined
})
```

#### Common Transformations

| Use Case                | What to Add                                                           |
| ----------------------- | --------------------------------------------------------------------- |
| **Engagement Analysis** | `engagementTotal`, `likesToComments`                                  |
| **Owner Flattening**    | `username`, `fullName`, `isVerified`                                  |
| **Hashtag Analysis**    | `hashtagCount`, `hasHashtag`                                          |
| **Data Cleanup**        | Set `video: undefined`, `image: undefined`                            |

#### Requirements & Error Handling

The value must be a **single JavaScript function** that takes one item and returns the transformed item. Arrow functions and regular functions both work; `async` and generator functions are not supported.

**Limits:** the function runs in an isolated sandbox. It must be synchronous and finish within about 1 second per item, and only plain JavaScript is available (no network requests, `require` or `console`). Each item is passed in as plain JSON data.

**An unusable function never stops your run.** The actor logs a warning, ignores the function, and saves the original, unmodified items instead-so you still get your data:

| Situation | What happens |
| --------- | ------------ |
| Not valid JavaScript (for example, plain text pasted into the field) | Rejected before the first request; original items are saved |
| Valid JavaScript but not a function (for example, an object) | Rejected before the first request; original items are saved |
| `async` or generator function | Rejected before the first request; original items are saved |
| Returns a Promise (for example, `(object) => Promise.resolve(object)`) | Rejected at that point; the remaining items are saved unmodified |
| Returns something other than an object (for example, a number or `null`) | Rejected at that point; the remaining items are saved unmodified |
| Throws while transforming an item | Rejected at that point; the remaining items are saved unmodified |
| Takes longer than about 1 second on one item (for example, an endless loop) | Rejected at that point; the remaining items are saved unmodified |
| Uses date operations (`new Date`, `Date.now`, `1970`) | Rejected-use the `until` input to filter by date instead |

If your output does not look transformed, check the run log for a warning that starts with `Your "customMapFunction" input was rejected:`-it explains exactly what was wrong.

If you do not need to transform the output, simply leave this field empty.

### 🔌 Send results straight into Notion, Todoist and more (MCP connectors)

Skip the manual exports — the scraper can deliver its results directly into the tools you already work in, through [Apify MCP Connectors](https://apify.com/store/collections/mcp-connectors?fpr=yhdrb):

1. Authorize a connector (Notion, Todoist, or any service whose MCP server offers non-destructive write tools) once in [Console → Settings → API & Integrations → MCP connectors](https://console.apify.com/settings/integrations).
2. Pick it from the **Send results to Notion, Todoist, …** dropdown.
3. Fill in where and how to write:
   - **Destination target** — paste the URL or ID (Notion example: `https://www.notion.so/My-Posts-24f8a1b2c3d44e5f8a9b0c1d2e3f4a5b`); share it with your connector first via Notion's **••• → Connections** menu. (Some services need no target.)
   - **Write mode** — `perPost` writes one record per scraped item; `summary` writes a single roll-up for the run.
   - **Max records to deliver** *(optional)* — cap on how many records `perPost` delivers.

**Notion, structured like a spreadsheet:** point the target at a Notion **page** and the Actor auto-creates a database with one correctly-typed column per field (URL, number, date, text). An **existing database** fills the columns it already has (matched by name); an **empty database** receives only the title, with the rest of each record in the row body. Nested fields are flattened too (e.g. `owner` becomes `owner.username`, `owner.fullName`, … and `hashtags` becomes a comma-joined column), and the full record is kept in each row's page body.

Your credentials stay yours: the Actor only talks to your services through your own authorized connector and only uses non-destructive write tools — it cannot delete or overwrite anything you already have. Delivery is best-effort and runs after scraping: if it fails or the connector is misconfigured, the run still finishes successfully with all results intact and a warning in the log. If the run is about to time out, delivery stops early and the log tells you how many records were delivered.

### 🔧 Troubleshooting

- **Getting Few Results?** Check "Maximum number of items on output" (`maxItems`) field. This field enables you to control the total number of results. Leaving it empty will result in unlimited results.
- **Are Some Outputs Missing?** Ensure that you review all fields, not just the overview. You can navigate to the "Storage" tab and select either "Download the results" or "Open in a New Tab."
- **Getting No Results?** Confirm that your hashtag exists and has public content. Private or restricted hashtags may not return results.
- **Not Receiving New Items After a Large Batch?** Examine the log for messages like "Logging is too fast, some lines were skipped." If you encounter this issue, consider scraping smaller amounts of data to avoid it.

### 📞 Contact and Feature Requests

If you need any sort of support, please send an email to <apidojo10@gmail.com>. You name it, we get it.

### 🈴 Other Actors you might want to check

- [Instagram Scraper](https://apify.com/apidojo/instagram-scraper?fpr=yhdrb)
- [Instagram Comments Scraper](https://apify.com/apidojo/instagram-comments-scraper?fpr=yhdrb)
- [Instagram Location Scraper](https://apify.com/apidojo/instagram-location-scraper?fpr=yhdrb)
- [Twitter Scraper Unlimited](https://apify.com/apidojo/twitter-scraper-lite?fpr=yhdrb)
- [TikTok Comment Scraper](https://apify.com/apidojo/tiktok-comments-scraper?fpr=yhdrb)
- [TikTok User Scraper](https://apify.com/apidojo/tiktok-user-scraper?fpr=yhdrb)

# Actor input Schema

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

Instagram hashtag search URLs. Paste hashtag search URLs from Instagram and get the results immediately. Use the explore/tags/ format for hashtag URLs.

## `keyword` (type: `string`):

The keyword or hashtag that you want to search on Instagram. The scraper will find posts and reels containing this hashtag or keyword. Don't include the # symbol.

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

Set to true to include Instagram Reels in your results. Reels are short-form videos similar to TikTok content.

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

Set to true to include regular Instagram posts (photos and videos) in your results. This excludes Reels and Stories.

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

Return only posts newer than this date (YYYY-MM-DD format). Useful for tracking recent content and filtering by time period.

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

Maximum number of posts and reels that you want to receive as output. Leave empty for unlimited results (subject to available content).

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

JavaScript function to transform each output post or reel. Use to add computed fields, modify values, or remove unnecessary data. NOT intended for filtering - filtering may result in automatic bans. Must be a single synchronous function, e.g. (object) => { return {...object} }. It runs in a sandbox with plain JavaScript only (no network or require) and about 1 second per item. Leave empty if you do not need to transform the output - an unusable function is ignored and the original items are saved instead.

## `outputConnector` (type: `string`):

Pick an MCP connector you authorized in Console → Settings → API & Integrations → MCP connectors (e.g. Notion, Todoist — any service whose MCP server offers non-destructive write tools works best-effort). The scraped results are written through your own connector — the Actor never sees your third-party credentials. Only non-destructive write tools are used; it can never delete or overwrite your existing data.

## `deliverTarget` (type: `string`):

Where to write into the connector — paste the URL or ID. Notion example: https://www.notion.so/My-Posts-24f8a1b2c3d44e5f8a9b0c1d2e3f4a5b. Leave empty for services that need no target (e.g. Todoist Inbox, Slack). For Notion, share the page or database with your connector first (Notion's ••• → Connections menu), and point at a PAGE for structured columns (the Actor builds the database for you) — an empty database receives only the title (the rest of each record goes to the row's body).

## `deliverMode` (type: `string`):

perPost writes one record per scraped item; summary writes a single roll-up for the run.

## `deliverMaxItems` (type: `integer`):

Cap on how many records perPost mode writes to the connector; ignored in summary mode. Leave empty to deliver everything scraped.

## Actor input object example

```json
{
  "startUrls": [
    "https://www.instagram.com/explore/tags/cats/"
  ],
  "getReels": false,
  "getPosts": true,
  "maxItems": 1000,
  "customMapFunction": "(object) => { return {...object} }",
  "deliverMode": "perPost"
}
```

# Actor output Schema

## `overview` (type: `string`):

No description

# 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/explore/tags/cats/"
    ],
    "getReels": false,
    "getPosts": true,
    "maxItems": 1000,
    "customMapFunction": (object) => { return {...object} }
};

// Run the Actor and wait for it to finish
const run = await client.actor("apidojo/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 = {
    "startUrls": ["https://www.instagram.com/explore/tags/cats/"],
    "getReels": False,
    "getPosts": True,
    "maxItems": 1000,
    "customMapFunction": "(object) => { return {...object} }",
}

# Run the Actor and wait for it to finish
run = client.actor("apidojo/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 '{
  "startUrls": [
    "https://www.instagram.com/explore/tags/cats/"
  ],
  "getReels": false,
  "getPosts": true,
  "maxItems": 1000,
  "customMapFunction": "(object) => { return {...object} }"
}' |
apify call apidojo/instagram-hashtag-scraper --silent --output-dataset

```

## MCP server setup

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