# Instagram Hashtag Username Scraper (`maximedupre/instagram-hashtag-username-scraper`) Actor

Find public Instagram posts by hashtag and save usernames, captions, media links, available engagement counts, and author details. Use the dataset for hashtag research without an Instagram login.

- **URL**: https://apify.com/maximedupre/instagram-hashtag-username-scraper.md
- **Developed by:** [Maxime Dupré](https://apify.com/maximedupre) (community)
- **Categories:** Social media, Marketing, Lead generation
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$0.15 / 1,000 hashtag posts

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?

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

### 🔎 Find Instagram users from hashtags

Marketers, researchers, and creator teams can search public Instagram hashtags and get structured post rows with usernames, available author IDs, captions, engagement counts, media links, and post URLs. This helps you find accounts and study the content around a hashtag without an Instagram login.

Use it to:

- Find public posts for a tag with **[Scrape Instagram Hashtags](https://apify.com/maximedupre/instagram-hashtag-username-scraper/examples/scrape-instagram-hashtags)**.
- Review public post data with **[Instagram Post Scraper](https://apify.com/maximedupre/instagram-hashtag-username-scraper/examples/instagram-post-scraper)**.
- Collect rows from several tags with **[Instagram Hashtag Posts](https://apify.com/maximedupre/instagram-hashtag-username-scraper/examples/instagram-hashtag-posts)**.
- Search one of your tags with **[Instagram Hashtag Search](https://apify.com/maximedupre/instagram-hashtag-username-scraper/examples/instagram-hashtag-search)**.
- Build a hashtag post list with **[Instagram Hashtag Scraper](https://apify.com/maximedupre/instagram-hashtag-username-scraper/examples/instagram-hashtag-scraper)**.

#### 📋 Public hashtag post data

Each saved row represents one public Instagram post found through a submitted hashtag. It includes post identity, public author details, caption text, caption hashtags and mentions, engagement counts, publication time, media details, and source links when Instagram provides them.

The Actor saves the first eligible match for a source post. If the same post appears again through another submitted hashtag, the later match is ignored. The saved row describes that first match only.

#### ▶️ Search hashtags and save posts

**How it works**

1. Add one or more hashtag values in the Input tab.
2. Set a maximum number of posts for each hashtag, or add a date filter.
3. Start the run and let the Actor save eligible public post rows.
4. Open the dataset link in the run output.

To shorten the run and review fewer rows, set a lower **Maximum posts per hashtag** value or use **Posts newer than**. Leave **Maximum posts per hashtag** empty to return all available posts until the source is exhausted.

#### ⚙️ Input

**Input fields**

| Field | Type | What it does |
| --- | --- | --- |
| `hashtags` | array of strings | Required. Add one or more Instagram hashtag values, with each value as a separate item. |
| `maxPostsPerHashtag` | integer | Optional positive limit for each hashtag. The schema has no upper bound. Leave it empty to return all available posts until the source is exhausted. |
| `newerThan` | string (`YYYY-MM-DD`) | Optional date filter. Only include posts published after this date. Leave it blank to include all available dates. |

**Default input example**

This example is from a successful current beta run with the default input.

```json
{
  "hashtags": [
    "travel"
  ],
  "maxPostsPerHashtag": 10
}
```

#### 🧾 Output

**Dataset link**

| Field | Type | What it does |
| --- | --- | --- |
| `dataset` | string | Link to the saved public Instagram post rows in the `overview` view. |

**Post rows**

| Field | Type | What it does |
| --- | --- | --- |
| `mediaId` | string | Required stable identifier of the public Instagram media. |
| `shortcode` | string | Required shortcode used in the public post URL. |
| `postUrl` | string (URL) | Required public URL of the Instagram post. |
| `sourceHashtag` | string | Submitted hashtag that first led to this post, without `#`, when available. |
| `author` | object | Required available public details about the post author. |
| `author.username` | string | Required username of the account that posted the media. |
| `author.id` | string | Public author identifier when available. |
| `author.displayName` | string | Public display name of the post author when available. |
| `author.isVerified` | boolean | Whether Instagram marks the author as verified when available. |
| `author.isPrivate` | boolean | Whether Instagram marks the author account as private when available. |
| `author.profileImageUrl` | string (URL) | Public URL of the author's profile image when available. |
| `caption` | string | Caption published with the post when available. |
| `hashtags` | array of strings | Hashtags found in the post caption when available. |
| `mentions` | array of strings | Usernames mentioned in the post caption when available. |
| `likesCount` | integer | Number of likes shown for the post when available. |
| `commentsCount` | integer | Number of comments shown for the post when available. |
| `videoViewsCount` | integer | Number of views shown for a video or reel when available. |
| `videoDurationSeconds` | number | Length of a video or reel in seconds when available. |
| `publishedAt` | string (date-time) | Time when the post was published when available. |
| `mediaType` | string | Type of the public media, such as photo, video, reel, or carousel. |
| `mediaUrl` | string (URL) | Main public URL for the post media when available. |
| `dimensions` | object | Width and height of the main media when available. |
| `dimensions.width` | integer | Width of the main media in pixels. |
| `dimensions.height` | integer | Height of the main media in pixels. |
| `location` | object | Public location attached to the post when available. |
| `location.name` | string | Public name of the attached location. |
| `location.id` | string | Public location identifier when available. |
| `taggedAccounts` | array of objects | Public accounts tagged in the post when available. |
| `taggedAccounts[].username` | string | Username of a tagged public account. |
| `taggedAccounts[].id` | string | Public identifier of a tagged account when available. |
| `taggedAccounts[].displayName` | string | Display name of a tagged account when available. |
| `collaborators` | array of objects | Public accounts listed as collaborators when available. |
| `collaborators[].username` | string | Username of a collaborator account. |
| `collaborators[].id` | string | Public identifier of a collaborator when available. |
| `collaborators[].displayName` | string | Display name of a collaborator when available. |

**Example post row**

This complete row came from a successful current beta run for the `photodump` hashtag. Optional fields that were not returned are not added.

```json
{
  "mediaId": "POLARIS_3907137784182940844",
  "shortcode": "DY48R0iuySs",
  "postUrl": "https://www.instagram.com/p/DY48R0iuySs/",
  "author": {
    "username": "aaverdeestefany",
    "id": "17841428646874266",
    "displayName": "𝑬𝒔𝒕𝒆𝒇𝒂𝒏𝒚 𝑴𝒐𝒓𝒆𝒏𝒐",
    "isVerified": false,
    "isPrivate": false,
    "profileImageUrl": "https://scontent-dfw5-2.cdninstagram.com/v/t51.75761-19/491496796_18065630422954896_9093467990242766351_n.jpg?stp=cp0_dst-jpg_s34x34_tt6&_nc_cat=100&ccb=7-5&_nc_sid=bf7eb4&efg=eyJ2ZW5jb2RlX3RhZyI6InByb2ZpbGVfcGljLnd3dy4xMDI0LkMzIn0%3D&_nc_ohc=N9Q9M1pt83EQ7kNvwF6nMcq&_nc_oc=AdojPKOjj9lhhGffJdgh6V81gOzl3mojcqFgRQDQez0L3a-wGLIJHnqjG7D5NRgfSe0&_nc_zt=24&_nc_ht=scontent-dfw5-2.cdninstagram.com&_nc_gid=hwPu5acJWhzCsm4AbpmjvQ&_nc_ss=73689&oh=00_AQL5skiv86JFbFFVyHqixq_28ngt88Wd6O1rS_WjCUQASw&oe=6A9BFC0C"
  },
  "mediaType": "reel",
  "caption": "Un dump de fotos y videos porque una sola imagen no era suficiente 🌿📸\nCosas bonitas, momentos simples y un poquito de todo lo que me inspira últimamente ✨\n\n#photodump #collage #aesthetic #plantlover #dump reels tiktok momentos vibes naturaleza contenido fyp",
  "hashtags": [
    "photodump",
    "collage",
    "aesthetic",
    "plantlover",
    "dump"
  ],
  "likesCount": 14478,
  "commentsCount": 38,
  "publishedAt": "2026-05-28T16:55:18.000Z",
  "mediaUrl": "https://scontent-dfw6-1.cdninstagram.com/o1/v/t2/f2/m86/AQMUVqDqvXQPt6d4U_lIiLtrE3z327wtlq5c0eWwVrOZOK3srp2UaE_gYaRpwf2eRPOF3UL7M4Z9uX-1h7ujj_HiLD7ZYxtV4seaED0.mp4?_nc_cat=102&_nc_sid=5e9851&_nc_ht=scontent-dfw6-1.cdninstagram.com&_nc_ohc=A9pVIjjs6R8Q7kNvwF010F_&efg=eyJ2ZW5jb2RlX3RhZyI6Inhwdl9wcm9ncmVzc2l2ZS5JTlNUQUdSQU0uQ0xJUFMuQzMuNzIwLmRhc2hfYmFzZWxpbmVfMV92MSIsInhwdl9hc3NldF9pZCI6MTQzNDg5NzQ1ODY3MjQ2OCwiYXNzZXRfYWdlX2RheXMiOjk1LCJ2aV91c2VjYXNlX2lkIjoxMDgyNywiZHVyYXRpb25fcyI6NywidXJsZ2VuX3NvdXJjZSI6Ind3dyJ9&ccb=17-1&vs=747d9e3007efb07c&_nc_vs=HBksFQIYUmlnX3hwdl9yZWVsc19wZXJtYW5lbnRfc3JfcHJvZC9GMzQzRDc2NEY1RkNBRjhDMzkxQUJBMTBBN0U2NDJBNF92aWRlb19kYXNoaW5pdC5tcDQVAALIARIAFQIYUWlnX3hwdl9wbGFjZW1lbnRfcGVybWFuZW50X3YyL0Y2NDQxM0REMzMzMDA3NDdFQ0E0RUU0NTZEMTNDQzk2X2F1ZGlvX2Rhc2hpbml0Lm1wNBUCAsgBEgAoABgAGwKIB3VzZV9vaWwBMRJwcm9ncmVzc2l2ZV9yZWNpcGUBMRUAACaozYGVg8KMBRUCKAJDMywXQB5DlYEGJN0YEmRhc2hfYmFzZWxpbmVfMV92MREAdf4HZZapAQA&_nc_gid=hwPu5acJWhzCsm4AbpmjvQ&_nc_ss=73689&_nc_zt=28&oh=00_AQLi679CON5i7hCqZeXVw6GUKJEVq6HJr7wTpZSJRz6HKA&oe=6A983CAB",
  "dimensions": {
    "width": 1215,
    "height": 2160
  },
  "videoViewsCount": 206048,
  "videoDurationSeconds": 7.568254,
  "sourceHashtag": "photodump"
}
```

#### 💳 Pricing

**Charged event**

This Actor uses pay-per-event pricing. Apify charges one event for each eligible public post saved to the dataset, with available username and post metadata. The current event price is shown before you run. Your total depends on the number of posts saved and the limits you choose.

#### 🔌 Integrations

Open the dataset in Apify or use the Apify API to read and export saved rows.

https://www.youtube.com/watch?v=bNACk1\_S\_6w\&list=PLObrtcm1Kw6MUrlLNDbK9QRg8VDJg0gOW\&index=4

#### ❓ FAQ

##### What happens when the same post matches more than one hashtag?

The Actor saves the first eligible match and ignores later matches for that source post. The saved row keeps the data from the first match.

##### Can I search more than one hashtag in one run?

Yes. Add each hashtag as a separate item. The Actor searches each one and applies the post limit and date filter to each hashtag.

##### What does leaving Maximum posts per hashtag empty do?

It returns all available posts until the source is exhausted. The schema does not set an upper bound for this field.

##### Can I filter posts by date?

Yes. Enter a date in `YYYY-MM-DD` format in `newerThan`. The Actor includes posts published after that date.

##### What if Instagram does not provide a field?

Optional public fields may be missing or null when Instagram does not provide them. The Actor does not guess missing values.

##### Does it return every post for a hashtag?

No complete or fixed result set is promised. Public availability can change. With no per-hashtag limit, the Actor continues until the source is exhausted.

##### Can it access private posts or use my Instagram login?

No. This Actor discovers public hashtag posts and does not require an Instagram login or other customer credentials.

### 📝 Changelog

**v0.1** (01-09-2026)

- Adds source hashtag, video views and duration, location, tagged-account, and collaborator details when Instagram provides them.
- Improves post discovery when Instagram returns transient, incomplete, or alternate response data.

**v0.0**

- Initial release.

### 🆘 Support

For issues, questions, or feature requests, [file a ticket](https://console.apify.com/actors/maximedupre~instagram-hashtag-username-scraper/issues) and I'll fix or implement it in less than 24h 🫡

### 🔗 Related Actors

- [Instagram Downloader API](https://apify.com/maximedupre/instagram-downloader-api) - Get direct media links from known public Instagram posts or Reels.
- [Instagram User Search](https://apify.com/maximedupre/instagram-user-search-scraper) - Find public account candidates from keywords before a separate profile or post review.
- [Instagram Reels Comment Scraper](https://apify.com/maximedupre/instagram-reels-comments-scraper) - Collect top-level comments from known public Reels to study audience feedback.
- [Instagram Profile Stats Scraper](https://apify.com/maximedupre/instagram-profile-stats-scraper) - Check public profile counts and account flags for usernames found in your post rows.
- [Instagram Related Users Scraper](https://apify.com/maximedupre/instagram-related-users-scraper) - Expand from a known public profile to related accounts after finding an author.

**Made with ❤️ by Maxime Dupré**

# Actor input Schema

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

Enter one or more Instagram hashtags. Add each hashtag as a separate item.

## `maxPostsPerHashtag` (type: `integer`):

Stop after this many posts for each hashtag. Leave it empty to return all available posts until the source is exhausted.

## `newerThan` (type: `string`):

Only include posts published after this date. Leave it blank to include all available dates.

## Actor input object example

```json
{
  "hashtags": [
    "travel",
    "streetstyle"
  ],
  "maxPostsPerHashtag": 25,
  "newerThan": "2025-01-01"
}
```

# Actor output Schema

## `dataset` (type: `string`):

Open the discovered public Instagram posts in the default dataset.

# 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": [
        "travel"
    ],
    "maxPostsPerHashtag": 10
};

// Run the Actor and wait for it to finish
const run = await client.actor("maximedupre/instagram-hashtag-username-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": ["travel"],
    "maxPostsPerHashtag": 10,
}

# Run the Actor and wait for it to finish
run = client.actor("maximedupre/instagram-hashtag-username-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": [
    "travel"
  ],
  "maxPostsPerHashtag": 10
}' |
apify call maximedupre/instagram-hashtag-username-scraper --silent --output-dataset

```

## MCP server setup

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