# Instagram User Search Scraper: Profiles by Keyword (`automation_craft/instagram-user-search-scraper`) Actor

Instagram user search by keyword, no login: accounts from Threads' user search, Meta's Ad Library and Instagram's reel creators for each niche, trade or place. Rows carry followers, posts, bio, links, category, engagement and the linked Facebook Page; 24 filters. JSON, CSV or API; pay per profile.

- **URL**: https://apify.com/automation_craft/instagram-user-search-scraper.md
- **Developed by:** [Automation Craft](https://apify.com/automation_craft) (community)
- **Categories:** Social media, Lead generation, Marketing
- **Stats:** 3 total users, 2 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $1.33 / 1,000 profiles

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 User Search Scraper: Profiles by Keyword

**Find Instagram accounts by keyword** and get every public account Meta's own searches show for your words, read on Instagram
with its followers, following, posts, bio, links, category, account type, recent posts and engagement, without an Instagram
account, cookies or login. Give a niche, a trade, a brand or a place ("coffee roaster", "wedding photographer miami", "vegan
bakery"), a list of usernames, or post links, and get one row per account plus a free row per keyword that says what each search
found and why the work stopped.

- **Three searches per keyword, merged.** Threads' user search (accounts whose name or username matches, about 100 a search),
  Meta's Ad Library search (businesses with a Facebook Page and their Instagram account, up to 15 a search) and Instagram's
  popular reels search (the creators of 24 reels about your words, up to about 96 reels with more pages). On request: the
  keyword's name variants and the accounts Instagram suggests next to the ones found, one or two levels deep, for keywords,
  username lists and post links.
- **Every account read on Instagram.** Exact followers and following, post count, bio, website and bio links, category, account
  type (personal, business, creator), verified, private, Threads profile, highlights, the linked Facebook Page, the 6 newest
  posts with likes and comments, and engagement figures computed from them.
- **24 filters that cost nothing.** Followers, posts, verified, account type, influencers only, words in the name, bio or posts,
  category, language, place words, an e-mail or a phone shown, a website, engagement rate, posting activity, reel plays and more.
  Accounts a filter leaves out are never charged.
- **Add-ons when you need them.** Reel figures (median plays of the 12 newest reels), profile info (the business address, joined
  recently) and the linked Facebook Page's public contact (e-mail, phone, website, address, hours).
- **Fair billing.** Each account is charged once per run, even when several keywords or searches find it. Searches that find
  nothing, accounts Instagram does not show logged out, failed calls, repeats and refused entries are free rows.

### Quick start

1. Open the Actor's **Input** tab and type your keywords, one per line (for example `coffee roaster`, `yoga studio`,
   `wedding photographer miami`), or paste usernames or post links.
2. Set **Max profiles per keyword** (the searches together list up to about 140 accounts a keyword; variants and suggested
   accounts find more).
3. Optional: add filters (minimum followers, account types, words that must be in the bio, a contact shown) or the add-ons.
4. Click **Start**. Each account arrives as a row of the dataset, followed by one free row per keyword and a run summary.
5. Download the dataset as JSON, CSV or Excel, or read it through the Apify API, a schedule, Make, n8n or Zapier.

### What you get

One `profile` row per account. The fill rates below were measured on 392 distinct accounts read on the platform on 2026-10-28
(the 30 checking runs of the released build).

| Field | What it holds | Filled |
|---|---|---|
| `keyword`, `searchedAs`, `foundVia`, `rank` | your keyword, the text searched, how the account was found (`threads`, `ad_library`, `reel_creator`, `threads_variant`, `related_profile`, `username`, `commenter`), its place in the keyword's merged list | 100% |
| `username`, `id`, `url`, `fullName` | the account's username, Instagram id, link and name | 100%, name 99.2% |
| `biography` | the bio as Instagram serves it | 97.2% |
| `followerCount`, `followingCount`, `followerToFollowingRatio` | exact followers and following, and their ratio | 100% |
| `postsCount` | the post count (private accounts show none) | 95.7% |
| `accountType`, `isProfessional`, `category` | `personal`, `business` or `creator`, and the category the account shows | 100%, category 58.2% |
| `isVerified`, `isPrivate`, `isMemorialized`, `isMetaVerified` | the badges and states Instagram serves | 100% (verified 29.8%, private 1.5%) |
| `externalUrl`, `bioLinks` | the website and the bio links (title, link, type) | 77.8%, 81.4% |
| `profilePicUrl`, `profilePicUrlHd` | the picture, small and full size | 100% |
| `threadsUsername`, `threadsUrl` | the account's Threads profile | 66.8% |
| `highlightTitles`, `latestStoryAt`, `hasPublicStory`, `hasReels`, `reelsCount`, `pronouns` | story highlights, the latest story, reels | 86.7%, 56.4%, reels count 93.9% |
| `facebookPage` | the Facebook Page the account links: `id`, `name`, `alias`, `url`, and for Ad Library finds `category`, `likes`, `country` | 27.3% |
| `recentPosts`, `recentPostTimes` | the 6 newest posts: link, type, date, likes, comments, caption, pinned, paid partnership, place | 94.1% |
| `avgLikes`, `avgComments`, `engagementRate`, `engagementGrade`, `postsPerWeek`, `lastPostAt` | engagement of the newest posts (likes plus comments over followers, in percent; grade `high` from 3%, `average` from 1%, else `low`), the posting pace and the newest post | 90.3%, last post 94.1% |
| `biographyLanguage` | the language of the bio and recent captions, our own estimate (see the FAQ) | 81.4% |
| `keywordMatch`, `matchedTerms` | how the username, name and bio hold your keyword's words: `all`, `some` or `none` | 100% (`all` 79.4%) |
| `hasEmail`, `hasPhone` | whether the bio, bio links or recent captions show an e-mail address or a phone number | 8.4%, 13.3% |
| `emails`, `phones` | those addresses and numbers with where each was found: empty unless you turn on **Include personal data** | when asked |
| `reelStats` | add-on: `reelsRead`, `medianPlays`, `averagePlays`, `maxPlays`, `newestReelCreatedAt`, `medianPlaysToFollowersPercent` | when asked |
| `businessAddress`, `businessContactMethod`, `joinedRecently`, `businessCategory`, `isBusinessAccount`, `highlightCount`, `hasGuides`, `hasChannel`, `igtvVideoCount`, `facebookId` | add-on: profile info, read when Instagram answers that read (`profileInfoStatus` says when it did not); Instagram limits this read hard, so expect it on about a quarter of the accounts (131 of 500 on 2026-10-28) | when asked |
| `facebookPageContact` | add-on: the Facebook Page's public `emails`, `phones`, `whatsapp`, `websites`, `addresses`, `hours`, `priceRange`, `services`, `categories`, `ratings` | when asked |
| `relatedProfiles` | add-on: the accounts Instagram suggests next to this one (often none logged out); needs **Include personal data** | when asked |
| `commentsOnPost` | for post links: how many of the comments read the account wrote | post links |

Example row (from a run on `coffee roaster`; recent posts cut short):

```json
{
  "type": "profile",
  "keyword": "coffee roaster",
  "foundVia": "ad_library",
  "rank": 2,
  "username": "origincoffeeroasters",
  "url": "https://www.instagram.com/origincoffeeroasters/",
  "fullName": "Origin Coffee",
  "biography": "Progressive coffee\nProudly B Corp\nBorn in Cornwall",
  "followerCount": 101231,
  "followingCount": 1426,
  "postsCount": 2144,
  "accountType": "business",
  "isVerified": false,
  "externalUrl": "https://linktr.ee/origincoffeeroasters",
  "facebookPage": { "id": "109396825744233", "name": "Origin Coffee Roasters", "alias": "origincoffeeroasters", "category": "Coffee shop", "likes": 15035 },
  "keywordMatch": "all",
  "matchedTerms": ["coffee", "roaster"],
  "avgLikes": 231.3,
  "avgComments": 8.7,
  "engagementRate": 0.237,
  "engagementGrade": "low",
  "lastPostAt": "2026-10-26T17:00:03.000Z",
  "postsPerWeek": 2.19,
  "recentPosts": [{ "url": "https://www.instagram.com/p/De9xQ3hiKTS/", "postedAt": "2026-10-26T17:00:03.000Z", "likeCount": 164, "commentCount": 2 }],
  "emails": null,
  "phones": null
}
```

**The subject row (free).** One per keyword (and one for the account list, one per post link): its `status` (`ok`,
`no_accounts`, `no_matching_accounts`, `failed`, `stopped`), `finished`, `stopReason`, how many accounts were found, read,
delivered and left out by each check (`leftOut`), and every search with the text sent and the accounts it found. The last row of
every run is a free `summary` row with the run's counts.

### How much does it cost to scrape Instagram profiles?

You pay per result (pay per event). Prices per 1,000 events:

| Event | Free | Bronze | Silver | Gold |
|---|---|---|---|---|
| Profile (one account delivered as a row, with its details) | $1.86 | $1.70 | $1.54 | $1.33 |
| Basic profile (one account without details, when details are off) | $0.40 | $0.36 | $0.32 | $0.28 |
| Facebook Page contact (add-on, a linked Page that shows contact details) | $2.10 | $1.92 | $1.74 | $1.50 |
| Re-filtered profile (a profile of an earlier run that passes this run's filters) | $0.10 | $0.09 | $0.08 | $0.07 |

Platinum and Diamond plans pay the Gold price. Each run also pays the Actor start event of $0.0075 (256 MB), which has no plan
discount. The Store pricing card shows these same prices per 1,000 events: "$1.33 / 1,000" on the Profile row means one profile
costs about a seventh of a cent.

Examples at the Gold price: 50 profiles of one keyword cost $0.0075 + 50 x $0.00133 = $0.074; 1,000 profiles of twenty keywords
cost $0.0075 + 1,000 x $0.00133 = $1.34; the same 1,000 with the Facebook Page contact read for the 200 of them whose Page shows
one add 200 x $0.0015 = $0.30.

Free: subject rows, status rows, left out rows, the summary, accounts another keyword of the run already delivered, accounts a
filter leaves out, accounts Instagram does not show logged out, accounts whose recent posts could not be read (a failed read,
or embeds switched off by a public account: delivered free with `detailsStatus` `partial`), Facebook Pages without contact details, searches that find nothing, failed calls, refused
entries and invalid input. An invalid input charges only the run's start fee.

### Input

| Setting | What it does | Default |
|---|---|---|
| `keywords` | words or phrases, up to 500 (see below) | none |
| `usernames` | accounts to read directly: usernames, @handles, profile links or numeric ids, up to 5,000 | none |
| `postUrls` | post or reel links: the authors of their public comments are read, up to 100 links | none |
| `maxProfilesPerKeyword`, `maxProfiles` | the most profiles of one keyword or post link (1 to 1,000), and of the run | 50, none |
| `maxCommentersPerPost` | the most distinct comment authors collected from one post | 50 |
| `searchThreads`, `searchAdLibrary`, `searchReelCreators` | which searches a keyword runs | all on |
| `reelSearchPages` | pages of the reels search read for its creators (1 to 8: 24 reels, then about 50 a page, about 96 in all; one search call a page) | 1 |
| `adLibraryCountry` | the country the Ad Library search favours (`ALL` or a two letter code in capitals, such as `US`) | `ALL` |
| `searchVariants` | also search Threads for the keyword's joined, underscored and dotted forms (`coffeeroaster`, `coffee_roaster`, `coffee.roaster`) | off |
| `expandWithRelatedProfiles`, `expansionDepth` | also deliver the accounts Instagram suggests next to each profile a keyword, a username list or a post link delivered (`foundVia` `related_profile`), one level or two (level 2 expands the accounts level 1 delivered); a username list's suggested accounts count against `maxProfilesPerKeyword`; Instagram suggests accounts for about 13 of 100 profiles logged out | off, 1 |
| `includeDetails` | read each account on Instagram (off: basic rows from the search only, billed as Basic profile) | on |
| `includeRecentPosts` | put the 6 newest posts on the row (engagement is computed either way) | on |
| `includeReelStats` | the reel figures (one more read per account, included in the Profile price) | off |
| `includeProfileInfo` | the profile info (one more read per account, included in the Profile price) | off |
| `includeFacebookPageContact` | the Facebook Page contact add-on | off |
| `includeRelatedProfiles` | the suggested accounts on the row (needs **Include personal data**) | off |
| `minFollowers`, `maxFollowers`, `minPosts`, `maxPosts` | follower and post count bands | none |
| `verified`, `accountTypes`, `influencersOnly`, `includePrivate` | verified only or not verified, account types (`professional` = business or creator), creators and influencer categories only, private accounts in or out | any, any, off, in |
| `requireKeywordMatch` | keep only accounts whose username, name or bio holds every word of the keyword | off |
| `mustContain`, `mustContainIn` | words that must appear, and where: username, name or bio (default), bio, name, recent captions, anywhere | none |
| `excludeWords` | leave out accounts whose username, name or bio holds any of these words | none |
| `categories`, `combineCategoryAndWords` | Instagram categories to keep (any of, whole words), and whether categories and `mustContain` must both pass or either | none, both |
| `languages` | keep only accounts whose bio and recent captions read as these languages (44 two letter codes) | any |
| `locationMustContain` | place words in the bio, the business address (with profile info) or the Facebook Page country | none |
| `contactFilter`, `requireWebsite` | a contact shown (an e-mail or a phone, an e-mail, a phone, both) and a website | any, off |
| `minEngagementRate`, `activeWithinDays`, `minRecentPosts`, `recentPostsDays` | engagement rate floor (percent), newest post within days, at least N of the 6 newest posts within days | none, none, none, 30 |
| `minMedianReelPlays`, `reelPostedWithinDays`, `minPlaysToFollowersPercent`, `maxPlaysToFollowersPercent` | reel filters (need **Reel figures**) | none |
| `excludeUsernames` | accounts never to deliver, up to 10,000 | none |
| `minMatchRatePercent` | stop the run once 100 accounts were judged and fewer than this percent passed your filters | none |
| `includeLeftOutAccounts` | a free row for every account read and left out, with the reason | off |
| `refilterDatasetId` | check an earlier run's profiles again with this run's filters, without reading Instagram (Re-filtered profile); rows saved without details carry no id and no bio, so with id or bio word exclusions they are left out (free); on a re-filter alone the options that read Instagram or Facebook are refused, and reel filters judge the reel figures the rows carry | none |
| `includePersonalData` | fill `emails`, `phones` and `relatedProfiles`, and keep links to Instagram, Facebook, Messenger, Threads or WhatsApp and contact links (mailto, tel, sms, callto, Telegram, Signal, Viber, Skype) in the website and bio links | off |
| `maxRunSeconds`, `requestTimeoutSecs`, `maxRetries` | a time limit, the request timeout (5 to 60 s) and retries per request (0 to 5) | none, 30, 2 |
| `proxyConfiguration` | Apify Proxy setting (see below) | Apify Proxy |

**Keywords.** A word or phrase in any language; a leading # is dropped. Each keyword is searched lower cased. Threads' user search
matches account names and usernames loosely and finds accounts that use Threads; for a phrase with a place, few accounts carry
every word (on "real estate agent miami", 8 of the 118 readable accounts the three searches found held every word in their username, name or bio), so use
**Every keyword word in the account** or **Place words** for a strict list. An entry that is empty, a link, starts with @ (put
accounts in usernames), looks like a token or API key, or repeats an earlier keyword is refused with one free row per reason that
names its position (the value is never shown); the other keywords run.

**Proxy.** By default the Actor reads from its own server address first and moves a request type to Apify's datacenter proxy
when it is refused there. Choose a proxy group or country to read only through Apify Proxy, or give your own proxy links. A
residential group is read through the datacenter pool instead, at no extra cost, and a free status row says so.

**Work that earns nothing.** Searches that find nothing, filters no account passes and calls that are answered badly cost time but
deliver nothing. A run spends at most a small fixed amount of such work before its first charged profile, and more as it
delivers; when it is spent the run stops with the stop reason `work_allowance` and a free `skipped` row naming the entries not
searched. Measured on the platform: about 40 accounts read and left out before the first charged profile, and about 13 more for
each profile delivered; 150 keywords that find nothing stopped after 22 and after 30 of them in two runs, the rest skipped. A filter set that passes fewer than about one account in 13 (a rare language, a very high follower
minimum) therefore ends early: loosen a filter, or start from keywords closer to the accounts you want. A round of account reads that
Instagram keeps failing (half the reads of two rounds in a row) stops the run as `source_failing`, and the run's status message
names the failing side.

#### Filters

Every filter is judged once, on the row as it will be delivered; an account a filter leaves out is free (with
**Left out accounts** on, a free `left_out` row says which filter). **Influencers only** keeps creator accounts and accounts whose
category is one of these 34: Digital creator, Video creator, Gaming video creator, Blogger, Personal blog, Public figure, Artist, Musician, Musician/band, Athlete, Fitness model, Fashion model, Model, Actor, Comedian, Writer, Author, Photographer, Gamer, Dancer, Chef, Entrepreneur, Coach, Personal coach, Fitness trainer, Makeup artist, Podcast, Journalist, News personality, Motivational speaker, DJ, Producer, Designer, Fashion designer.

**Languages** accepts these 44 two letter codes (any other code refuses the run, which then charges only its start fee): en, es, pt, fr, de, it, nl, pl, tr, ru, uk, ar, fa, ur, hi, bn, mr, ta, te, gu, kn, ml, pa, ne, id, ms, tl, vi, th, ja, ko, zh, sw, ro, hu, cs, sv, el, bg, sr, hr, az, uz, kk.

### API examples

```bash
curl -X POST "https://api.apify.com/v2/acts/automation_craft~instagram-user-search-scraper/run-sync-get-dataset-items?token=YOUR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"keywords": ["coffee roaster", "yoga studio"], "maxProfilesPerKeyword": 30, "minFollowers": 1000}'
```

```javascript
import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: 'YOUR_TOKEN' });
const run = await client.actor('automation_craft/instagram-user-search-scraper').call({ keywords: ['wedding photographer miami'], requireKeywordMatch: true, accountTypes: ['professional'] });
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.filter((row) => row.type === 'profile').map((row) => row.username));
```

```python
from apify_client import ApifyClient
client = ApifyClient("YOUR_TOKEN")
run = client.actor("automation_craft/instagram-user-search-scraper").call(run_input={"keywords": ["vegan recipes"], "influencersOnly": True, "minEngagementRate": 1})
for row in client.dataset(run["defaultDatasetId"]).iterate_items():
    if row["type"] == "profile":
        print(row["username"], row["followerCount"], row["engagementRate"])
```

### What this Actor does NOT do

- **No follower or following lists, no likers.** Instagram shows them only to logged in viewers; this Actor reads logged out only.
  Commenters of a post are public and are read (post links).
- **No Instagram search box results, hashtag search or place search.** Instagram's own account search and its hashtag feeds need a
  login; a #hashtag keyword is searched as its word on the three searches above. Accounts by place come from place words in the
  keyword and the place filter, not from a place's feed.
- **No search engine results and no AI.** The Actor reads only Meta's own pages: no Google or other search engine, and no outside
  AI service (no AI scoring or natural language search).
- **No business e-mail or phone of Instagram's contact button, no account creation date or country, no WhatsApp linked flag and no
  private collections.** A logged out reader does not get them; the bio, bio links, recent captions and the linked Facebook Page's
  contact are read instead.
- **No pages outside Meta.** The website a bio links to is not opened, and no e-mail address is verified against its mail server.
- **No posts, reels or comments of the accounts as rows of their own**, beyond the 6 newest posts and the reel figures on each
  row.
- **No monitoring across runs.** There is no memory of earlier runs, no "new accounts only" mode and no rising creators (a jump
  in followers between runs); pass the accounts you already have in **Accounts to leave out** and schedule runs as you like.
- **No delivery into other apps and no custom code.** The Actor writes only to its own dataset: it has no input that pushes rows
  into Notion, Todoist or other apps through connectors (Apify's integrations, webhooks and the API deliver the dataset anywhere),
  and it runs no mapping function you send.
- **No logins, cookies or accounts of yours.**
- **No more than Meta's searches list.** About 100 accounts per Threads search, up to 15 per Ad Library search, the creators of
  about 96 reels per reels search (24 on its first page, the default); variants, more reel search pages and suggested accounts
  widen a keyword.

### FAQ

#### How do I find Instagram accounts by keywords in their bio?

Give the keywords and the Actor finds accounts for each one on Threads' user search, Meta's Ad Library and Instagram's reel
creators, then reads every account's bio. **Must contain any of** keeps the accounts whose bio (or name, or recent posts) holds
your words.

#### How do I find Instagram influencers in my niche?

Search your niche ("vegan recipes", "fitness coach"), then keep creator accounts with **Influencers only** and set followers,
engagement rate and posted within days; every account a filter leaves out is free.

#### How do I find Instagram accounts in a specific city?

Put the place in the keyword ("wedding photographer miami") and add the city to **Place words**: the Actor keeps accounts that name
it in their bio, their business address (with profile info) or their Facebook Page country. **Every keyword word in the account**
keeps only accounts holding every word of the keyword.

#### Can you search Instagram without an account?

This Actor does. It reads Meta's public searches and each account's public profile data without an account, cookies or login, so
your own Instagram account is never involved.

#### Is there an Instagram search API?

Instagram's user search endpoint for developers was retired, and Meta's official API offers hashtag search only to Business or
Creator accounts. This Actor works as an account search API through the Apify API, schedules, Make, n8n or Zapier.

#### How is the language of an account estimated?

Instagram serves no language for an account, so the Actor estimates it from the bio and each recent caption with the franc library
(a text of 40 letters or more with a clear result) and takes the language most of them agree on; a tie or nothing clear gives no
language, and the language filter leaves such accounts out.

#### Why does this Actor run with limited permissions?

It needs no more: it reads Meta's public pages and writes only to its own run's dataset and key-value store, so it cannot touch
anything else in your Apify account. Filtering an earlier run again reads that run's dataset, in your own account, by its id.

### More data tools by Automation Craft

- [Instagram Posts Scraper: Profiles, Reels, No Login](https://apify.com/automation_craft/instagram-posts-scraper)
- [Threads Profile Scraper: Followers, Bio, Posts](https://apify.com/automation_craft/threads-profile-scraper)
- [Facebook Page ID Finder: Names to Page IDs](https://apify.com/automation_craft/facebook-page-id-finder)
- [Facebook Search Scraper: Keyword Posts, No Login](https://apify.com/automation_craft/facebook-search-scraper)
- [Meta Branded Content Scraper: Paid Partnerships](https://apify.com/automation_craft/meta-branded-content-scraper)
- [TikTok Hashtag Scraper: Posts, Free Date Filter](https://apify.com/automation_craft/tiktok-hashtag-scraper)

### Changelog

See the Changelog tab: 0.1 (2026-10-28) is the first release.

# Changelog

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

# Actor input Schema

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

Words or phrases to find Instagram accounts by, one per line (up to 500): a niche, a trade, a brand or a place ("coffee roaster", "wedding photographer miami", "vegan bakery"). Each keyword is searched on Threads' user search (accounts whose name or username matches), Meta's Ad Library search (businesses with a Facebook Page) and Instagram's reels search (creators of matching reels). A leading # is dropped. Put accounts in usernames and post links in postUrls.

## `usernames` (type: `array`):

Instagram accounts to read directly (up to 5,000): usernames, @handles, profile links (instagram.com/<username>/) or numeric account ids. Each one gives its own profile row; an account Instagram does not show logged out gets a free note on the account list row.

## `postUrls` (type: `array`):

Instagram post or reel links (up to 100). The authors of each post's public comments are read as profiles, with commentsOnPost (how many of the comments read they wrote). Likers are not public logged out.

## `maxProfilesPerKeyword` (type: `integer`):

The most profiles delivered for one keyword (all its searches together) or one post link. Threads lists about 100 accounts a search, the Ad Library up to 15 and the reels search the creators of 24 reels a page; variants and suggested accounts find more.

## `maxProfiles` (type: `integer`):

Stops the run once this many profiles were delivered across all keywords, accounts and posts (read in the order given). Empty means no run limit.

## `maxCommentersPerPost` (type: `integer`):

For post links: the most distinct comment authors collected from one post before their profiles are read (about 15 comments a call).

## `searchThreads` (type: `boolean`):

Threads' user search: accounts whose name or username matches the keyword (about 100 a search). Finds accounts that use Threads; their Threads username is their Instagram username.

## `searchAdLibrary` (type: `boolean`):

Meta's Ad Library search: Facebook Pages matching the keyword that link an Instagram account (up to 15 a search), with the Page's id, category, likes and country on the row.

## `adLibraryCountry` (type: `string`):

The country the Ad Library search favours: ALL (default) or a two letter code in capitals such as US, GB or DE (local Pages come first).

## `searchReelCreators` (type: `boolean`):

Instagram's popular reels search for the keyword: the creators of its matching reels (24 on the first page; more with Reel search pages), accounts that post about the keyword. Broad single words list no reels.

## `reelSearchPages` (type: `integer`):

How many pages of Instagram's popular reels search to read for the reel creators: the first page lists 24 reels, each next one about 50, about 96 reels a search in all. One search call a page; more pages find more creators.

## `searchVariants` (type: `boolean`):

For a keyword of several words, also search Threads for its joined, underscored and dotted forms ("coffeeroaster", "coffee_roaster", "coffee.roaster"), which find accounts named that way (32 to 134 more accounts on six keywords measured). Three more searches a keyword.

## `expandWithRelatedProfiles` (type: `boolean`):

Read the accounts Instagram suggests next to each profile delivered for a keyword, a username list or a post link and deliver them too (foundVia related_profile, expansionLevel 1 or 2), up to that entry's cap (for a username list, Max profiles per keyword counts its suggested accounts). Logged out Instagram suggests accounts for about 13 of 100 profiles (67 of 500 measured).

## `expansionDepth` (type: `integer`):

With Suggested accounts on: 1 expands the profiles your keywords, usernames or post links delivered; 2 also expands the suggested accounts the first level delivered. Accounts found at the last level are not expanded.

## `includeDetails` (type: `boolean`):

On (default): every account is read on Instagram (followers, following, posts, bio, links, category, account type, recent posts, engagement) and billed as a Profile. Off: rows hold only what the search showed (username, name, verified flag; followers and the Facebook Page for Ad Library finds) and are billed as a Basic profile; filters that need details are refused.

## `includeRecentPosts` (type: `boolean`):

Adds the account's 6 newest posts (link, date, likes, comments, caption, pinned, paid partnership, place) to its row. Engagement figures are computed from them either way.

## `includeReelStats` (type: `boolean`):

Reads the account's 12 newest reels: median, average and highest play count and the newest reel's date (reelStats). One more read per account, no extra charge.

## `includeProfileInfo` (type: `boolean`):

Reads Instagram's profile info for each account: the business address (street, city, zip, coordinates) where the account shows one, the contact method, and whether it joined recently. One more read per account, no extra charge; Instagram limits this read hard and answers it for about a quarter of the accounts (profileInfoStatus says when it did not).

## `includeFacebookPageContact` (type: `boolean`):

For accounts that link a Facebook Page, reads the Page's public contact details (e-mail, phone, WhatsApp, website, address, hours, price range, services). Charged as one Facebook Page contact only when the Page shows an e-mail, a phone or WhatsApp number, a website, an address or its hours; a Page that shows only a price range, services or ratings is free.

## `includeRelatedProfiles` (type: `boolean`):

Adds the accounts Instagram suggests next to each profile (relatedProfiles; often none logged out). These name other accounts, so they need includePersonalData. One more read per account, no extra charge.

## `minFollowers` (type: `integer`):

Leave out accounts with fewer followers.

## `maxFollowers` (type: `integer`):

Leave out accounts with more followers.

## `minPosts` (type: `integer`):

Leave out accounts with fewer posts (private accounts show no post count and are left out by this filter).

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

Leave out accounts with more posts.

## `verified` (type: `string`):

Any account (default), verified accounts only, or unverified accounts only.

## `accountTypes` (type: `array`):

Keep only these account types (empty keeps every type). Professional means business or creator.

## `influencersOnly` (type: `boolean`):

Keep only creator accounts and accounts whose category is one of a list of people who publish for an audience (Digital creator, Video creator, Blogger, Public figure, Artist, Musician, Athlete, model, Writer, Photographer, Gamer, Chef, Coach and more; README "Filters").

## `includePrivate` (type: `boolean`):

Private accounts show their name, bio and counts but no posts. Off leaves them out (free).

## `requireKeywordMatch` (type: `boolean`):

Keep only accounts whose username, name or bio holds every word of the keyword (keywordMatch "all"). The searches match names loosely: for "real estate agent miami" 8 of the 118 readable accounts found carried every word.

## `mustContain` (type: `array`):

Keep only accounts that hold at least one of these words or phrases (whole words, any case; a word of four letters or more also counts inside the username) in the part mustContainIn names.

## `mustContainIn` (type: `string`):

Where mustContain looks: the username, name and bio (default), the bio only, the username and name only, the captions of the 6 recent posts, or anywhere.

## `excludeWords` (type: `array`):

Leave out accounts whose username, name or bio holds any of these words or phrases.

## `categories` (type: `array`):

Keep only accounts whose Instagram category holds one of these words ("photographer", "coffee shop"). Accounts without a category are left out.

## `combineCategoryAndWords` (type: `string`):

When both categories and mustContain are set: an account must pass both (default), or either one.

## `languages` (type: `array`):

Keep only accounts whose bio and recent captions read as one of these languages (two letter codes such as en, es, de; our own estimate, accounts we cannot tell are left out).

## `locationMustContain` (type: `array`):

Keep only accounts that name one of these places in their bio, their business address (with includeProfileInfo) or their Facebook Page country.

## `contactFilter` (type: `string`):

Keep only accounts that show this contact in their bio, bio links or recent captions: any account (default), an e-mail or a phone, an e-mail, a phone, or both. The addresses and numbers themselves are delivered with includePersonalData.

## `requireWebsite` (type: `boolean`):

Keep only accounts with a website or another link in their bio.

## `minEngagementRate` (type: `number`):

Keep only accounts whose engagement rate (average likes and comments of their 6 newest posts over followers, in percent) is at least this. Accounts without visible likes are left out.

## `activeWithinDays` (type: `integer`):

Keep only accounts whose newest post (pinned posts aside) is at most this many days old.

## `minRecentPosts` (type: `integer`):

Keep only accounts with at least this many of their 6 newest posts inside the last recentPostsDays days (1 to 6).

## `recentPostsDays` (type: `integer`):

The period minRecentPosts counts in, in days back from the run's start (default 30).

## `minMedianReelPlays` (type: `integer`):

Keep only accounts whose 12 newest reels have at least this median play count. Needs includeReelStats.

## `reelPostedWithinDays` (type: `integer`):

Keep only accounts whose newest reel is at most this many days old. Needs includeReelStats.

## `minPlaysToFollowersPercent` (type: `number`):

Keep only accounts whose median reel play count is at least this percent of their followers. Needs includeReelStats.

## `maxPlaysToFollowersPercent` (type: `number`):

Leave out accounts whose median reel play count is above this percent of their followers (one viral reel). Needs includeReelStats.

## `excludeUsernames` (type: `array`):

Accounts never to deliver (usernames, @handles, profile links or ids), for example the accounts an earlier run already gave you (up to 10,000).

## `minMatchRatePercent` (type: `integer`):

After 100 accounts were read in the run, stop it when fewer than this percent of them passed your filters, so strict filters cannot read on for long. Empty never stops on this.

## `includeLeftOutAccounts` (type: `boolean`):

Adds a free row for every account read and left out (its username and the reason: a filter, not readable logged out, already delivered), so you see why an account is missing.

## `refilterDatasetId` (type: `string`):

The dataset id of an earlier run of this Actor (its Storage tab). Its profile rows are checked again with this run's filters and the ones that pass are delivered, without reading Instagram, each as a Re-filtered profile.

## `includePersonalData` (type: `boolean`):

Off (default): the dedicated fields that name or reach a person are empty: emails and phones (read from the bio, bio links and recent captions), relatedProfiles, and links to Instagram, Facebook, Messenger, Threads or WhatsApp and contact links (mailto, tel, sms, callto, Telegram, Signal, Viber, Skype) in the website and bio links. On: they are filled. Bios and captions are always delivered as Instagram serves them. You are responsible for a lawful use of personal data, GDPR included.

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

Stops the run after this many seconds, with a row for each entry not finished. Empty means the platform timeout.

## `requestTimeoutSecs` (type: `integer`):

How long one request may take before it is retried.

## `maxRetries` (type: `integer`):

How often a failed request is retried on a fresh connection.

## `proxyConfiguration` (type: `object`):

Default: Apify Proxy without a group or country, which reads from the run's own address first and moves a request type to Apify's datacenter proxy when it is refused there. Choose a group or a country to read only through Apify Proxy, or give your own proxy links. A residential group is read through the datacenter pool instead (no extra cost).

## Actor input object example

```json
{
  "keywords": [
    "coffee roaster"
  ],
  "maxProfilesPerKeyword": 10,
  "maxCommentersPerPost": 50,
  "searchThreads": true,
  "searchAdLibrary": true,
  "adLibraryCountry": "ALL",
  "searchReelCreators": true,
  "reelSearchPages": 1,
  "searchVariants": false,
  "expandWithRelatedProfiles": false,
  "expansionDepth": 1,
  "includeDetails": true,
  "includeRecentPosts": true,
  "includeReelStats": false,
  "includeProfileInfo": false,
  "includeFacebookPageContact": false,
  "includeRelatedProfiles": false,
  "verified": "any",
  "influencersOnly": false,
  "includePrivate": true,
  "requireKeywordMatch": false,
  "mustContainIn": "bio_or_name",
  "combineCategoryAndWords": "and",
  "contactFilter": "any",
  "requireWebsite": false,
  "recentPostsDays": 30,
  "includeLeftOutAccounts": false,
  "includePersonalData": false,
  "requestTimeoutSecs": 30,
  "maxRetries": 2,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}
```

# Actor output Schema

## `items` (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 = {
    "keywords": [
        "coffee roaster"
    ],
    "maxProfilesPerKeyword": 10,
    "proxyConfiguration": {
        "useApifyProxy": true
    }
};

// Run the Actor and wait for it to finish
const run = await client.actor("automation_craft/instagram-user-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": ["coffee roaster"],
    "maxProfilesPerKeyword": 10,
    "proxyConfiguration": { "useApifyProxy": True },
}

# Run the Actor and wait for it to finish
run = client.actor("automation_craft/instagram-user-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": [
    "coffee roaster"
  ],
  "maxProfilesPerKeyword": 10,
  "proxyConfiguration": {
    "useApifyProxy": true
  }
}' |
apify call automation_craft/instagram-user-search-scraper --silent --output-dataset

```

## MCP server setup

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