# Instagram Search Scraper (`happy_b/instagram-search-scraper`) Actor

Search Instagram users, hashtags, and public posts by keyword. Export stable IDs, canonical URLs, engagement metrics, media fields, and typed results.

- **URL**: https://apify.com/happy\_b/instagram-search-scraper.md
- **Developed by:** [Happy B](https://apify.com/happy_b) (community)
- **Categories:** Social media, Videos
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 1 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.49 / 1,000 results

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

### What is Instagram Search Scraper?

Instagram Search Scraper finds public Instagram users, hashtags, and posts by keyword and returns clean, typed rows for discovery, research, monitoring, and analytics. Submit up to 50 search terms, choose the result types you need, and export stable IDs, canonical URLs, engagement metrics, media fields, source-query context, and scrape timestamps.

Every row records the query and query position that produced it. User, Hashtag, and Post dataset views expose the same validated records in Apify Console, API responses, JSON, and CSV without undocumented response fields.

### What can you search?

Enable any combination of the three supported result types:

- **Users:** stable profile ID, username, full name, verification state, profile pictures, and canonical profile URL.
- **Hashtags:** stable hashtag ID, normalized name, canonical hashtag URL, and observed media count.
- **Posts:** stable post ID, shortcode, canonical post URL, caption, publication time, likes, comments, plays, views, photo or video URLs, dimensions, carousel slides, and author identity.

Post search is paginated up to `maxPostsPerQuery`. User and hashtag search return the matches made available for that query. Numeric zero is kept as `0`; an optional value that was unavailable is returned as `null`.

### Use cases

- **Influencer discovery:** search a niche, collect matching accounts, and pass their usernames to Instagram Profile Scraper for full audience and profile details.
- **Hashtag research:** compare stable hashtag IDs and media counts across multiple topic phrases.
- **Brand monitoring:** collect public posts matching brand, product, campaign, or competitor terms and compare engagement.
- **Content discovery:** find photos, videos, and carousels related to a topic, including canonical URLs and publication times.
- **Trend research:** schedule repeat searches and compare the public results and engagement made available over time.
- **Dataset enrichment:** attach `sourceQuery`, `queryPosition`, `resultType`, and result `position` to every row for reproducible downstream joins.

### Input

| Parameter | Type | Default | Description |
|---|---|---:|---|
| `searchQueries` | string\[] | required | One to 50 keyword phrases. Blank entries are rejected and case-insensitive duplicates are removed. |
| `searchUsers` | boolean | `false` | Return matching public accounts. |
| `searchHashtags` | boolean | `false` | Return matching hashtags and media counts. |
| `searchPosts` | boolean | `true` | Return paginated public posts. |
| `maxPostsPerQuery` | integer | `50` | Maximum unique post rows per query when post search is enabled. Range: 1–5,000. |

At least one result type must be enabled. The defaults search posts only, which keeps a simple input useful while avoiding extra user or hashtag rows unless requested.

#### Sample input

```json
{
  "searchQueries": [
    "space photography",
    "climate science"
  ],
  "searchUsers": true,
  "searchHashtags": true,
  "searchPosts": true,
  "maxPostsPerQuery": 25
}
```

### Output

The default dataset uses a closed schema. Operational request fields, authentication values, and pagination state are not included.

#### Schema-valid user row

```json
{
  "sourceQuery": "space photography",
  "queryPosition": 1,
  "resultType": "user",
  "position": 1,
  "scrapeTimestamp": "2026-08-30T12:15:00.000Z",
  "pk": "528817151",
  "username": "nasa",
  "fullName": "NASA",
  "profileUrl": "https://www.instagram.com/nasa/",
  "isVerified": true,
  "profilePicUrl": "https://images.example/nasa-profile.jpg",
  "hdProfilePicUrl": "https://images.example/nasa-profile-hd.jpg"
}
```

#### Schema-valid hashtag row

```json
{
  "sourceQuery": "space photography",
  "queryPosition": 1,
  "resultType": "hashtag",
  "position": 1,
  "scrapeTimestamp": "2026-08-30T12:15:00.000Z",
  "id": "17843701042062919",
  "name": "spacephotography",
  "hashtagUrl": "https://www.instagram.com/explore/tags/spacephotography/",
  "mediaCount": 1250000
}
```

#### Schema-valid post row

```json
{
  "sourceQuery": "space photography",
  "queryPosition": 1,
  "resultType": "post",
  "position": 1,
  "scrapeTimestamp": "2026-08-30T12:15:00.000Z",
  "pk": "3712345678901234567",
  "code": "DSpaceExample",
  "postUrl": "https://www.instagram.com/p/DSpaceExample/",
  "mediaType": 2,
  "mediaTypeName": "video",
  "caption": "Earthrise from orbit.",
  "takenAt": 1788092100,
  "takenAtIso": "2026-08-30T12:15:00.000Z",
  "likeCount": 245000,
  "commentCount": 1850,
  "playCount": 920000,
  "viewCount": 920000,
  "imageUrl": "https://images.example/space-cover.jpg",
  "videoUrl": "https://media.example/space-video.mp4",
  "imageWidth": 1080,
  "imageHeight": 1920,
  "carouselMedia": [],
  "authorPk": "528817151",
  "authorUsername": "nasa",
  "authorProfileUrl": "https://www.instagram.com/nasa/"
}
```

Download results as JSON, CSV, Excel, XML, or HTML, or read them through the Apify API. The run key-value store also contains `METADATA`, which reports `COMPLETE`, `PARTIAL`, or `FAILED`, per-type row totals, query completion counts, spending-limit state, and customer-safe error summaries.

### Pricing

You pay once when a run starts and once for each successful user, hashtag, or post row delivered to the default dataset. All three result types have the same price. Empty searches, rejected rows, overlaps, and results that are not stored do not create a result charge.

| Apify tier | Per result | Per 1,000 results |
|---|---:|---:|
| Free | $0.00349 | $3.49 |
| Bronze | $0.00349 | $3.49 |
| Silver | $0.00349 | $3.49 |
| Gold | $0.00349 | $3.49 |
| Platinum | $0.00349 | $3.49 |
| Diamond | $0.00349 | $3.49 |

The Actor Start event is $0.001 per run. There is no minimum total charge and no premium add-on event.

| Example | Approximate event cost |
|---|---:|
| 10 delivered results | $0.0409 |
| 50 delivered results | $0.2005 |
| 1,000 delivered results | $3.4910 |

Use `maxPostsPerQuery`, the result-type switches, and Apify’s maximum total charge to bound exploratory searches.

### Deduplication and positions

Rows are deduplicated deterministically within each source query and result type. If consecutive post pages overlap, the repeated post is not stored or charged again. The same post may legitimately appear once for each different query because `sourceQuery` is part of the result identity and explains why that row was discovered.

`queryPosition` is the submitted query’s one-based position. `position` is the one-based unique-result position for that query and result type. These fields remain stable through page overlap and make CSV exports suitable for ranking and auditing.

### Run status and reliability

The Actor saves progress between pages and validates each normalized row before storage. It detects malformed pagination and repeated page states. If a run is interrupted, migrated, or resurrected, it reconciles already stored rows before continuing so a result is not stored or charged twice.

`METADATA.status` means:

- `COMPLETE`: all enabled search operations reached a terminal result and no spending boundary stopped delivery.
- `PARTIAL`: some data was delivered, but a spending boundary or retryable failure prevented full delivery.
- `FAILED`: no requested data was delivered.

A valid search with no available matches is complete with zero rows. A run never reports success simply because the process exited normally.

### API example

Start a search and return its dataset items with Apify’s synchronous endpoint:

```bash
curl -X POST \
  "https://api.apify.com/v2/acts/happy_b~instagram-search-scraper/run-sync-get-dataset-items?token=YOUR_APIFY_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "searchQueries": ["outdoor photography", "sustainable travel"],
    "searchUsers": true,
    "searchHashtags": true,
    "searchPosts": true,
    "maxPostsPerQuery": 20
  }'
```

For longer searches, start the Actor asynchronously and read items from the run’s default dataset. See the [Apify API documentation](https://docs.apify.com/api/v2) for JavaScript, Python, and HTTP clients.

### Integrations

Connect [Apify integrations](https://docs.apify.com/platform/integrations) to Google Drive, Make, Zapier, Slack, webhooks, or your own warehouse. Use `sourceQuery` to route results and stable string IDs to update existing records instead of creating duplicates.

### Limitations

- Results are limited to information available from public Instagram search surfaces at scrape time.
- Search ordering and result availability can change between runs.
- A maximum is a delivery ceiling, not a promise that a query has that many public matches.
- User search does not include full audience counts or biographies; enrich discovered usernames with Instagram Profile Scraper.
- Place search, comments, Stories, follower lists, following lists, and private analytics are not supported.
- Optional engagement and media values can be unavailable and will be `null`.
- Media URLs can expire. Download permitted media promptly if durable files are required.

### Responsible use

Public search results can still contain personal data. Use them only for a lawful purpose, minimize retention, honor access and deletion obligations, and comply with applicable privacy laws and Instagram’s terms.

### Related Actor

Use [Instagram Profile Scraper](https://apify.com/happy_b/instagram-profile-scraper) to turn discovered usernames into complete profile rows with exact audience counts, bio links, account classification, and optional public post history.

### Support

If a run behaves unexpectedly, open an issue from the Actor page and include the run ID, a secret-free input example, the expected result, and the observed `METADATA.status`.

# Actor input Schema

## `searchQueries` (type: `array`):

Keywords to search on Instagram. Each query runs a separate search.

## `searchUsers` (type: `boolean`):

Return matching public Instagram accounts.

## `searchHashtags` (type: `boolean`):

Return matching hashtags and observed media counts.

## `searchPosts` (type: `boolean`):

Return paginated public posts matching each query.

## `maxPostsPerQuery` (type: `integer`):

Maximum number of unique post rows to return per query when post search is enabled.

## Actor input object example

```json
{
  "searchQueries": [
    "fitness"
  ],
  "searchUsers": false,
  "searchHashtags": false,
  "searchPosts": true,
  "maxPostsPerQuery": 50
}
```

# Actor output Schema

## `results` (type: `string`):

Unique user, hashtag, and post rows tagged with their source query and position.

## `metadata` (type: `string`):

COMPLETE, PARTIAL, or FAILED status, exact result counts, spending-limit state, and sanitized errors.

# 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 = {
    "searchQueries": [
        "fitness"
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("happy_b/instagram-search-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 = { "searchQueries": ["fitness"] }

# Run the Actor and wait for it to finish
run = client.actor("happy_b/instagram-search-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 '{
  "searchQueries": [
    "fitness"
  ]
}' |
apify call happy_b/instagram-search-scraper --silent --output-dataset

```

## MCP server setup

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