# Instagram Account Search — Find Accounts with Business Contacts (`steadyfetch/instagram-account-search-scraper`) Actor

Instagram account search and Instagram user search by keyword or hashtag: find the accounts behind any phrase or tag, and read each in full for the email, phone and city a business publishes. $3.00 per 1,000 accounts. Accounts you already have are never charged twice.

- **URL**: https://apify.com/steadyfetch/instagram-account-search-scraper.md
- **Developed by:** [Steadyfetch Team](https://apify.com/steadyfetch) (community)
- **Categories:** Social media, Lead generation, Automation
- **Stats:** 1 total users, 0 monthly users, 0.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $3.00 / 1,000 accounts

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 Account Search — Find Accounts with Business Contacts

**Instagram account search and Instagram user search by keyword or hashtag: type "dentist miami" or "#bakery" and get the accounts behind it, then read each one in full for the email, phone and city a business publishes on its own profile. $3.00 per 1,000 accounts; the full read is $2.30 per 1,000 more from Silver up.**

Type search phrases, hashtags, or both. Each one is a search, and every account it finds comes back as one row: handle, name, profile link, verified and private flags, and the keyword or hashtag that found it. Switch on **"Read each account in full"** and the same row adds followers, following, posts, business and creator flags, category, bio, website and the public contact block. No login, no cookies, no proxy to set up. A search that finds nothing, and a read that did not go through, are never charged, and nothing is charged for starting a run.

**Using an AI agent?** Pin this actor in Apify's MCP server with one link: `https://mcp.apify.com?tools=steadyfetch/instagram-account-search-scraper`

- **Actor id:** `steadyfetch/instagram-account-search-scraper`
- **Input:** `{ "keywords": ["dentist miami"], "maxAccounts": 30, "enrichContacts": true }` — `keywords` or `hashtags` is the one field you have to set.
- **Cap the bill:** set `maxTotalChargeUsd` on the run (a run option, not Actor input), e.g. `0.50` — the run stops when it reaches it.
- **Price:** $0.003 per account found and delivered; the full read is $0.006 per account on the Apify free plan, $0.0055 on Bronze and $0.0023 from Silver, only when you ask for it. Full table below.
- **How often it changes:** search results shift week to week as accounts grow, post and rename; contact fields change only when the owner edits them. Re-running the same searches weekly with "New accounts only" on delivers just the accounts you have not had.

*Unofficial. Not affiliated with, endorsed by, or sponsored by Instagram or Meta Platforms, Inc.*

### What you get

One row per account:

| Column | What it holds |
|---|---|
| `username` · `userId` · `profileUrl` · `fullName` | who the account is |
| `isVerified` · `isPrivate` | the two flags Instagram's search shows |
| `foundBy` · `foundByType` | the keyword or hashtag that found it |
| `followersCount` · `followingCount` · `postsCount` | the counts — full read only |
| `isBusiness` · `isProfessionalAccount` · `category` | what kind of account it is — full read only |
| `biography` · `externalUrl` · `bioLinks` | the bio and its links — full read only |
| `publicEmail` · `publicPhoneNumber` · `publicPhoneCountryCode` · `contactPhoneNumber` · `whatsappNumber` · `cityName` · `addressStreet` · `zip` | the contact block the account publishes on its own business profile — full read only, `null` when the account does not publish it |
| `charged` · `chargedEvents` · `status` · `statusReason` | what the row was charged, and why it says what it says |

Every column is always present. A column the search does not return is `null` on a row that was not read in full, never missing. Nothing is guessed: every contact field is exactly what the account holder published, and an account that publishes none has none. Across three business niches (a trade, a bakery and a fitness studio search), about half of the accounts read in full published an email or a phone number.

**Two ways to search:**

- **Keywords** run Instagram's own account search, the same list the search box shows. One phrase usually runs dry at about 30 accounts, so use several specific phrases ("dentist miami", "pediatric dentist miami") rather than one broad one.
- **Hashtags** return the accounts behind the tag's top posts, each account once. Tags go deeper than a phrase search.

An account two of your terms both find is delivered once, under the first one, and charged once.

### What a row looks like

```json
{
  "username": "sample_bakery_2",
  "fullName": "Sample Bakery 2",
  "profileUrl": "https://www.instagram.com/sample_bakery_2/",
  "isVerified": true,
  "isPrivate": false,
  "foundBy": "bakery",
  "foundByType": "keyword",
  "followersCount": 12840,
  "followingCount": 312,
  "postsCount": 486,
  "isBusiness": true,
  "category": "Bakery",
  "biography": "Sourdough every morning. Orders by email.",
  "externalUrl": "https://bakery.example/",
  "publicEmail": "hello@bakery.example",
  "publicPhoneNumber": "5550100",
  "publicPhoneCountryCode": "1",
  "cityName": "Sample City",
  "enriched": true,
  "charged": true,
  "chargedEvents": { "account": 1, "enriched-account": 1 },
  "status": "delivered"
}
```

### Price

You pay per event, and only for what was delivered:

| Event | When it is charged | Apify free plan | Bronze | Silver and up |
|---|---|---|---|---|
| `account` | each new account found and delivered | $0.003 | $0.003 | $0.003 |
| `enriched-account` | each account read in full, only when the read came back (opt-in) | $0.006 | $0.0055 | $0.0023 |
| `check` | once per keyword or hashtag, only when a repeat search found nothing new for you | $0.004 | $0.004 | $0.004 |

Examples: 30 accounts from one search is $0.09. The same 30 read in full is $0.159 from Silver up, $0.255 on the Apify free plan. No start fee, ever.

### Re-run the same searches without paying twice

Every run remembers, in a key-value store in your own Apify account (`ig-account-search-account`), which accounts it delivered under which search. With **"New accounts only"** on (the default), a later run of the same keyword or hashtag skips those accounts: no row and no charge, and the next new account takes the slot. Accounts older than 90 days in that memory count as new again.

When a repeat search reads its pages and every account on them is one you already have, that term's row says so and is charged one **check** ($0.004), once, for the read. A first search is never charged a check, nor is a search that returns nothing, a search a limit of yours cut short, or any run with "New accounts only" off. Turn it off and the accounts you already have come back again, marked `repeat: true`, with no result fee.

### Honest rows: what "not charged" actually means

Every keyword or hashtag that returns fewer accounts than you asked for gets one row saying which of these happened:

- `nothing_found` — the search returned no accounts, Instagram has no such hashtag, or it returned all it had.
- `already_delivered` — the search kept returning accounts you already have, so the run stopped paying for pages of them (the one row that may carry a check, and it says so).
- `your_limit_reached` — your own limit (accounts per term, maximum cost, run seconds) stopped it.
- `limit_reached` — this actor's own page limit for one term, or this run reached its limit; the row says which.
- `plan_limit_reached` — the Apify free plan's daily allowance for this actor; the row says when it resets.
- `try_again` — the read did not go through; a re-run is the fix.
- `not_accepted` / `not_supported` — an input value it cannot use, or an answer this actor does not read yet; the row says what.

Apart from a check named on its own row, none of these is charged, and the run still finishes successfully. A time limit ends the collecting, never the delivering: accounts already in hand are always written out. The last row is the run's own summary: what was delivered, what was asked for, and what stopped it. Results may fail when Instagram changes; failed items are never charged.

### How often this data changes

Search rankings move with Instagram's own activity, so a phrase finds a slightly different list each week. Follower and post counts move daily on an active account. The bio, website and contact block change only when the owner edits them, often not for months. For lead lists, a weekly run of the same searches with "New accounts only" on is what most buyers need.

### Use it as an API endpoint (Standby)

Every input above also works as one HTTP request to this actor's endpoint (also on its Endpoints tab), by GET with the fields in the query string or by POST with the same fields as a JSON body:

```bash
curl -H "Authorization: Bearer <YOUR_APIFY_TOKEN>" \
  "https://steadyfetch--instagram-account-search-scraper.apify.actor/?keywords=bakery&maxAccounts=20&enrichContacts=true"
```

| Setting | What it does |
|---|---|
| `keywords` | A search phrase. Repeat it for more than one. |
| `hashtags` | Instagram hashtags, with or without the #. Repeat it or separate with commas for more than one. |
| `maxAccounts` | How many accounts for each term. 50 if you leave it out. |
| `enrichContacts` | `true` reads every account in full (counts, category, bio, website, public contacts). |
The accounts come back in the response as JSON, with the same columns as a dataset row, charged per account (and per full read) at the same prices as a run. One request takes up to 10 terms at 50 accounts each (3 terms at 20 on the Apify free plan). The endpoint keeps no memory of what you already have, so every request reads fresh and no check is ever charged there. A request that returns no accounts is not charged; if a request's charge cannot be completed, its accounts are not sent.

### Limits and good manners

- **Max accounts per term:** 50 by default, up to 200. Above that the run continues at 200 and one uncharged row says so.
- **Pages per term:** at most 12, and a term stops after two pages in a row that added nothing new.
- **Handles are not this actor's input.** It finds accounts; to read accounts you already know by handle or link, use the Instagram Bio Scraper. A handle list sent here is refused on an uncharged row that says so.
- Only public data: what Instagram shows any visitor. Private accounts appear in search with their flag set; their posts are never read.

### Related actors

- [Instagram Bio Scraper](https://apify.com/steadyfetch/instagram-profile-details-scraper) — the full record of accounts you already know, by handle or link.
- [Instagram Hashtag Scraper](https://apify.com/steadyfetch/instagram-hashtag-scraper) — the posts under a hashtag or keyword.
- [Instagram Followers Scraper](https://apify.com/steadyfetch/instagram-followers-scraper) — who follows an account.
- [Instagram Similar Profiles Scraper](https://apify.com/steadyfetch/instagram-similar-profiles-scraper) — the accounts Instagram suggests next to one you know.

### Reliability

Every row says what it was charged. A read that fails is tried again before it is reported; a row that cannot be delivered is never charged; and the run never ends on a limit it set itself without saying so on the last row.

### Support

Questions, a search that returns something odd, or a column you need: open an issue on the Issues tab and it will be looked at.

If it earned its keep, a rating helps other buyers find it, and saving the actor keeps it one click away.

# Changelog

This Actor's version history is a separate document: https://apify.com/steadyfetch/instagram-account-search-scraper/changelog.md

# Actor input Schema

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

Search phrases, one per line — "dentist miami", "vegan bakery", "yoga studio london". Each returns the accounts Instagram's own account search ranks for that phrase, the same list the search box shows. A phrase that returns nothing, and a read that did not go through, come back as labelled rows and are never charged. A profile link is refused with a row pointing to the Instagram Bio Scraper, which reads accounts you already know. Leave Keywords and Hashtags both empty and the run returns built-in sample rows instead, so you can see the output shape at no result fee.

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

Instagram hashtags, one per line — "bakery", "#bakery" or an https://www.instagram.com/explore/tags/bakery/ link. Each returns the accounts behind the tag's top posts, each account once. A hashtag Instagram has nothing under comes back as a labelled row and is never charged. Leave empty if you only want keyword searches.

## `maxAccounts` (type: `integer`):

Hard cap on the accounts delivered for EACH keyword or hashtag — 30 across 3 terms delivers up to 90. Instagram's account search usually runs dry around 30 accounts for one phrase; hashtags go deeper. A term that runs short leaves an uncharged row saying so. At most 200 per term: ask for more and the run continues at 200, with one uncharged row saying so, rather than being refused.

## `enrichContacts` (type: `boolean`):

OFF (default): each account row carries what the search returns — handle, display name, profile link, private and verified flags — at $0.003 per account. ON: every new account is also read in full and the row adds followers, following, posts, business/creator flags, category, bio, website and links, and the public email, phone and city a business shows on its own profile (blank when the account does not publish them). Charged as enriched-account: $0.006 per account on the Apify free plan, $0.0055 on Bronze, $0.0023 from Silver — only when the read came back. An account whose read did not come through still delivers its search row and is not charged for the read.

## `newAccountsOnly` (type: `boolean`):

ON (default): an account already delivered to you under the same keyword or hashtag is skipped — no row, no charge — and the next new account takes its place. When a repeat search finds nothing new at all, that term is charged one check ($0.004) for the read, once, and its row says so; a first search, an empty search and a search this run's own limit cut short are never charged a check. OFF: accounts you already have are handed back again, marked repeat: true, with no result fee and no fresh full read, and no check is charged. Accounts older than 90 days in your memory count as new again.

## `maxRunSeconds` (type: `integer`):

The run stops cleanly before this many seconds and reports what is left, instead of being killed by a timeout. A time limit ends the collecting, never the delivering: accounts already in hand are always written out, and accounts the clock does not reach are not charged. Between 30 seconds and 1 hour: set it outside that and the run continues at the nearest one, with one uncharged row saying so.

## `resumeFromDatasetId` (type: `string`):

The dataset ID of a previous run of this actor. Accounts already in it are treated as accounts you already have and are skipped, so a follow-up run delivers only new ones, even from a different Apify account. Selecting it here is what grants this run permission to read it.

## Actor input object example

```json
{
  "keywords": [
    "bakery"
  ],
  "hashtags": [],
  "maxAccounts": 50,
  "enrichContacts": false,
  "newAccountsOnly": true,
  "maxRunSeconds": 1800
}
```

# Actor output Schema

## `accounts` (type: `string`):

One row per account delivered: username, name, profile link, verified and private flags, and the keyword or hashtag it was found by. Rows read in full ("Read each account in full" on) add followers, following, posts, business/creator flags, category, bio, website and the public email, phone and city the business shows on its own profile — blank when the account does not publish them. Every row carries `charged`, `chargedEvents` and `status`, so the invoice reconciles from the dataset itself: `account` ($0.003) on every account delivered new, `enriched-account` ($0.006 on the Apify free plan, $0.0055 on Bronze, $0.0023 from Silver) only on a row whose full read came back, and `check` ($0.004) only on the one row of a term that a repeat search found nothing new for. Accounts you already have under the same search are skipped and never charged again — that check reads a key-value store in your own account, so a run on a scoped API token without key-value store permission says so on its status line and on an uncharged row; with "New accounts only" off they come back marked `repeat: true`, uncharged.

## `misses` (type: `string`):

One row for every keyword or hashtag that returned less than it was asked for, with `status` saying which: `nothing_found` (the term returned no accounts, or Instagram has no such hashtag), `already_delivered` (the search kept returning accounts you already have — the one row that may carry the $0.004 `check`, and it says so), `limit_reached` (this actor's own page limit for one term, or this run reached its limit), `your_limit_reached` (your own result limit, cost limit or run clock stopped it first), `plan_limit_reached` (the Apify free plan's daily allowance), `try_again` (the read failed and a re-run is the fix), `not_accepted` (an input value or a refused search), `not_supported` (Instagram answered in a shape this actor does not read yet). Apart from a check named on its own row, none of these is charged.

## `summary` (type: `string`):

Accounts delivered, what was asked for, accounts read in full, accounts your account already had, accounts found under more than one of your terms, checks charged, what stopped the run, the charged-event totals, and — when this run's token could not open the repeat memory — `repeatCheck: "unavailable_scope"`.

# 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": [
        "bakery"
    ],
    "hashtags": []
};

// Run the Actor and wait for it to finish
const run = await client.actor("steadyfetch/instagram-account-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": ["bakery"],
    "hashtags": [],
}

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

```

## MCP server setup

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