# Instagram Keyword Search 🔍 Posts & Reels — $1/1K (`viralanalyzer/instagram-keyword-search-scraper`) Actor

Search Instagram by keyword or hashtag and extract posts, Reels and carousels: permalink, caption, author, media URL and engagement when exposed. Pay per event + usage — you pay compute and proxy.

- **URL**: https://apify.com/viralanalyzer/instagram-keyword-search-scraper.md
- **Developed by:** [viralanalyzer](https://apify.com/viralanalyzer) (community)
- **Categories:** Social media, Developer tools, Automation
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $0.53 / 1,000 post discovereds

This Actor is paid per event and usage. You are charged both the fixed price for specific events and for Apify platform usage.
Since this Actor supports Apify Store discounts, the price gets lower the higher subscription plan you have.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#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 Keyword Search Scraper — Posts & Reels

> 🔗 [View on Apify Store](https://apify.com/viralanalyzer/instagram-keyword-search-scraper) | 🇺🇸 English | [🇧🇷 Português](#português)

Search **Instagram by keyword or hashtag** and extract matching **posts, Reels, and carousels**. Get permalinks, captions, authors, media URLs, hashtags, mentions, and engagement when Instagram exposes them. Playwright cascade: cookie seeding → keyword explore XHR → hashtag page → embedded JSON → DOM links. No Meta API key.

### ✨ Features

- 🔍 **Keyword & hashtag search** — Single-word (`travel`) and multi-word (`sunset photography`)
- 📝 **Posts, Reels & Carousels** — Discover content from Instagram search, not from a profile you already know
- 📊 **Engagement when exposed** — Likes, comments, video views, duration
- 🏷️ **Hashtags & mentions** — Parsed from the caption
- 🧵 **Multiple keywords** — Process a batch in one run
- 🍪 **Cookie support** — Optional session cookies when Instagram shows a login wall
- 🔄 **Strategy cascade** — Explore XHR → hashtag page → embedded JSON → DOM permalinks
- 🛡️ **Stealth browsing** — Webdriver flag removal and basic fingerprint spoofing
- 🌐 **Proxy control** — Datacenter default; residential only after a confirmed block
- ✅ **Contract + provenance** — Invalid items are dropped, never billed
- 📷 **Debug screenshots** — Saved to KV Store when a keyword yields zero posts

### 🧭 Capabilities & Limits

| Discover by | Supported? | Notes |
|---|---|---|
| Keyword / search query (`keywords`) | ✅ Yes | Primary input. Returns posts/Reels/carousels. |
| Hashtag (`#tag` as a keyword) | ✅ Yes | Also opens `/explore/tags/{tag}/` as fallback. |
| Handle / username (`profiles`) | ❌ No | This actor searches by keyword. Use the [Reels & Posts Scraper](https://apify.com/viralanalyzer/instagram-reels-scraper) for profiles. |
| Post / Reel URL | ❌ No | Search results only. |
| Accounts / places typeahead | ❌ No | v1.0 typeahead was replaced. This actor returns **posts**. |

**Output includes:** post URL ✅ · shortcode ✅ · type ✅ · caption ✅ (when the media node has it) · author ✅ (when exposed) · likes/comments/views ✅ (XHR/embedded) or `null` on DOM fallback · hashtags/mentions ✅ (from caption) · comment **text** ❌.

### 📥 Input

| Parameter | Type | Required | Default | Description |
|---|---|---|---|---|
| `keywords` | string\[] | Yes | — | Keywords or hashtags (`sunset photography`, `#fitness`) |
| `maxPosts` | integer | No | 10 | Max posts per keyword (1–100 in this version) |
| `maxResults` | integer | No | — | **Alias** of `maxPosts` (unified vocabulary) |
| `seeds` | string\[] | No | — | **Alias** of `keywords` when `seedType` is `keyword` |
| `seedType` | string | No | `keyword` | Only `keyword` is supported |
| `cookies` | object\[] | No | — | Optional `{name, value, domain}` session cookies |
| `proxyConfig` | proxy | No | Apify DC | Datacenter default |

#### Input Example

```json
{
  "keywords": ["sunset photography", "#fitness"],
  "maxPosts": 10
}
```

**With cookies for authenticated access:**

```json
{
  "keywords": ["sunset photography"],
  "maxPosts": 10,
  "cookies": [
    {
      "name": "sessionid",
      "value": "your-session-id",
      "domain": ".instagram.com"
    }
  ]
}
```

### 📤 Output

| Field | Type | Description |
|---|---|---|
| `keyword` | string | Keyword that produced this item |
| `id` | string | null | Instagram media id when exposed |
| `shortCode` | string | Shortcode used in the permalink |
| `url` | string | `https://www.instagram.com/p/{code}/` or `/reel/` |
| `type` | string | `post`, `reel`, or `carousel` |
| `caption` | string | Caption text when present |
| `author` | string | null | Username when the media node includes it |
| `timestamp` | string | null | ISO 8601 UTC publish time |
| `likesCount` | integer | null | Likes when exposed |
| `commentsCount` | integer | null | Comment **count** (no comment text) |
| `videoViewCount` | integer | null | Plays/views for video |
| `videoDuration` | number | null | Duration in seconds |
| `displayUrl` | string | null | Thumbnail / display image |
| `hashtags` | string\[] | Parsed from caption |
| `mentions` | string\[] | Parsed from caption |
| `source` | string | `xhr`, `embedded`, or `dom` |
| `_dataQuality` | string | `full`, `dom_only_no_metrics`, or `diagnostic` |
| `scrapedAt` | string | ISO 8601 UTC collection time |

Missing engagement is `null`, never invented. DOM-only items have permalink + shortcode and `_dataQuality: "dom_only_no_metrics"`.

#### Output Example

```json
{
  "keyword": "sunset photography",
  "id": "3315678901234567890",
  "shortCode": "DFxRtPqWsYz",
  "url": "https://www.instagram.com/p/DFxRtPqWsYz/",
  "type": "post",
  "caption": "Golden hour in Lisbon #travel #sunset",
  "author": "citywalks",
  "timestamp": "2026-08-10T19:12:00Z",
  "likesCount": 1842,
  "commentsCount": 36,
  "videoViewCount": null,
  "videoDuration": null,
  "displayUrl": "https://scontent.cdninstagram.com/v/t51.2885-15/428573961_1234567890.jpg",
  "hashtags": ["travel", "sunset"],
  "mentions": [],
  "source": "xhr",
  "_dataQuality": "full",
  "scrapedAt": "2026-08-16T20:00:00Z"
}
```

### 📋 Use Cases

- 🔎 **Trend monitoring** — See what Instagram surfaces for a topic or hashtag
- 🏷️ **Hashtag research** — Collect real posts behind a tag, not just the tag page title
- 📊 **Market research** — Caption language, hashtags, and engagement patterns by keyword
- 🤖 **Seed generation** — Feed authors into the [Reels & Posts Scraper](https://apify.com/viralanalyzer/instagram-reels-scraper) for a full profile pull
- 📈 **Campaign tracking** — Watch branded keywords over time

### ❓ FAQ

**Q: Does this use the official Instagram Graph API?**
A: No. Graph API does not offer anonymous keyword search of public posts. This actor reads Instagram's public web search UI.

**Q: Does it work without logging in?**
A: Often yes, via homepage cookie seeding. A login wall is common. If you get `_blockReason: BLOCKED`, provide `cookies` (`sessionid`).

**Q: Why are likes null on some rows?**
A: DOM fallback found a real permalink but the media JSON did not include metrics. `_dataQuality` is `dom_only_no_metrics`. Those rows are still real posts.

**Q: Why is maxPosts capped at 100?**
A: Cost control. This is Playwright. A 10,000-post crawl is not safe until we have a measured cost curve.

**Q: Who pays compute and proxy?**
A: **You do.** Pricing is Pay per event **+ usage**. Events cover each valid post; compute units and Apify proxy are billed to the run owner. The publisher does not absorb Playwright or residential cost.

**Q: What happens on zero posts?**
A: Confirmed login wall or an empty set from Instagram → SUCCEEDED + one diagnostic item, no PPE. Parser drift or no origin response → FAIL with status, URL, HTML size, intercept count and proxy flag.

### 💰 Pricing

**Pay Per Event + platform usage** (client pays CU, traffic and Apify proxy):

| Event | Price |
|---|---|
| `apify-actor-start` | $0.00005 (platform default; 1× per GB of memory) |
| `post-discovered` | $0.001 per valid post ($1.00 / 1,000) |

**Example:** 5 keywords × 10 posts = 50 items = **$0.05** in events, plus the run's compute/proxy on your Apify invoice.

Diagnostics are never charged. Free-plan users are capped at **5 posts per keyword**.

### 🔗 Related Actors

- [Instagram Reels & Posts Scraper](https://apify.com/viralanalyzer/instagram-reels-scraper) — Profile grid + full engagement
- [TikTok Viral Scanner](https://apify.com/viralanalyzer/tiktok-viral-scanner) — TikTok profile and video data
- [YouTube Fast Scraper](https://apify.com/viralanalyzer/youtube-fast-scraper) — YouTube video metrics
- [Google Maps BR Scraper](https://apify.com/viralanalyzer/google-maps-br-scraper) — Google Maps business data

### 📝 Changelog

#### v1.1.0 (Current)

- Product is **posts/Reels by keyword**, not typeahead users/hashtags/places
- PPE event `post-discovered`; incremental charge; owner-skip
- Platform usage paid by the client (`isPPEPlatformUsagePaidByUser`)
- UAG-SG only on confirmed block or empty origin
- Residential fallback only after a confirmed block
- Default run: 2048 MB / 600 s

#### v1.0

- Typeahead search (users / hashtags / places) — superseded

***

<a name="português"></a>

## 🔍 Instagram Keyword Search Scraper — Posts e Reels

> [🇺🇸 English](#-instagram-keyword-search-scraper--posts--reels) | 🇧🇷 Português

Pesquise **por keyword ou hashtag no Instagram** e extraia **posts, Reels e carrosséis**. Permalink, legenda, autor, URL de mídia, hashtags, menções e engajamento quando o Instagram expõe. Cascata Playwright: cookie seeding → explore XHR → página de hashtag → JSON embutido → links DOM. Sem chave da API da Meta.

### ✨ Funcionalidades

- 🔍 **Busca por keyword e hashtag** — Uma palavra (`viagem`) ou várias (`pôr do sol lisboa`)
- 📝 **Posts, Reels e carrosséis** — Conteúdo da busca, não de um perfil que você já conhece
- 📊 **Engajamento quando exposto** — Curtidas, comentários, views, duração
- 🏷️ **Hashtags e menções** — Extraídas da legenda
- 🧵 **Várias keywords** — Um único run
- 🍪 **Cookies opcionais** — Quando o Instagram pede login
- 🔄 **Cascata de estratégias** — XHR da busca → hashtag → JSON embutido → permalinks DOM
- 🛡️ **Navegação stealth** — Remoção da flag webdriver
- 🌐 **Proxy** — Datacenter padrão; residencial só após bloqueio confirmado
- ✅ **Contrato + proveniência** — Item inválido é descartado, nunca cobrado
- 📷 **Screenshots de debug** — Salvos no KV Store se a keyword não render posts

### 🧭 Capacidades e Limites

| Descobrir por | Suportado? | Observações |
|---|---|---|
| Keyword / busca (`keywords`) | ✅ Sim | Entrada principal. Devolve posts/Reels/carrosséis. |
| Hashtag (`#tag` como keyword) | ✅ Sim | Também abre `/explore/tags/{tag}/` como fallback. |
| Handle / username (`profiles`) | ❌ Não | Este actor busca por keyword. Use o [Reels & Posts Scraper](https://apify.com/viralanalyzer/instagram-reels-scraper) para perfis. |
| URL de post / Reel | ❌ Não | Só resultados de busca. |
| Autocomplete de contas/lugares | ❌ Não | O v1.0 typeahead foi substituído. Este actor devolve **posts**. |

**A saída inclui:** URL do post ✅ · shortcode ✅ · tipo ✅ · legenda ✅ (quando o nó de mídia tem) · autor ✅ (quando exposto) · likes/comentários/views ✅ (XHR/embutido) ou `null` no fallback DOM · hashtags/menções ✅ · **texto** de comentário ❌.

### 📥 Entrada

| Parâmetro | Tipo | Obrigatório | Padrão | Descrição |
|---|---|---|---|---|
| `keywords` | string\[] | Sim | — | Keywords ou hashtags |
| `maxPosts` | inteiro | Não | 10 | Máximo de posts por keyword (1–100) |
| `maxResults` | inteiro | Não | — | **Alias** de `maxPosts` |
| `cookies` | objeto\[] | Não | — | Cookies de sessão opcionais |
| `proxyConfig` | proxy | Não | DC Apify | Datacenter padrão |

#### Exemplo de Entrada

```json
{
  "keywords": ["sunset photography", "#fitness"],
  "maxPosts": 10
}
```

### 📤 Saída

Campos iguais à tabela em inglês. Itens só-DOM têm permalink + shortcode e `_dataQuality: "dom_only_no_metrics"`. Engajamento ausente vem `null`.

### 📋 Casos de Uso

- 🔎 **Monitoramento de tendência** — O que o Instagram mostra para um tema
- 🏷️ **Pesquisa de hashtags** — Posts reais atrás da tag
- 📊 **Pesquisa de mercado** — Linguagem de caption e padrões de engajamento
- 🤖 **Geração de sementes** — Autores para o scraper de perfil
- 📈 **Rastreamento de campanha** — Keywords de marca ao longo do tempo

### ❓ Perguntas Frequentes

**P: Usa a Graph API oficial?**
R: Não. A Graph API não oferece busca anônima de posts por keyword.

**P: Funciona sem login?**
R: Muitas vezes sim, com cookie seeding da homepage. Login wall é comum — use `cookies`.

**P: Por que likes vêm null?**
R: Fallback DOM achou permalink real sem JSON de métricas. `_dataQuality` = `dom_only_no_metrics`.

**P: Por que o teto é 100?**
R: Custo de Playwright. Sem curva medida, 10 mil posts não é seguro.

**P: Quem paga compute e proxy?**
R: **Você.** Pay per event **+ usage**. Eventos cobrem cada post válido; CU e proxy Apify vão na conta de quem rodou.

**P: E se não vier nenhum post?**
R: Login wall ou conjunto vazio confirmado pela origem → SUCCEEDED + diagnóstico, sem PPE. Drift ou origem muda → FAIL com status, URL, bytes e interceptações.

### 💰 Preços

**Pay Per Event + uso de plataforma** (o cliente paga CU, tráfego e proxy Apify):

| Evento | Preço |
|---|---|
| `apify-actor-start` | $0.00005 (default; 1× por GB) |
| `post-discovered` | $0.001 por post válido ($1,00 / 1.000) |

**Exemplo:** 5 keywords × 10 posts = 50 itens = **$0,05** em eventos, mais o compute/proxy na sua fatura Apify.

Diagnóstico nunca é cobrado. Plano free: **5 posts por keyword**.

### 🔗 Actors Relacionados

- [Instagram Reels & Posts Scraper](https://apify.com/viralanalyzer/instagram-reels-scraper) — Grade de perfil + engajamento
- [TikTok Viral Scanner](https://apify.com/viralanalyzer/tiktok-viral-scanner) — Perfis e vídeos do TikTok
- [YouTube Fast Scraper](https://apify.com/viralanalyzer/youtube-fast-scraper) — Métricas do YouTube
- [Google Maps BR Scraper](https://apify.com/viralanalyzer/google-maps-br-scraper) — Empresas no Google Maps

### 📝 Changelog

#### v1.1.0 (Atual)

- Produto = **posts/Reels por keyword**
- Evento `post-discovered`; charge incremental; owner-skip
- Uso de plataforma pago pelo cliente
- UAG-SG só com bloqueio ou origem vazia confirmados
- Residencial só após bloqueio confirmado
- Default: 2048 MB / 600 s

#### v1.0

- Busca typeahead (users / hashtags / places) — substituída

# Actor input Schema

## `keywords` (type: `array`):

Keywords or hashtags to search (e.g. 'sunset photography', '#fitness'). Each keyword returns matching posts/Reels.

## `maxPosts` (type: `integer`):

Maximum number of posts to extract per keyword. Capped at 100 in this version to protect run cost.

## `maxResults` (type: `integer`):

Unified-vocabulary alias for 'maxPosts'. If set, it overrides 'maxPosts'.

## `maxResultsAlias` (type: `integer`):

Legacy alias for 'maxPosts'. If set, it overrides 'maxPosts' and 'maxResults'.

## `seeds` (type: `array`):

Unified-vocabulary alias for 'keywords'. Used when non-empty AND seedType is 'keyword'.

## `seedType` (type: `string`):

Type of the values in 'seeds'. This actor only supports keywords.

## `cookies` (type: `array`):

Optional cookies for authenticated access. Array of {name, value, domain} objects. Improves reliability when Instagram shows a login wall.

## `proxyConfig` (type: `object`):

Select proxies to be used by your scraper.

## Actor input object example

```json
{
  "keywords": [
    "sunset photography"
  ],
  "maxPosts": 10,
  "seedType": "keyword",
  "proxyConfig": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

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

Dataset of posts/Reels. Each item follows the dataset schema.

# 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 = {
    "keywords": [
        "sunset photography"
    ],
    "proxyConfig": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("viralanalyzer/instagram-keyword-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 = {
    "keywords": ["sunset photography"],
    "proxyConfig": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("viralanalyzer/instagram-keyword-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 '{
  "keywords": [
    "sunset photography"
  ],
  "proxyConfig": {
    "useApifyProxy": true
  }
}' |
apify call viralanalyzer/instagram-keyword-search-scraper --silent --output-dataset

```

## MCP server setup

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