# Changelog of Instagram Profile MCP Server — Tools for AI Agents (`afanasenko/instagram-profile-scraper-mcp-server`) Actor

- **URL**: https://apify.com/afanasenko/instagram-profile-scraper-mcp-server/changelog.md
- **Full Actor documentation**: https://apify.com/afanasenko/instagram-profile-scraper-mcp-server.md

## Changelog

### \[0.0.48] - 2026-09-10

- **A list that Instagram limits on a large account now says so.** When a Verified or Business account's followers list ends well short of what the profile declares, the tool result and the `RUN_SUMMARY` storage record report how many of how many arrived. Before, the shortfall passed without a word.

- **The difference between an empty list and an unreadable one now reaches the result itself.** When a followers or following list could not be read, the tool result and the run's message say so and suggest trying again in a few minutes, instead of reporting that the list came back empty. A private account keeps its own advice: the account has to be public.

- **Clearer reasons when a list cannot be read.** Log lines and the skipped-accounts record now describe the problem in plain words.

### \[0.0.47] - 2026-09-10

- Clarified wording in the README, the input form, the output column descriptions and earlier changelog entries. Nothing changes in how the actor runs, what it returns or what it costs.

### \[0.0.46] - 2026-09-10

- **`instagram_analyze_followers_following` works again.** Since 9 September follower lists could not be read at all and the tool returned no accounts with no explanation. Lists are now read through a different route and return data as before.

- **An empty result now tells you whether the list was empty or unreadable.** These are opposite facts and the tool used to report both the same way. A list that cannot be read is now reported as a temporary problem on our side, not as a fact about the account you asked for.

### \[0.0.45] - 2026-09-09

- **A brief hiccup no longer makes a real, public account look deleted.** When an account can't be looked up on the first try, it is now double-checked through a second, independent route before being reported as unreachable. Accounts that really are deleted, private, or mistyped are still reported exactly as before.

- **Honest wording above the filter section.** It used to say filters "save on processing costs". They don't: filters run after each profile is read, so they shape your results, not your bill. The Pricing section has always said this; the input form now agrees with it.

### \[0.0.44] - 2026-09-04

#### Fixed

- **Creator accounts were being reported as personal, and the account-type filter dropped them.**
  Instagram has three kinds of account — business, creator and personal — and the first two are
  both professional: both can publish a Contact button with an email or a phone number. This actor
  read a single business/not-business signal, so every creator fell into the personal bucket.
  Measured across the populations these tools return, creators are between a tenth and half of a
  result set, so **business** was discarding a large part of what it found and **personal** was
  returning creators.

#### Added

- **Account Type column**, on every row: `business`, `creator` or `personal`, read from
  Instagram's own account type. It is the last column, so every column you already read keeps its
  position.
- **Two new values for `accountType`**, in both the tool schema and the input form: `creator`,
  and `professional` for business and creator together. `any`, `business` and `personal` behave
  as before, except that `personal` now means what it says.

### \[0.0.43] - 2026-09-04

Documentation only. The **Related actors** table now lists *Instagram Email Scraper*, for the
contact details a list of usernames publishes — email, phone, website and business category,
one row per account. No change to this actor's behaviour, input, output or prices.

All notable changes to the Instagram Profile MCP Server actor are documented here.
The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).

### \[0.0.42] - 2026-09-04

Documentation only. The **Related actors** table now lists *Instagram Comments Scraper*, for
reading what a post's comments say — every comment and reply as a row, with @mentions and
\#hashtags in their own columns. No change to this actor's behaviour, input, output or prices.

### \[0.0.41] - 2026-09-03

Maintenance build — no user-facing changes. Input schema, output dataset
columns, KVS records, console output, error messages, defaults, and pricing
are all unchanged from 0.0.40. Saved tasks continue to work identically.

### \[0.0.40] - 2026-09-01

#### Changed

- Related actors section updated to include **Instagram Likes Scraper** (post likers and
  commenters) and **Instagram Influencer Search** (keyword and hashtag search). The second one
  had been missing since it shipped on 2026-08-11 — a customer landing here saw a family that
  was two members short of the real one.

### \[0.0.39] - 2026-08-31

#### Fixed

- A mistake in the input no longer marks the run as failed. If a required field is missing or a
  username isn't a username, the run now finishes normally and the status line says exactly what to
  change. Nothing is fetched and nothing is charged, as before.
- If the server cannot start — for example because its port is unavailable — the reason is now
  recorded instead of the container disappearing without a word.
- A failure during start-up, before the first tool call, no longer ends the run without
  explanation. The reason is now written to the log and to the run's status.
- Work done by a long-running server is now saved when the platform moves it to another machine,
  even if the move happens before the first tool call. Previously that case was not covered.

### \[0.0.38] - 2026-08-26

#### Fixed

- A regular run that stopped early because no account in the search publishes a business address
  now says so. It used to fall through to the generic wording — "we found 200 and your filters
  rejected every one of them" — which describes a different thing than a run that deliberately
  stopped after 25. Tool calls have always explained it; regular runs never did.
- The early stop now works for every tool call in a session. Once any one call had found a
  matching profile, later calls in the same session stopped checking, so a call whose search
  had no addressed accounts at all would keep paying to the end of its list.
- The diagnostics a call reports are now its own. Two counters were carried over from previous
  calls in the same session, which could make a call blame the address filter for rejections that
  happened in an earlier one.

### \[0.0.37] - 2026-08-19

#### Changed

- Correction to the 0.0.36 note on the Business-Address filter: full country names DO match
  outside the US, Canada, Mexico and India — Instagram writes the city line as "Berlin, Germany"
  or "Lagos, Nigeria", country spelled out in English; in the US, Canada, Mexico and India it
  ends in the state ("Miami, Florida"). Abbreviations like "USA" or "UAE" are not what the field
  carries.
- The filter's input-form description, the README guidance and the run messages now teach the
  shape that works: a comma-separated list of several cities plus the region written out in full,
  in Instagram's own spelling, accents included.
- When some profiles did publish an address and your terms simply missed them, the closing
  message now says so and suggests the towns-plus-region list instead of staying generic.

### \[0.0.36] - 2026-08-19

#### Changed

- The location filter is now called **"Filter by Business Address — professional accounts only"**,
  because that is what it reads. Instagram publishes an address only on professional accounts that
  filled it in, so ordinary creators have none at all and this filter rejects every one of them.
  Write city names: the field holds a city, so "Miami" can match and "USA" never will.

#### Added

- A run whose location filter cannot match anything now stops after the first 25 profiles instead
  of paying its way through the whole search and reporting an empty result at the end. If none of
  those 25 publishes a business address, the run says so, tells you how much of the search it
  declined to pay for, and points at the field to clear.

- A location rejection now comes back with the numbers behind it — "25 of 25 had no public
  business address at all" — the way the other filters already explained themselves.

### \[0.0.35] - 2026-08-18

Maintenance build — no user-facing changes. Input schema, output dataset columns,
KVS records, console output, error messages, defaults and pricing are all unchanged
from 0.0.34.

### \[0.0.34] - 2026-08-18

#### Fixed

- The pre-run warning about narrow filters now also fires on a location filter used on its own.
  Until now it only spoke up when location was combined with keywords, so a run narrowed by
  location alone went ahead with no warning at all — and those are the runs most likely to fetch
  profiles, charge for them and save none of them.
- The same warning now understands `Location Seeds`. That field replaced the older location
  input in the form, and the warning had never been taught the new name, so a run narrowed by
  location discovery looked unfiltered to it.
- The expected-yield figure in that warning is now specific to the contact type you picked.
  All four choices used to be quoted the same ~10%. They do not behave the same: asking for
  BOTH an email and a phone — the strictest of the four — actually keeps about twice as many
  profiles as asking for an email alone, and the warning now says so instead of understating it.

### \[0.0.33] - 2026-08-17

Maintenance build — no user-facing changes. Input schema, output dataset
columns, KVS records, console output, error messages, defaults, and pricing
are all unchanged from 0.0.32. Saved tasks continue to work identically.

### \[0.0.32] - 2026-08-17

Maintenance build — no user-facing changes. Input schema, output dataset
columns, KVS records, console output, error messages, defaults, and pricing
are all unchanged from 0.0.31. Saved tasks continue to work identically.

### \[0.0.31] - 2026-08-12

Maintenance build — no user-facing changes. Input schema, output dataset
columns, KVS records, console output, error messages, defaults, and pricing
are all unchanged from 0.0.30. Saved tasks continue to work identically.

### \[0.0.30] - 2026-08-12

#### Fixed

- **The language filter and the `Detected Language` column now cover 44 languages instead of 13.**
  Korean, Polish, Ukrainian, Dutch, Swedish, Serbian, Thai, Vietnamese, Greek, Hebrew, Persian and
  23 others were already being recognised from the bio and captions — and then reported as "N/A",
  because the column only knew how to name 13 of them. They are now named, and each can be picked
  in **Filter by Profile Language**. Nothing changed for the 13 languages that already worked.
- **`profileLanguage` told callers to pass an ISO code.** The filter has always matched on the full
  language name, so a call asking for `"en"` matched nothing and returned an empty result with no
  explanation. The description now says what the field takes: `"English"`, `"Korean"`, `"Polish"`.

#### Added

- **`Posts in Last 30 Days` is now described in the output schema.** The column has always been
  written; it was the one column with no description, so anything reading the schema to find out
  what the output contains never saw it.

### \[0.0.29] - 2026-08-10

#### Fixed

- **A failed run no longer shows you raw failure text.**
  It was printed as the run's failure message, stored in `RUN_SUMMARY`, and rendered on the run's
  status page — including, on a connection problem, a server address. None of it was ever
  useful to you. A failed run now says the failure was on our side, and nothing more.

### \[0.0.28] - 2026-08-10

#### Changed

- The free-plan limit ids listed in the run's `FREE_LIMITS_APPLIED` storage record now use one
  shared vocabulary across all our actors, so the same limit reads the same wherever you meet it.
  The human-readable message on each entry is unchanged.

#### Added

- Every result row now ends with **Analysis Status** and **Why Not Analyzed**, matching the
  Instagram Profile Scraper row for row. On this actor every row is `analyzed` / `N/A`; the
  columns exist so a result read from here and a result read from there have the same shape.

### \[0.0.27] - 2026-08-02

#### Added

- **Network Expansion now reports when the starting profiles are far bigger than the profiles asked
  for.** Instagram suggests accounts of a similar size to the one it is given, so seeding from an
  account with millions of followers and asking for accounts under 100,000 asks for something the
  suggestions will not contain. When a call returns nothing for that reason, the tool result now says
  so and names the size of each starting profile, so the caller can retry with better seeds instead
  of guessing. A call whose starting profiles are within about 10x of the maximum says nothing.

### \[0.0.26] - 2026-08-02

#### Fixed

- **A narrow follower range is now recognised as the strong filter it is.** Setting both a minimum and
  a maximum close together is the single fastest way to spend a run and keep almost none of it, and
  the up-front warning did not treat it as narrow at all. It now does, and it fires before the run
  starts collecting rather than after the money is spent. A wide range is unaffected — nothing that
  ran quietly before starts warning now.

### \[0.0.25] - 2026-07-30

#### Added

- **Related actors** now lists **Instagram Reel Script Extractor** — reel content instead of profiles: the spoken transcript, the text burned into the frame, the opening hook and the structure.

### \[0.0.24] - 2026-07-29

#### Fixed

- **The server's own bookkeeping now survives the platform moving it to another host.** The records
  it keeps about tool calls were saved every so often and whenever a run was stopped by hand, but not
  when the platform moved the server — so those moves lost whatever had accumulated since the last
  save. Results returned to callers were never affected; only the run's own summary records were.

### \[0.0.23] - 2026-07-29

#### Changed

- **The Store listing now says what this server does** — six tools covering follower and following
  export, profile enrichment, similar-account discovery, keyword and location search, and post
  engagers, returning up to 38 fields per profile — and the price line shows the per-profile price
  instead of a generic label. Written so an AI agent browsing the MCP directory can tell what it
  gets. The listing previously said five tools; there are six.

### \[0.0.22] - 2026-07-28

#### Added

- **A "Live Status" link in the run's Output tab.** The status page was always being saved, but
  nothing linked to it. The link opens it during the run and still opens it afterwards.

#### Fixed

- **The status page now keeps up with the run.** It was only rewritten once every ten tool calls, so
  a server that had handled fewer than ten showed the start-up screen no matter how much work it had
  actually done. It now refreshes within ten seconds of a tool call — and stays quiet while the
  server is idle, so an always-on server does not accumulate pointless rewrites.

### \[0.0.21] - 2026-07-28

#### Added

- **Sixth tool — `instagram_post_engagement_discovery` (Mode 6).** Give it one or more Instagram post or reel links and it returns the accounts that liked or commented on them, enriched with the same profile fields as every other tool. Three new columns come with it — `Liked Posts`, `Comments Left`, `Posts Engaged` — so an agent can rank results by how much each account engaged. `engagementType` selects likers, commenters, or both. Matches the parent actor's Mode 6 one-for-one, including pricing: $0.01 per analyzed profile, no new event.
- **The tool reports how much of each post it could see.** Instagram serves a post's likers as one capped sample with no way to page past it, so a high-engagement post returns part of its liker list. The tool summary names the posts that came back partial with their returned-versus-declared counts, so an agent is never handed a truncated list presented as a complete one. Comments are read page by page, so `engagementType: "commenters"` returns a set that can be verified complete.
- Private accounts that liked or commented are skipped before analysis — Instagram publishes no profile data for them, so they can never become a row and are now never fetched or billed.

#### Changed

- Post links that cannot be opened are named individually in the tool summary, with the reason: deleted, private, or not a post link at all. The call proceeds with whatever links did open, and fails only if none of them did.

### \[0.0.20] - 2026-07-28

#### Added

- **Your first run no longer pays for profiles your filters reject.** Setting up filters for the first time is buying information about what the filters do, not data. On a customer's first run, a profile rejected by a filter is not billed — until the run finds its first match, at which point the filters are demonstrably working and normal billing resumes. Up to 100 rejects per run are covered. `RUN_SUMMARY.filterRejectsWaived` reports how many.
- **A run that saves nothing because of filters now names the filter that did it.** Instead of generic "loosen the strictest filter" advice, the message names the field by the exact title it carries in the Input form and shows what the rejected profiles actually looked like — e.g. `12 rejected by "Follower Count Range: Min" — the profiles we found had 14,320–291,698 followers, your minimum is 999,999,999`. Over MCP the same explanation rides the tool result, so the calling agent can loosen the filter and retry without a round trip to the user.
- Every filter in the MCP tool schemas now describes what it rejects, so an agent choosing filters can tell in advance which ones are aggressive.

#### Fixed

- **The charge is settled after the filter verdict, not before it.** Ordering change only for a first run (see above); for every other run the billed amount is unchanged.
- README, FAQ and the filter field descriptions no longer imply filters reduce what you are billed. They narrow the result set: a profile retrieved and then rejected still counts, with the first-run exception above. The "Follower Count Range" field also no longer recommends the 5 000–100 000 band, which measured badly as a starting point.
- Field descriptions now state what silently rejected everything before: the engagement-rate filter drops accounts with no readable posts, the Reel-recency filter drops accounts that post no Reels at all, and the contact-info filter reads data that only professional accounts publish.

### \[0.0.19] - 2026-07-06

#### Fixed

- **Timestamp filters work again** (last post / last Reel / posts-per-period). Around 2026-06-25 the post date started arriving under a different name, which made every profile look like it had "no media found to apply last post filter" — any tool call using `lastPostDays`, `lastReelDays`, `minPostsInPeriod`, or posts-per-month metrics returned 0 results while still charging for the scan. Both forms are now accepted for posts and Reels, restoring documented behavior.
- Reel view counts now match their posts reliably, even when post and Reel IDs come back in different formats.

### \[0.0.18] - 2026-07-03

#### Fixed

- **Billing now matches the documented rule everywhere.** The `PROFILE_ANALYZED` event fires at the moment a profile is successfully retrieved and analyzed — exactly as the pricing table and the narrow-filters heads-up always described. Not-found, private, and failed retrievals are never billed (unchanged); a retrieved profile that one of your filters rejects afterwards is billed (previously it slipped through unbilled, contradicting every documented surface and the parent scraper).
- **Runs that fail on a missing or invalid input now explain themselves.** Every validation stop (no target accounts, both list toggles off, no seeds/queries/locations, unknown mode, depth-2 on a free plan) writes a `USER_MESSAGE` naming the exact form field to fix, with a starter example — and the run's status message carries the specific error. A Mode 1 regular run with an empty "Target Accounts" field previously completed silently with 0 rows; it now stops with the same clear guidance.
- **The free-plan profile cap is recorded only when it actually bites.** `FREE_LIMITS_APPLIED` previously listed the Mode 1 profile cap whenever a large `maxCount` was requested, even when the target's list was smaller than the ceiling; now it appears only when the cap truly bounded the read.
- The demo trial-cost line now includes Mode 1's list-fetch event: a default demo run costs at most $0.20, not $0.10.

#### Added

- **Zero-result runs are diagnosed, not just completed.** A regular run that saves 0 profiles now writes a `USER_MESSAGE` with the cause (all filtered vs unreachable vs empty source), the top fix, a verified starter input, and an honest billing line — and the live status page shows this diagnosis instead of a bare stats grid.
- `RUN_SUMMARY` now reports `profilesCharged`, `listFetchesCharged`, and `cost.spent` — the real billed counts for the run.
- README: example agent prompts per tool, VS Code and Claude Code connection snippets, 6 new FAQ entries, and 2 new related actors.

### \[0.0.17] - 2026-06-12

#### Added

- **Partial list reads are no longer silent.** When a Verified or Business target's followers/following read is cut off deep in the list (1,000+ entries already delivered) by a persistent failure, the `instagram_analyze_followers_following` tool result now says so: the summary text notes the cut, and `structuredContent` gains an additive `partialListReads` field with the exact delivered/declared numbers per list. Regular (non-MCP) runs surface the same hint via `USER_MESSAGE` and `RUN_SUMMARY.partialListReads` — matching the parent Instagram Profile Scraper's behavior. Billing and all existing fields are unchanged.

### \[0.0.16] - 2026-06-10

#### Fixed

- **The narrow-filters heads-up (0.0.15) now names the cost-control field for your mode.** The warning always suggested validating with a small `maxCount`, but only Mode 1 reads that field — Modes 2–5 read `maxCountList` / `maxCountExpansion` / `maxCountDiscovery` / `maxCountLocation`. The suggestion now always matches the mode you are running.
- On free plans the heads-up no longer counts filter options that the free plan does not apply — predictions match what the run will actually do.
- With **Filter Combination = OR**, combining Keywords with a Business Category no longer over-states the expected filtering.
- The MCP `initialize` handshake and the `GET /` info endpoint now report the actor's real build version instead of a stale `0.0.1`.

#### Changed

- The heads-up now also accounts for the engagement, posting-recency, views and follower-range filters when estimating how much of a fetched list will be kept. MCP tool calls remain unaffected — the heads-up only applies to regular Apify runs.

### \[0.0.15] - 2026-06-10

#### Added

- **Heads-up before launching a regular run with very narrow filters.** Some filter combinations (for example **Contact Info** combined with **Profile Language**, or **Keywords** combined with **Location Keywords**) save only a small fraction of fetched profiles — billing is per fetched profile, not per saved profile, so a big run with such filters can be much pricier per saved result than expected. Regular runs now write a pre-run warning estimating the expected save-rate, suggest validating yield with a small `maxCount` first, and write the prediction to a new `FILTER_BURN_PREDICTION` record in the run's Storage tab. No change to billing, run behaviour, or input schema. MCP tool calls are unaffected — the warning is only relevant for regular Apify runs.

### \[0.0.14] - 2026-06-05

#### Fixed

- **More patient when Instagram briefly returns a server error on the first account lookup.** The account-resolution step now uses the same long retry window the followers / following list reads already use — short hiccups no longer abort the MCP tool call with zero results. No change to behavior on successful runs; no change to billing.

### \[0.0.13] - 2026-06-03

#### Fixed

- Profile-category filters (**Filter for Influencers Only** and **Filter by Specific Business Category**) now match category names regardless of capitalisation. Previously, a profile whose category came back as `"Digital creator"` was treated as different from `"Digital Creator"` — the same string with one letter cased differently — and was incorrectly excluded. On creator-heavy queries this was rejecting up to ~45% of analysed profiles. No input change needed; existing filter settings are strictly more inclusive after the fix.

### \[0.0.12] - 2026-05-29

#### Added

- A short callout near the top of the README announcing the new **Instagram Follower Tracker** — a sibling Actor (same author) that reports who started following and who unfollowed any public account over time. Links to its Store page for anyone who wants change-over-time monitoring rather than a one-time scrape.

### \[0.0.11] - 2026-05-25

#### Fixed

- Large follower / following lists now finish reliably even if a single page briefly hiccups partway through. Before, one temporary blip while reading a long list could stop the read early and return a truncated list; the read now waits and retries that page before moving on, so big accounts come back complete.

### \[0.0.10] - 2026-05-22

#### Changed

- Maintenance build — no user-facing changes.

### \[0.0.9] - 2026-05-22

#### Changed

- Added the new **Instagram Follower Tracker** (track who follows / unfollows a public account over time) to the Related actors section. No change to input, output, behaviour, or pricing.

### \[0.0.8] - 2026-05-11

#### Changed

- **README** — Dropped the `How to use it (in one screen)` section. Its content overlapped with Quick start (just above) and the mode picker in INPUT\_SCHEMA. Same input, output, and pricing.

### \[0.0.7] - 2026-05-08

#### Changed

- Maintenance build — no user-facing changes.

### \[0.0.6] - 2026-05-07

#### Changed

- **README** — refreshed structure for clarity (restored prior section layout). Same input, output, dataset shape, and pricing.

### \[0.0.5] - 2026-05-07

#### Changed

- Maintenance build — no user-facing changes. Input schema, output dataset columns, KVS records, console output, error messages, defaults, and pricing are all unchanged from 0.0.4. Saved tasks continue to work identically.

### \[0.0.4] - 2026-05-07

#### Changed

- **README** — aligned to Apify quality template (same shape as the parent and sibling actors). Hero rewritten with value-first prose and a "beyond what Instagram's official Graph API offers" comparison; numbered 3-step Quick start; new `🧭 When to use it` (5 numbered scenarios); new `⭐ Choose your tool` table covering all 5 MCP tools; new `💡 Tips & Best Practices` section (4 sub-sections × 3 bullets); new `🛟 Support & feedback` section pointing to Apify Store reviews / bookmark / Issues tab; new dedicated `⚖️ Is it legal to scrape Instagram?` H2 with link to Apify's web-scraping legality blog; FAQ expanded from 5 to 10 Q\&As (legality, ban risk, MCP vs regular run, Standby costs, agent auto-discovery, data freshness, cost cap). Section order normalized to match the family. No functional changes — same data, tools, pricing, schema.

### \[0.0.1] - 2026-05-07

#### Added

- **First public release.** Instagram Profile MCP Server — wraps the [Instagram Profile Scraper](https://apify.com/afanasenko/instagram-profile-scraper) parent as a Model Context Protocol server with 5 narrow agent tools (Standby `/mcp` endpoint).
- **5 MCP tools, one per parent mode**: `instagram_analyze_followers_following` (Mode 1), `instagram_analyze_specific_accounts` (Mode 2), `instagram_network_expansion` (Mode 3), `instagram_keyword_discovery` (Mode 4), `instagram_location_discovery` (Mode 5). Each tool exposes a narrow Zod schema (mode-specific required fields + a single `filters` / `extraction` object) so AI clients can pick by intent without inspecting the parent's 60-field INPUT\_SCHEMA.
- **Hybrid input** — actor accepts both Standby `/mcp` JSON-RPC tool calls and regular Apify run input (with `operationMode` + per-mode fields), so customers can use the same actor as MCP server OR as a one-shot run-input/output actor via Apify Console / `apify call` / API. Same 5 modes, same dataset shape on both paths.
- **Parent-parity data**: 38-column dataset (Account, Source, Tagged Location, Matched By, Mutual Follow, Full Name, Followers Count, Bio, Email, Phone, External URL, Category, Reels Count, Median Views, Avg Likes, Avg Comments, Posts per Month, Median ER, Quality, Post 1–8, etc.). Mapping function populates every column using the same logic as parent.
- **Parent-parity pricing**: `PROFILE_ANALYZED` $0.01 + `USER_LIST_FETCHED` $0.10 (Mode 1 only) — same FREE-tier prices as the parent scraper. Mirrors parent's tiered Console pricing 1:1.
- **Parent-parity FREE-plan paywalls**: 50 profiles per run cap, 3 targets in Mode 1, 5 expansion profiles in Modes 3/4/5, masked emails (`j***@a***.com`), Reels analytics + view/follower ratio + `searchDepth=2` paid-only. Each ceiling hit is recorded in `FREE_LIMITS_APPLIED` for transparency.
- **Test-run cap (≤$1)** — when input matches a demo seed (`natgeo` / `openai, claudeai` / `openai`) at default with no `maxCount`, the run is capped at 10 profiles (~$0.10 trial cost) on any plan.
- **5 storage records** mirroring the parent: `RUN_SUMMARY`, `SKIPPED_ACCOUNTS`, `FREE_LIMITS_APPLIED`, `USER_MESSAGE`, `status.html`. Standby instances aggregate counters across all MCP tool calls in the same instance and flush every 10 calls + on `Actor.exit` + on `aborting`.
- **All 4 Apify schemas + KVS schema** wired in `.actor/actor.json`: `input_schema.json`, `output_schema.json`, `dataset_schema.json`, `web_server_openapi.json` (OpenAPI 3.0.3 for `/mcp` Streamable HTTP), `key_value_store_schema.json`.
- **Filter parity**: every search filter the parent forwards (follower range, contact info, language, engagement, post-cadence, view/follower ratio, business category, AND/OR keyword combination) is supported in the wrapper.
