Instagram Search Scraper API for Profiles & Reels · Apify
Instagram Search Scraper avatar

Instagram Search Scraper

Pricing

from $1.00 / 1,000 results

Go to Apify Store
Instagram Search Scraper

Instagram Search Scraper

Search Instagram by keyword for profiles, Reels, hashtags, places, music, and exact-hashtag content. Get structured, deduplicated results with automatic pagination.

Pricing

from $1.00 / 1,000 results

Rating

0.0

(0)

Developer

LanceAPI

LanceAPI

Maintained by Community

Actor stats

0

Bookmarked

15

Total users

8

Monthly active users

a day ago

Last modified

Categories

Features

Limited permissions

Share

Instagram Search Scraper API

Search profiles, top results, Reels, hashtags, places, music and exact-hashtag posts in one structured workflow — with run-wide de-duplication and predictable pay-per-event billing.

Search Instagram by keyword and get structured, de-duplicated data back. Seven search modes: profile search, top results (the media Instagram surfaces for a keyword), Reel search, hashtag search, hashtag posts, Instagram place search and Instagram music search — pick one per run, so a keyword means one search and one result shape.

Give it a list of queries, choose the kind of result you want, and it returns one dataset. A profile found by three different queries is delivered once, with all three queries listed on the row, so the file you download is already the file you would have built by hand.

  • Seven search modes — profiles, top results, Reels, hashtags, places, music and exact-hashtag posts.
  • Optional full profile data — turn it on for a profile search and each account also carries its exact follower, following and post counts, bio, links, category and business flags. Off by default.
  • Batch up to 200 canonical searches and return up to 3,000 unique rows.
  • Duplicate protection — if several queries discover the same result, it is delivered and billed once.
  • No Instagram login, cookies or session required.
  • Predictable billing — one Search charge when a canonical search starts, then Result charges only for unique delivered rows.

Top results is the widest keyword content search: it returns whatever media Instagram's own top tab holds for the keyword, which in practice is mostly Reels with the occasional image or carousel post. Reels is the narrower one — the same keyword, restricted to the Reels tab. Ordinary image and carousel posts are found most reliably through exact-hashtag posts (Hashtag posts) rather than any keyword search — the details are in Limits.

Quick Start

A first run needs nothing more than a keyword and the kinds of results you want:

{
"queries": ["travel"],
"searchType": "content",
"maxResultsPerQueryType": 20
}
  1. Paste that input in the Actor's Input tab.
  2. Click Start.
  3. Open the run's Dataset when it finishes.
  4. Each unique result is one structured row. When several searches found the same result, matchedQueries and matches list all of them on that single row.

For a first run, keep maxTotalResults at its default. hashtagTab only applies when you pick Hashtag posts.

What a row looks like

Illustrative example values — invented for illustration, not taken from a run.

{
"resultType": "profile",
"query": "openai",
"matchedQueries": ["openai", "artificial intelligence"],
"url": "https://www.instagram.com/openai/",
"id": "1234567890",
"username": "openai",
"fullName": "OpenAI",
"followersCount": 4100000,
"isVerified": true,
"fullProfileIncluded": false,
"rank": 1,
"scrapedAt": "2026-01-14T09:12:44.512Z"
}

The full field reference is in Output.

Choose the right search type

There are seven search types. Each one reads a different kind of query and returns a different kind of result, so pick the one that matches what you are looking for — the wrong type is the most common way a first run fails or comes back empty.

Search typeWhat to searchExample inputWhat you get
Profiles (profiles)A username or an account-related keyword@openaiAccount records: username, full name, id, profile URL and picture, verification and privacy flags
Top results (content)A keyword or search phrasehiring freelance developersThe media Instagram's top tab holds for the keyword — mostly Reels, sometimes image or carousel posts
Reels (reels)A video topic, keyword or phraseAI video generatorReels only: shortcode, caption, video URL, play and view counts, owner
Hashtags (hashtags)A topic or keyword to discover hashtags fortravel photographyHashtag records: name, URL, post count
Places (places)A city, landmark or venue nameCentral ParkPlace records: id, name, address, city, coordinates
Music (music)A song, artist or music keywordlofi beatsTrack records: title, artist, duration, cover, preview audio
Hashtag posts (hashtag_content)One exact hashtag name, no spaces#freelanceEverything under that hashtag — image, carousel and Reel posts

Every one of these examples is a valid input for its type. Each query is treated as an independent search, and all of them are case-insensitive and de-duplicated across the run.

Hashtags vs. Hashtag posts

These two sound alike but do opposite jobs.

  • Hashtags is discovery: you give it a topic and it finds the hashtags that relate to it. travel photography returns a list of hashtag records, so you can see which tags exist and how much content sits under each.
  • Hashtag posts is depth: you already know one exact hashtag, and you want the posts inside it. #travelphotography returns the media itself, not a list of tags.

Rule of thumb: to find hashtags, use Hashtags; to read the posts under one you already know, use Hashtag posts.

Top results vs. Reels

Both take a keyword, but they read two different lists, not two filters over one list.

  • Top results reads Instagram's own top tab for the keyword — the widest net. In practice it returns mostly Reels, with the occasional image or carousel post.
  • Reels reads only the Reels tab — the same keyword narrowed to short videos.

A short or ambiguous keyword can return nothing on the Reels tab while the top tab still has a full page, so Top results is the safer default when you are not sure.

Profiles vs. content searches

Profiles finds accounts; content, reels, hashtags, places and music find other kinds of results.

  • Profiles returns account records — who the accounts are, their follower counts, verification and privacy flags. Use it when you know a topic but not the handles.
  • Top results / Reels / Hashtag posts return media — posts and videos. Use them when you want content, not accounts.

A leading @ on a Profiles query is removed automatically, so @openai and openai find the same accounts.

JSON examples for each type

Each search type is one minimal input. Only queries and searchType are required; every other field falls back to its default.

Profiles

{ "queries": ["@openai"], "searchType": "profiles" }

Top results

{ "queries": ["hiring freelance developers"], "searchType": "content" }

Reels

{ "queries": ["AI video generator"], "searchType": "reels" }

Hashtags

{ "queries": ["travel photography"], "searchType": "hashtags" }

Places

{ "queries": ["Central Park"], "searchType": "places" }

Music

{ "queries": ["lofi beats"], "searchType": "music" }

Hashtag posts

{ "queries": ["#freelance"], "searchType": "hashtag_content" }

You can send several queries at once — each one runs as its own search under the chosen type:

{ "queries": ["@openai", "fitness coach", "nike"], "searchType": "profiles" }

How it works

  1. Submit queries and choose the search type you want.
  2. The Actor validates and normalises the input, and removes duplicate search operations.
  3. Valid searches run and paginate where that search mode supports pagination.
  4. Results are normalised and de-duplicated across the whole run.
  5. If you asked for full profile data, each account found is read once and its profile fields are merged onto the row that already exists. A read that fails leaves the row as it was.
  6. Unique rows are written to the Dataset with query and source-match context for downstream analysis.
You wantSearch typeWhat comes back
Accounts matching a keywordProfiles (profiles)Username, full name, id, profile URL and picture, verification and privacy flags — plus the full public profile of each account when you turn on includeFullProfile
The media Instagram surfaces for a keywordTop results (content)Top results: mostly Reels, sometimes image or carousel posts — shortcode, caption, media type, counts, owner
Reels matching a keywordReels (reels)Shortcode, caption, video URL, play and view counts, owner
Hashtags matching a keywordHashtags (hashtags)Hashtag name, URL, post count
Places matching a keywordPlaces (places)Place id, name, address, city, coordinates
Music tracks matching a keywordMusic (music)Track title, artist, duration, cover, preview audio
Posts under an exact hashtag — the image and carousel entry pointHashtag posts (hashtag_content)Everything carrying that hashtag (image, carousel and Reel posts), read from the tab you choose

Hashtag posts is the only type that needs an exact hashtag rather than free text, and the only one where you choose an ordering: top, recent, or reels. See Choose the right search type for how it differs from hashtags.

One type per run. You pick a single search type, so one keyword means one search and one result shape — and the bill is one search, not one per type. Want a second type? Run the Actor again; it is a second run, not a second charge on the first.

Use cases

Each search type answers a different question, so it helps to know which one you want before you run anything:

  • Find accounts by keyword — search profiles for a topic and get the accounts Instagram surfaces for it, with follower counts, so you can shortlist creators or brands. This is the way in when you know the topic but not the handles.
  • See everything a keyword surfaces — search content for the widest net: the top results Instagram itself shows for that word, which mixes Reels with the occasional image or carousel post. Start here when you do not yet know what kind of media a topic lives in.
  • See only the videos a keyword surfaces — search reels to see which videos are being surfaced for a topic, with views, plays, likes and the video asset.
  • Read the posts behind an exact hashtag — search hashtag_content on a single hashtag and page through its feed. This is the search type that returns ordinary image and carousel posts most reliably.
  • Hashtag research before a campaign — search hashtags to see which hashtags exist around a topic and how much content sits under each.
  • Location and local-business research — search places to resolve a city, district or venue into a record with coordinates.
  • Music and audio discovery — search music to find the tracks and artists behind a genre, mood or campaign.
  • Topic sweep — run the Actor once per search type on the same keyword to get a first-pass picture before narrowing down. Each run is billed separately.
  • Seed lists for downstream analysis — hand the output to a profile scraper, a Reel scraper or an audience scraper when you need depth on what you just found.

The Actor collects and structures the data. Analysis on top of it — sentiment, scoring, influencer ranking, outreach decisions — happens in your own tools; this Actor does not perform it.

Input

{
"queries": ["travel", "specialty coffee", "@openai", "#vanlife"],
"searchType": "content",
"maxResultsPerQueryType": 50,
"maxTotalResults": 1000
}
FieldTypeRequiredDefaultPrefillNotes
queriesstring listYes—["travel"]Keywords, usernames, hashtags, place names or music terms. One per line in the Console.
searchTypeselectYes—contentOne search type per run. Console labels: Profiles, Top results, Reels, Hashtags, Places, Music, Hashtag posts. API values: profiles, content, reels, hashtags, places, music, hashtag_content.
includeFullProfilebooleanNofalse—Full profile data. Only applies when searchType is profiles: each account found is also read for its public profile fields. Every other search type ignores it, and the run summary says so.
maxResultsPerQueryTypeinteger, 1–200No50—Upper bound per search; see Limits.
maxTotalResultsinteger, 1–3000No1000—Run-wide ceiling on delivered rows.
hashtagTabselectNorecent—Only used by Hashtag posts (hashtag_content): top, recent or reels. Every other search type ignores it; if you picked a tab other than the default, the run summary says the choice did not apply.

Those six fields are the whole input. There is no second, similarly named field next to them.

Required means required. queries and searchType have no default, and the platform checks both before the Actor starts: a request that omits either one is rejected outright, the run never begins, and nothing is charged. The Console pre-fills them so that a first run is one click, but a pre-filled field is not a default.

The legacy searchTypes array is still accepted for API compatibility — older integrations send it, and it takes precedence when present. It is no longer part of the public input schema, so it cannot be picked in the form any more; only code written before the single-type input existed sends it. If your integration still uses it, also send searchType with any one of its values: the platform requires that field to be there, and the array still decides what actually runs. See Batch size.

The run summary reports what actually ran. RUN_SUMMARY in the run's Key-Value store lists the effective search type, the result ceilings that were applied, and a notes list for anything that differed from what you asked for — a hashtagTab you set to something other than the default on a run that searched no hashtag posts, a limit that had to be pulled inside its range, or a run that came in through the legacy searchTypes array. Nothing this Actor changes is changed silently.

Full profile data

includeFullProfile turns a profile search into a search plus one profile read per account. It is off by default, and it only does anything for searchType: "profiles".

{
"queries": ["ai"],
"searchType": "profiles",
"maxResultsPerQueryType": 20,
"includeFullProfile": true
}

What it adds to each account row: biography, bioLinks, externalUrl, followersCount, followingCount, postsCount, category, isVerified, isPrivate, isBusinessAccount, isProfessionalAccount, profilePicUrlHD, highlightReelCount, joinedRecently — and fullProfileIncluded: true to say the row really was enriched.

Four things it does not do:

  • It does not add rows. One account is still one row; the profile fields land on the row the search already produced.
  • It does not overwrite good data with nothing. When the profile read has no value for a field — a bio the account does not have, a count a source does not publish — the row keeps what the search already knew. null in a profile read means "not published", not "empty".
  • It does not fail the run. If a profile cannot be read, the account is still delivered with its search fields, fullProfileIncluded stays false, and nothing extra is charged for it. A run where some reads fail is still a successful search — the summary reports how many were enriched and how many were not.
  • It does not include recent posts. The profile read is the profile, not its media. Use a profile-posts Actor for that.

Two things worth knowing before turning it on:

  • It costs more. Each account whose profile data was successfully added carries one Full Profile charge on top of the Search and Result charges. Accounts that could not be enriched are not charged for. See Pricing.
  • It is slower. Each account needs one extra request, done a few at a time so a large batch stays stable. A search of 200 accounts with this on takes longer than the same search with it off.

includeFullProfile on a run that searched hashtags, Reels or anything other than profiles is not an error: the flag is ignored, the summary says so, and nothing is charged for it.

How queries are read

The same word means different things to different searches, so normalisation is per search type rather than one rule for everything.

Search typeWhat happens to the queryExample
profilesA leading @ is removed@openai → openai
hashtagsA leading # is removed; the rest is free text#travel → travel
hashtag_contentA leading # is removed, the result is lowercased, and it must be exactly one valid hashtag#VanLife → vanlife
contentUsed exactly as typedcoffee shop stays coffee shop
reelsUsed exactly as typedtravel photography stays travel photography
placesUsed exactly as typedNew York stays New York
musicUsed exactly as typedlo-fi beats stays lo-fi beats
  • Duplicates are merged. Queries that become identical after normalisation are collapsed, and the run summary reports how many were merged.
  • Exact hashtags are strict on purpose. A hashtag cannot contain a space, so #new york is not a hashtag; that one search is skipped instead of being silently rewritten into newyork, which would search for something you never asked for. The same query still runs for the other types you selected, and the summary reports how many searches were dropped.

Batch size

With one search type per run, a run accepts at most 200 canonical search operations, counted after query normalisation, type validation and duplicate removal — which, with a single type, means at most 200 queries.

QueriesSearch typesCanonical searches
2001200
1001100
40140

The legacy searchTypes array can still name several types when it is sent by code, and then the same 200-operation ceiling applies across all of them: 33 queries × 6 types is 198, 28 × 7 is 196.

A batch that expands past 200 is rejected before any data is fetched, and the message states the count you asked for. The operation limit is validated before any search starts, so an oversized batch creates no Search or Result charges. The standard Actor Start charge may still apply to the run.

Output

One row per unique result — profile, Reel, post, hashtag, place or music track. Every row has the same shape, so the dataset loads straight into a spreadsheet or a database. Missing values follow one rule: a value the source did not report — a number, a name, a URL — is null, never 0, an empty string or "N/A"; a list the source reported as empty is [], never null. So hashtags, mentions, matchedQueries and matches are always arrays, and are empty arrays rather than null when there is nothing in them.

Main fields

FieldMeaning
resultTypeOne of profile, reel, post, hashtag, place, music. Filter on this to split the dataset by type.
queryThe query that found this row, after normalisation.
matchedQueriesEvery query that found it. A row found by three queries is still one row.
urlCanonical Instagram URL. null for music, which has no page of its own.
rankPosition in the delivered dataset.
sourceRankPosition this result had in the source search result when first discovered.
matchesEvery discovery that pointed at this row — query, search type and position in that result list.
scrapedAtWhen the run started, ISO 8601 in UTC. Every row in a run carries the same value, so a dataset can be tied back to the moment it was collected.
fullProfileIncludedtrue when this account's row also carries data from a full profile read, false otherwise — including every row from a run where includeFullProfile was off.

Type-specific fields: id, username, fullName, biography, bioLinks, followersCount, followingCount, postsCount, isVerified, isPrivate, isBusiness, isBusinessAccount, isProfessionalAccount, category, externalUrl, profilePicUrl, profilePicUrlHD, highlightReelCount, joinedRecently for accounts; shortcode, caption, videoUrl, thumbnailUrl, playCount, viewCount, likeCount, commentCount, mediaType, publishedAt, ownerUsername, ownerId, hashtags, mentions, locationId, locationName, musicTitle, musicArtist for Reels and posts; name, mediaCount for hashtags; name, address, city, shortName, latitude, longitude for places; title, artist, durationSeconds, coverUrl, audioUrl, previewUrl, explicit, audioClusterId, audioAssetId for music.

Two business flags, not one. isBusinessAccount is Instagram's own account-level business flag. isProfessionalAccount is its professional-account flag; an account can be one, the other, both or neither. isBusiness is kept for older integrations and always carries the same value as isBusinessAccount — it is never a separate signal, and it is never true because a source said something adjacent (is_business) that does not mean this.

Views in the Dataset tab

The Dataset tab offers seven column layouts over the same rows, so the fields that matter for your search type come first instead of being buried behind twenty empty columns.

ViewLeads withBest for
Overviewtype, query, the name columns, caption, followers, likes, viewsa run that mixes several search types
Profilesusername, full name, id, followers, posts, following, verified, private, business, professional, category, bioaccount searches, with or without full profile data
Reelsowner, caption, views, plays, likes, duration, publishedReel searches
Hashtag postsowner, caption, likes, comments, media type, publishedexact-hashtag feeds
Hashtagshashtag, posts with hashtaghashtag discovery
Placesplace, city, address, coordinatesplace searches
Musictrack, artist, duration, cover, previewaudio searches

Two things a view does not do. It does not filter rows — a Reels run and a profile run in the same dataset share one table, and the type column tells you which is which. And it does not change an export: a JSON, CSV or Excel download always contains all 63 fields regardless of the view you were looking at.

Ordering: hashtag tabs, rank, sourceRank and matches

Four different things, deliberately kept apart:

  • hashtagTab chooses the source feed. top, recent and reels are three different lists of posts, not three sortings of one list. Changing the tab changes what exists to be found.
  • sourceRank preserves the source order for that one search. It is the position the result had in the list the source returned, so a Reel that was third for #vanlife keeps sourceRank: 3 on its row.
  • rank is run-level delivery order after global de-duplication — the order of rows in your dataset, not an Instagram ranking and not a per-hashtag order.
  • matches[] preserves per-query positions. When one row was found by #vanlife in recent and by the keyword van in reels, each discovery keeps its own query, searchType and sourceRank.

A dataset mixing several hashtags, tabs and search types is therefore not sorted by any single tab. If you need "what the top tab of one hashtag looked like", filter that one search out of matches and sort by sourceRank.

Run summary

Every run also writes a RUN_SUMMARY record with:

  • an outcome for the whole run — SUCCESS, PARTIAL, NO_DATA or FAILED — so one word tells you whether the run delivered everything it promised;
  • how many queries were supplied, used, merged and rejected, and how many search operations ran;
  • how many rows were saved, how many duplicates were removed, and the count per result type;
  • an outcome for every search — including the ones that returned nothing and why;
  • what was billed: searches started, searches charged, unique results delivered, results charged, and whether the two halves agree;
  • when includeFullProfile was on: how many accounts were asked about, how many were enriched, how many were not, and how many Full Profile charges that produced. A run that searched no profiles says the flag did not apply.

What each outcome means

OutcomeWhat it meansWhat you getIs retrying useful?
SUCCESSThe search ran and finished normally.All the results it found.No need.
PARTIALThe search ran and found results, but stopped before it was complete — a result or page limit of this Actor was reached, or the source stopped returning complete pages.The results it did find; nothing is discarded.Usually yes, with a narrower query or a higher limit.
TRUNCATEDThe search was not executed. Either the run reached a limit before it could start, or its charge could not be confirmed. It is not a statement that nothing matched.Nothing from this search.Yes — raise the limit, or run again.
NO_DATAThe search completed normally but returned no usable matches from the available search result.Nothing, because there was nothing usable.No; try a different keyword or type.
UNAVAILABLEThe search could not be completed right now. A re-run may well succeed.Nothing from this search.Yes.
FAILEDThe search failed for a technical reason.Nothing from this search.Yes.
INVALIDThe input for that search was not usable — for example hashtag_content with a query that is not a single hashtag.Nothing from this search.No; fix the input.

queriesWithNoResults in the summary lists only NO_DATA searches — searches that ran and came back with nothing usable. A search that never ran is listed as TRUNCATED instead, because "we did not ask" and "we asked and found nothing" are different facts, and only one of them is about Instagram.

These outcomes describe each search. includeFullProfile never turns a successful search into a failure — but because the profile data is part of what you asked for, the run summary also carries a single outcome for the whole run, and that one is PARTIAL when some accounts could not be enriched. A run that found 20 accounts and enriched 18 is outcome: "PARTIAL", still delivers all 20 rows, and still reports the search itself as SUCCESS. Both facts are shown, because only one of them is about Instagram.

This Actor recovers from common temporary failures on its own, so a single flaky response does not by itself lose you a search. How that is done is internal and is deliberately not exposed in the output.

Limits

Keyword searches return almost only video. That distinction matters, so it is stated plainly instead of being left for you to discover:

  • content and reels are both keyword searches, and both come back overwhelmingly as Reels. In one captured top-search page for a keyword, all 20 items were Reels; a later run on the same keyword returned 18 Reels plus 1 carousel and 1 image post. Posts do appear — they are simply the minority.
  • Content under a specific hashtag is searchable, images included. A hashtag feed still leans towards video, but it is where image and carousel posts actually appear — roughly one row in ten in the sample this Actor was built against.
  • There is no "image posts" search tab on Instagram, so no button here can honestly promise one. Any product that offers "search image posts by keyword" is quietly reading a hashtag or a profile feed, and so is this Actor when you use hashtag_content.

If you need image posts, start from a hashtag or an account instead of a keyword: give it a hashtag and it returns whatever that hashtag contains.

Other boundaries worth knowing:

  • One run covers at most 200 canonical searches and 3,000 rows. Both are upper bounds, not targets.
  • maxResultsPerQueryType is a ceiling, not a guarantee. A search returns fewer results when the source runs out of them, when the result count is genuinely smaller, or when this Actor's own page budget is reached first — in that last case the search is marked PARTIAL rather than reported as complete.
  • Hashtag tabs have different depth. recent supports paging through older posts. top and reels return a single page that cannot be continued, so they are short by nature — a finite, curated set.
  • Large batches can take longer than small ones. Searches are processed in a controlled way to keep batch execution stable.
  • content is the slowest type. It reads a live result page rather than a cached list, and one page can take up to a minute when Instagram is slow. That is waiting, not an error: the Actor keeps the request open and returns the page. If a page still has not arrived after 75 seconds it is reported as a temporary issue rather than as "no results", so a slow source never masquerades as an empty one.
  • Results reflect the source at the moment you ask. Search results are not a complete index of Instagram, and the same query on two different days legitimately returns overlapping rows.

Notes on data quality

  • Missing values stay missing. If a source does not report a follower count, the field is null rather than 0, so "unknown" and "zero" never look the same in your data.
  • Placeholder text is discarded. Some sources answer with a sentence such as "Access delayed…" where a name or city belongs; that is recognised and turned into null instead of being stored as if it were a real name.
  • Counts are as reported. Follower counts and other engagement numbers are what Instagram last reported, not live counters.
  • No filler requests. Search results can be thinner than a profile page: counts are often absent on a keyword search even when the account's own page shows them. The Actor does not make extra requests to fill those gaps silently — the one way to ask for more is includeFullProfile, which is explicit, is priced per account, and says fullProfileIncluded on every row it touched.

Pricing

Pay for searches that actually run and unique results that are actually delivered.

  • Actor Start — $0.0005 per run. Applied once by the Apify platform.
  • Search — one charge when one canonical query × result type actually starts. Additional pages and automatic recovery do not create another Search charge.
  • Result — one charge per unique result successfully delivered. When several queries discover the same profile, Reel, hashtag, place, post or music item, it is delivered once and creates one Result charge.
  • Full Profile — one charge per account whose profile data was successfully added. Only when you turn on includeFullProfile. An account that could not be enriched, or a row that already had the flag from a different run, creates no Full Profile charge here.

Results start at $1.00 per 1,000 on eligible plans. Search pricing starts at $2.00 per 1,000 on eligible paid plans. Full Profile data is $1.50 per 1,000 accounts on the Free plan, falling to $1.00 on higher plans. See the Pricing tab for current plan-specific rates.

Platform usage is currently included under this Actor's active Pricing configuration.

What controls cost

  • maxResultsPerQueryType limits result volume for one search and helps control Result-fee exposure.
  • maxTotalResults caps unique result rows across the run and helps control Result-fee exposure.
  • Selecting fewer query × search-type combinations reduces the number of possible Search charges.
  • Duplicate canonical searches are not charged twice.
  • Duplicate results are not charged twice.
  • An executed search that returns zero usable results can still create one Search charge, but creates no Result charge.
  • includeFullProfile adds one Full Profile charge per successfully enriched account. Turn it off to keep a profile search at Search + Result only.
  • An account that could not be enriched creates no Full Profile charge, even though the row is still delivered.
  • Invalid or never-started search operations create no Search charge.

Neither result limit is a guaranteed total-cost cap: Actor Start and Search charges still apply. Use them to bound how much data one run can produce, not as a spending guarantee.

Example

1 run + 10 Search operations + 100 unique Results

Actor Start $0.0005
10 Searches $0.0200
100 Results $0.1500
--------------------------
Total $0.1705

Example using current Bronze rates. See the Pricing tab for current plan-specific rates.

API access

Every run follows the same three steps: start the Actor → wait for the run to finish → read its dataset. Only the run id and the dataset id tie the steps together, and both come back in the start response.

Authentication is always a bearer header. Tokens are never sent in a query string:

export APIFY_TOKEN=... # Settings → Integrations in the Apify Console
export ACTOR_ID=lance_api~instagram-search-scraper-api # REST form: <owner>~<actor-name>

The SDKs take the same identifier with a slash: lance_api/instagram-search-scraper-api.

cURL

# 1. Start a run and keep its ids
RUN=$(curl -sS -X POST "https://api.apify.com/v2/acts/$ACTOR_ID/runs" \
-H "Authorization: Bearer $APIFY_TOKEN" \
-H "Content-Type: application/json" \
-d '{"queries":["travel"],"searchType":"reels","maxResultsPerQueryType":50}')
RUN_ID=$(printf '%s' "$RUN" | jq -r '.data.id')
DS=$(printf '%s' "$RUN" | jq -r '.data.defaultDatasetId')
# 2. Wait for it to finish
curl -sS "https://api.apify.com/v2/actor-runs/$RUN_ID?waitForFinish=300" \
-H "Authorization: Bearer $APIFY_TOKEN"
# 3. Read the dataset
curl -sS "https://api.apify.com/v2/datasets/$DS/items?format=json&clean=true" \
-H "Authorization: Bearer $APIFY_TOKEN"

JavaScript

import { ApifyClient } from 'apify-client';
const client = new ApifyClient({ token: process.env.APIFY_TOKEN });
// 1 + 2: start the run and wait for it to finish
const run = await client.actor('lance_api/instagram-search-scraper-api').call({
queries: ['travel', '#vanlife'],
searchType: 'reels',
maxResultsPerQueryType: 50,
});
// 3: read the dataset
const { items } = await client.dataset(run.defaultDatasetId).listItems();
console.log(items.length, items[0]);

Python

import os
from apify_client import ApifyClient
client = ApifyClient(os.environ["APIFY_TOKEN"])
# 1 + 2: start the run and wait for it to finish
run = client.actor("lance_api/instagram-search-scraper-api").call(run_input={
"queries": ["travel", "#vanlife"],
"searchType": "reels",
"maxResultsPerQueryType": 50,
})
# 3: read the dataset
items = client.dataset(run["defaultDatasetId"]).list_items().items
print(len(items), items[0])

Both queries and the search type are required in an API call: send them explicitly. The field is searchType (one value), and the platform rejects a request that leaves it out before the run starts, so nothing is charged for a call that forgot it.

The older searchTypes array still works and takes precedence when present, so published integrations keep running unchanged — with one addition: because the platform now requires searchType to be present, send it alongside the array (any one of the array's own values). The array still decides what runs; searchType is only there to satisfy the platform. The run summary names the source, so you can always see which one was used.

FAQ

Can I search ordinary image posts by keyword? Not reliably. Both keyword types (content and reels) come back mostly as Reels, with image and carousel posts only as the minority, because that is what Instagram's keyword search holds. To reach image and carousel posts, search an exact hashtag (hashtag_content) or a specific account instead. Limits explains why.

What is the difference between content and reels? Both take a keyword, and they read two different lists. content reads Instagram's top results for that word — the widest net, mostly Reels with the occasional image or carousel post. reels reads only the Reels tab. A short or ambiguous keyword can return nothing on the Reels tab while the top tab still has a full page, so content is the better default.

What is the difference between hashtags and hashtag_content? hashtags takes a topic and discovers which hashtags exist around it — travel photography returns hashtag records. hashtag_content takes one exact hashtag and returns the posts inside it — #vanlife returns media. One is discovery, the other is depth.

Can I combine several search types? Not in one run: the input form takes a single search type, so a keyword means one search and one bill. Run the Actor again for a second type — each run is billed on its own. (Code written before the single-type input existed can still send the legacy searchTypes array to search several types in one run; the run summary says when that happened.)

Why did I get fewer than maxResultsPerQueryType? Because the number is a ceiling. The source may genuinely have fewer results, may stop returning complete pages, or the Actor's own page budget may be reached first — the run summary says which, and marks the search PARTIAL when it was cut short.

What happens at maxTotalResults? The dataset stops growing. Searches that have not started are not started and are reported as TRUNCATED; a search that was mid-flight keeps what it had and is reported as PARTIAL. Raise the limit and run again, or split the batch.

Are duplicate results returned twice? No. De-duplication is run-wide: one row per unique result, with every query that found it in matchedQueries and matches. Duplicates are billed once for the same reason — one row, one Result charge.

What does NO_DATA mean? The search ran and completed, but returned no usable matches from the search result that was available. It does not claim that all of Instagram has nothing for that word — only that this search came back empty.

Do I need an Instagram login, cookies, or a session? No. The Actor needs no Instagram account, no cookies and no session, and it never asks for your Instagram password.

Which hashtag tabs support pagination? recent pages through older posts. top and reels are single-page only, so their result sets are naturally short.

How is this Actor billed? This Actor uses pay-per-event pricing. A Search charge applies once when one canonical query × result type actually starts, and a Result charge applies to each unique result successfully delivered. Additional pages and automatic recovery do not create additional Search charges, and duplicate results are not charged twice. With includeFullProfile on, each successfully enriched account adds one Full Profile charge; an account that could not be enriched adds none. A $0.0005 Actor Start charge applies once per run. See the Pricing tab for current plan-specific rates.

What does includeFullProfile actually add? The public profile of each account the search found: exact follower, following and post counts, bio, links, category, verification and privacy flags, avatar, highlight count, and the business and professional flags. It does not add rows, does not include recent posts, and does not replace a search row's existing values with empty ones.

Why is fullProfileIncluded false on some rows even though I turned it on? Each account is read once. When that one read fails — the source timed out, answered with an error, or returned a profile that is not the account that was asked for — the row is still delivered with its search fields and stays false, and no Full Profile charge is raised for it. The run summary reports the count, and re-running is the way to retry those accounts.

Troubleshooting

SymptomMeaning
Run status FAILED, no rows, summary says UNAVAILABLEThe search could not be completed at all. Re-run; if it persists, the data source is having an outage.
PARTIAL outcomes in the summarySome searches delivered results and some did not, or some stopped early at a limit. The rows that did arrive are in the dataset — nothing is discarded.
TRUNCATED outcomes in the summaryThose searches never ran: the run hit maxTotalResults first. Raise it, or run fewer queries.
BATCH_LIMIT_EXCEEDEDQueries × search types exceeded 200. The message states the count you asked for.
NO_DATA for a query you expected results fromThe search ran and came back empty. Try a broader keyword, or switch the type — a keyword may match accounts but no hashtags.
A hashtag search returns fewer rows than maxResultsPerQueryTypeThe tab you chose does not paginate indefinitely. top in particular is a finite, curated set.
INVALID for one search type onlyThe query is not usable for that type — usually hashtag_content with a phrase instead of a single hashtag. The other types still ran.
fullProfileIncluded: false on rows you expected to be enrichedThose accounts could not be read on this run. The search rows themselves are complete and were still billed as search results; no Full Profile charge was raised for the ones that failed. Re-run to retry them.
includeFullProfile was on but the summary says it did not applyThe run searched something other than profiles. The flag only works with searchType: "profiles"; nothing was read and nothing extra was charged.

Responsible Use

  • Collect only public data, or data you are otherwise permitted to collect.
  • Follow the laws that apply to you and the terms of the platforms you use.
  • Respect privacy and copyright: do not republish personal data or media you have no right to use.
  • Do not use this Actor for spam, harassment, or any abusive, deceptive or unlawful purpose.

Support

A useful bug report contains:

  • the run id (Console → Runs → the run);
  • the input, with anything sensitive removed;
  • the visible status or error message;
  • what you expected and what you got instead.

Please never send: your Apify token, cookies or session data, passwords, access keys, proxy details, or Authorization headers. Nothing in a support conversation needs them, and a message containing them should be treated as compromised.

Once you know what you are interested in, these take it further:

If you need to...Recommended Actor
inspect everything posted by a discovered accountInstagram Profile Posts & Reels Scraper
inspect one discovered profile in depthInstagram Profile Scraper – Followers & Engagement
analyse the audience of a discovered accountInstagram Followers & Following Scraper – Export Lists
read the comments on a discovered postInstagram Comments & Replies Scraper – Posts, Reels
see who liked a discovered postInstagram Likers Scraper – Post & Reel Like
download a discovered ReelInstagram Reels Downloader – Video, Audio & Metadata
turn a discovered Reel into textInstagram Video Transcript Scraper
find the sound behind a discovered ReelInstagram Music & Audio Scraper – Reels by Sound

Use this Actor first when you have keywords and no accounts yet; switch to the account-level Actors once you know who you are interested in.