Instagram Growth Tracker avatar

Instagram Growth Tracker

Pricing

from $2.50 / 1,000 profile snapshots

Go to Apify Store
Instagram Growth Tracker

Instagram Growth Tracker

Track public Instagram accounts over time. Monitor follower gains, following changes, posting activity, engagement trends, growth velocity, 7/30/90-day comparisons, milestones and alerts from stored historical snapshots. Built for scheduled runs.

Pricing

from $2.50 / 1,000 profile snapshots

Rating

0.0

(0)

Developer

Delowar Munna

Delowar Munna

Maintained by Community

Actor stats

0

Bookmarked

2

Total users

1

Monthly active users

a day ago

Last modified

Categories

Share

Instagram Growth Tracker

Track public Instagram accounts over time. Monitor follower gains, following changes, posting activity, engagement trends, growth velocity, milestones and historical snapshots. Ideal for creator monitoring, competitor research, agencies and influencer analytics.

What this actor does

Instagram Growth Tracker observes a list of public Instagram profiles on every run, stores each observation, and compares it with the account's own history. One row = one profile × the current observation, with:

  • 📈 Deltas: followers, following and posts gained or lost since the previous observation, plus growth percentage
  • ⏱️ Velocity: followers per day / week / 30 days, normalized for uneven run intervals
  • 🗓️ Period comparisons: 24 hours, 7, 30 and 90 days, each against a real stored baseline
  • 🧭 Trend: SURGING, GROWING, STABLE, DECLINING, SHARP_DECLINE and acceleration (ACCELERATING / STEADY / DECELERATING)
  • 🏁 Milestones: CROSSED_1K … CROSSED_1M
  • 🔔 Signals and alerts: follower surges and drops, posting and engagement changes, profile changes, plus alertTriggered / alertReasons ready for webhooks, Zapier, Make, n8n, Slack or email
  • 💬 Engagement (optional): average and median likes, comments and views over recent posts, engagement rate, and its change over time
  • 📝 Posting activity: latest post, posts in the last 7 / 30 days, posts per week and month
  • 🪪 Profile changes: bio, name, category, link, verification and account type, with old and new values
  • 🔁 Username changes: tracked through the stable Instagram user ID, so a rename doesn't break history

How is this different from a profile scraper?

A profile scraper answers "how many followers does this account have now?". This actor answers "how is this account changing over time?". It keeps persistent history in your Apify account and turns repeated observations into growth analytics. For one-off profile data, use Instagram Profile Scraper instead.

How it works

  1. Normalize. Usernames, @handles and profile URLs are reduced to one username. Duplicates are removed. Post or Reel URLs get a free INVALID_INPUT row, because this actor tracks accounts.
  2. Observe. The current public profile is fetched: followers, following, posts, user ID and metadata. With engagement on, recent posts are analyzed too.
  3. Look up history. The stored state for that profile is loaded under your trackerKey, keyed on the Instagram user ID.
  4. Compare. Deltas, growth %, velocity, period baselines, trend, acceleration, milestones, profile changes, signals and alerts are calculated.
  5. Persist. The observation is saved as an immutable snapshot, after validation, so a failed fetch can never overwrite good history.
  6. Output. One row per profile in the run's dataset, plus a RUN_SUMMARY record.

Growth only exists between two observations, so run the same input on a schedule: create a Task with your profile list and attach an Apify Schedule.

CadenceGood for
Daily (recommended)Most monitoring, agency reporting, competitor watch
Every 12 hoursFast-moving creators, campaign weeks
WeeklyLarge watchlists, long-term benchmarking

Hourly runs are rarely useful: follower counts move slowly, and Instagram rounds or caches them. Uneven intervals are fine. Velocity is always divided by the real elapsed time, so a missed day doesn't distort followersPerDay.

First run: the baseline

The first observation of a profile creates its baseline. Growth can't exist yet, so the row says so honestly:

{ "status": "BASELINE_CREATED", "isBaseline": true, "growth": { "followersDelta": null, "followersGrowthPct": null }, "trend": { "growthTrend": "INSUFFICIENT_HISTORY" } }

The actor never reports zero growth when there is nothing to compare with. History starts at the first observation. No history from before your first run is available or estimated.

Formulas

FieldFormula
followersDeltacurrent followers − previous followers (same for following and posts)
followersGrowthPct(current − previous) ÷ previous × 100; null when previous is 0 or unknown
followersPerDayfollowersDelta ÷ elapsed days; null under one hour of elapsed time
followersPerWeek / followersPer30DaysfollowersPerDay × 7 / × 30
engagementRate(avg likes + avg comments) ÷ followers, over the analyzed posts
engagementGrowthPctchange in engagement rate vs the previous observation, in %

7 / 30 / 90-day comparisons

Each period in growthPeriods (previous, day1, day7, day30, day90) is compared with the stored snapshot closest to that age, and only if that snapshot falls inside a tolerance window:

PeriodBaseline must be within
24 hours±6 hours
7 days±24 hours
30 days±3 days
90 days±7 days

No suitable snapshot means null, not a guess. A 30-day comparison appears about 30 days after you start tracking. Each period reports baselineAt, elapsedHours, followersDelta, followersGrowthPct, followersPerDay, followingDelta, postsDelta and engagementRateDelta.

Growth classifications

Trend uses follower growth normalized to one week, measured against a ~7-day baseline (±2 days), or else the previous observation if it is at least 12 hours old:

TrendWeekly follower growth
SURGING≥ 3% (and at least 20 followers/week)
GROWING≥ 0.1%
STABLEbetween −0.1% and 0.1%
DECLINING≤ −0.1%
SHARP_DECLINE≤ −2% (and at least 20 followers/week)
INSUFFICIENT_HISTORYno usable baseline yet

Acceleration compares follower velocity over the last 7 days with the 7 days before (or the last 24h with the 24h before, or the last two intervals between runs). ACCELERATING and DECELERATING need a change of at least 20% (minimum 1 follower/day).

Signals (trend.signals): FOLLOWER_SURGE, FOLLOWER_DROP, ACCELERATING_GROWTH, DECELERATING_GROWTH, POSTING_INCREASE, POSTING_DECREASE, ENGAGEMENT_INCREASE, ENGAGEMENT_DECREASE, FOLLOWERS_GROWING_ENGAGEMENT_FALLING, NEW_MILESTONE, PROFILE_CHANGED, USERNAME_CHANGED, POSTS_REMOVED_OR_ARCHIVED.

A negative postsDelta means posts were removed or archived. The actor can't tell which, so it doesn't claim deletions.

Alerts and webhooks

Every row has alertTriggered (boolean) and alertReasons (list). Set any of:

  • growthAlertThresholdPct, e.g. 5 → FOLLOWERS_GROWTH_PCT>=5
  • growthAlertThresholdAbsolute, e.g. 10000 → FOLLOWERS_DELTA>=10000
  • dropAlertThresholdPct, e.g. 3 or -3 → FOLLOWERS_GROWTH_PCT<=-3

A SHARP_DECLINE trend and every new milestone (MILESTONE_CROSSED_100K) always trigger an alert.

To act on alerts, add an Apify webhook on Run succeeded that calls Zapier / Make / n8n / Slack. In the receiving step, read the run's dataset and keep rows with alertTriggered: true:

GET https://api.apify.com/v2/datasets/{defaultDatasetId}/items?clean=true&fields=username,alertReasons,growth,trend

Historical storage

History lives in your own Apify account, in two named storages that persist between runs:

StorageHolds
Key-value store instagram-growth-stateLatest state per profile: identity, profile metadata, and the snapshots used as baselines, thinned to one per day after 3 days and kept for maxHistoryDays
Dataset instagram-growth-historyEvery saved observation, one immutable row each, append-only. Export it for charts or BI tools

Each run's own dataset holds that run's growth rows. Deleting the named storages resets tracking.

trackerKey isolation

trackerKey namespaces the history. Track the same account for two clients (agency-client-a, agency-client-b) and the two histories never mix. Changing a task's trackerKey starts a fresh history for it. Default: default.

Repeated and overlapping runs

A run within minSnapshotIntervalMinutes (default 30) of the last saved observation still returns a row, compared with the snapshot before it (or with that recent observation itself, when there is nothing older), but adds no history entry (historySkipReason: "MIN_SNAPSHOT_INTERVAL"). If two scheduled runs overlap, every save re-checks the stored version first. A run that lost the race recomputes against the fresh state, so the delta chain stays correct.

Private profiles, unavailable profiles and failures

  • Private profiles: public counters are tracked as normal (status: PROFILE_PRIVATE). Recent-post engagement and posting metrics are not available. The actor never bypasses privacy.
  • Not found: PROFILE_NOT_FOUND. If the username was tracked before, the status is USERNAME_CHANGED_UNKNOWN instead: the account was renamed, deleted or deactivated.
  • Temporary failures (RATE_LIMITED, BLOCKED, TEMPORARY_FETCH_ERROR, PROVIDER_ERROR) are retried on a fresh session with backoff. If they persist, the profile gets a free error row and its stored history is left untouched. The row shows the last known observation in previous, never zeros. Retryable failures are saved to the RETRY_INPUT record for an easy re-run.
  • Missing counters: a profile returned without its follower or following count gets PARTIAL_PROFILE. It isn't saved and isn't charged.
  • Posts count: some data sources don't report an account's total post count. That observation then has postsCount: null and postsDelta: null, never zero, while followers, following and posting cadence from recent posts are still tracked.
  • One failing profile never fails the run.

Username changes

Identity is the Instagram user ID, not the username. If an account renames itself and you track it under its new username, history continues and the row reports usernameChanged: true and previousUsername. If you keep tracking the old username, it stops resolving and gets USERNAME_CHANGED_UNKNOWN.

Engagement availability

Engagement is calculated from up to postsForEngagement recent public posts (default 12). Pinned posts are excluded because they are often months old, so an account with 3 pinned posts typically has 9 of its latest 12 analyzed. postsAnalyzed always shows the real number. Hidden like counts are skipped, never counted as zero, and views count only for videos and Reels. If recent posts can't be fetched, the counters are still tracked and the row says POSTS_UNAVAILABLE. Posting counts for a 7- or 30-day window are null when the analyzed posts don't reach back that far, rather than an undercount.

Login and cookies

None. You don't provide a login, password, cookies, session ID or Meta token. The actor reads only public information.

Input

FieldTypeDefaultDescription
profilesstring[]—Usernames, @handles or profile URLs (max 1,000 per run)
modeenumTRACKTRACK: compare with previous + selected periods. COMPARE: all periods. SNAPSHOT: record only
trackerKeystringdefaultHistory namespace
comparisonPeriodsenum[]PREVIOUS, 7_DAYS, 30_DAYSAlso 24_HOURS, 90_DAYS
includeEngagementMetricsbooltrueRecent-post engagement (recent-posts add-on)
postsForEngagementint12Recent posts analyzed (1–48); billed per block of 12
includePostingMetricsbooltruePosting cadence (recent-posts add-on)
includeProfileMetadatabooltrueName, bio, category, link, picture
saveHistorybooltrueOff = read-only comparison, nothing saved
maxHistoryDaysint365Baseline retention in the state store
minSnapshotIntervalMinutesint30Repeat-run protection
growthAlertThresholdPctnumber—Alert on growth ≥ this %
growthAlertThresholdAbsoluteint—Alert on gain ≥ this many followers
dropAlertThresholdPctnumber—Alert on a drop ≥ this %
proxyConfigurationobjectApify Proxy onSee Proxy policy
maxConcurrencyint10Profiles fetched in parallel
maxRetriesint3Retries per profile on temporary errors
debugModeboolfalseVerbose logging

An empty profiles list runs the example profile natgeo.

Example 1: Minimal

{
"profiles": ["nasa", "natgeo"]
}

Example 2: Daily competitor tracker (schedule it)

{
"profiles": ["competitor1", "competitor2", "competitor3"],
"trackerKey": "competitor-watch",
"mode": "TRACK",
"comparisonPeriods": ["PREVIOUS", "7_DAYS", "30_DAYS"],
"includeEngagementMetrics": true,
"postsForEngagement": 12,
"growthAlertThresholdPct": 5,
"dropAlertThresholdPct": 3
}

Example 3: Lightweight profile-only tracking

{
"profiles": ["brand1", "brand2"],
"trackerKey": "brand-growth",
"includeEngagementMetrics": false,
"includePostingMetrics": false,
"saveHistory": true
}

Output

Tabs: Growth, Period comparisons, Trends, signals & alerts, Engagement & posting, Profile, Status & errors. Every row, snapshot or error, has the same keys. Unavailable values are null, never zero.

Instagram Growth Tracker: Growth table view

The records below come from a real run with this input: 20 brand and media accounts, the second observation of each, 35 minutes after the first. Over that short gap the deltas are real, but velocity (followersPerDay, under one hour), the trend (needs a previous observation at least 12 hours old) and the 24h/7d/30d periods are still null. They fill in as the schedule builds history. Profile picture URLs are shortened with ….

{
"profiles": [
"nasa", "natgeo", "nike", "apple", "spotify",
"netflix", "starbucks", "redbull", "lego", "tesla",
"google", "adidas", "cocacola", "gopro", "airbnb",
"duolingo", "nba", "bbcnews", "louvremuseum", "nasahubble"
],
"mode": "TRACK",
"trackerKey": "readme-demo",
"comparisonPeriods": ["PREVIOUS", "24_HOURS", "7_DAYS", "30_DAYS"],
"includeEngagementMetrics": true,
"postsForEngagement": 12,
"includePostingMetrics": true,
"growthAlertThresholdPct": 0.05,
"dropAlertThresholdPct": 0.05
}

Full record: a compared profile

{
"rowType": "instagram_growth_snapshot",
"status": "SUCCESS",
"errorMessage": null,
"trackerKey": "readme-demo",
"mode": "TRACK",
"input": "redbull",
"username": "redbull",
"userId": "476322",
"observedAt": "2026-10-23T12:48:59.931Z",
"isBaseline": false,
"historySaved": true,
"historySkipReason": null,
"profile": {
"username": "redbull",
"userId": "476322",
"fullName": "Red Bull",
"profileUrl": "https://www.instagram.com/redbull/",
"profileImageUrl": "https://scontent-den2-1.cdninstagram.com/v/t51.2885-19/33020…",
"bio": "watch the World Of Red Bull👇\n#givesyouwiiings",
"category": "Personal Goods & General Merchandise Stores",
"isVerified": true,
"isPrivate": false,
"isBusinessAccount": true,
"isProfessionalAccount": true,
"accountType": "business",
"followersCount": 34222405,
"followingCount": 2148,
"postsCount": 11667,
"externalUrl": "https://onein.bio/redbull"
},
"previous": { "observedAt": "2026-10-23T12:14:21.733Z", "followersCount": 34221836, "followingCount": 2148, "postsCount": 11667, "engagementRate": 0.005391 },
"growth": {
"followersDelta": 569,
"followersGrowthPct": 0.002,
"followingDelta": 0,
"followingGrowthPct": 0,
"postsDelta": 0,
"elapsedHours": 0.58,
"followersPerDay": null,
"followersPerWeek": null,
"followersPer30Days": null,
"engagementRateDelta": 0.000045,
"engagementGrowthPct": 0.835,
"avgLikesDelta": 1559,
"avgCommentsDelta": 6.5,
"avgViewsDelta": 24982.4
},
"growthPeriods": {
"previous": { "baselineAt": "2026-10-23T12:14:21.733Z", "elapsedHours": 0.58, "followersDelta": 569, "followersGrowthPct": 0.002, "followersPerDay": null, "followingDelta": 0, "postsDelta": 0, "engagementRateDelta": 0.000045 },
"day1": null,
"day7": null,
"day30": null,
"day90": null
},
"trend": { "growthTrend": "INSUFFICIENT_HISTORY", "weeklyGrowthPct": null, "trendBaselineAt": null, "growthAcceleration": "INSUFFICIENT_HISTORY", "recentFollowersPerDay": null, "priorFollowersPerDay": null, "signals": [], "milestones": [] },
"activity": { "postsAnalyzed": 9, "latestPostAt": "2026-10-23T08:02:08.000Z", "postsInLast7Days": null, "postsInLast30Days": null, "postsPerWeek": 15, "postsPerMonth": 64.29 },
"engagement": {
"postsAnalyzed": 9,
"postsWithHiddenLikes": 0,
"avgLikes": 185374.2,
"medianLikes": 35195,
"avgComments": 664.2,
"medianComments": 155,
"avgViews": 3331798.2,
"medianViews": 753043,
"avgEngagement": 186038.4,
"medianEngagement": 35350,
"engagementRate": 0.005436
},
"changedFields": [],
"profileChanges": {},
"usernameChanged": false,
"previousUsername": null,
"alertTriggered": false,
"alertReasons": [],
"history": { "firstTrackedAt": "2026-10-23T12:14:21.733Z", "lastObservedAt": "2026-10-23T12:48:59.931Z", "snapshotCount": 2 },
"source": "direct"
}

postsInLast7Days is null here because Red Bull posts about 15 times a week, so its 9 analyzed posts cover less than 7 days.

Growth tab

{
"username": "lego",
"observedAt": "2026-10-23T12:49:23.887Z",
"profile": { "profileImageUrl": "https://scontent-lga3-2.cdninstagram.com/v/t51.2885-19/45642…", "followersCount": 14087576, "followingCount": 918, "postsCount": 6379 },
"growth": { "followersDelta": 219, "followersGrowthPct": 0.002, "followersPerDay": null, "followingDelta": 0, "postsDelta": 0 },
"trend": { "growthTrend": "INSUFFICIENT_HISTORY" },
"alertTriggered": false,
"isBaseline": false,
"status": "SUCCESS"
}

Period comparisons tab

On the second observation only previous has a baseline. day1, day7, day30 and day90 stay null until a stored snapshot of roughly that age exists.

{
"username": "apple",
"profile": { "followersCount": 38111738 },
"growthPeriods": {
"previous": { "followersDelta": 396, "elapsedHours": 0.58 },
"day1": null,
"day7": null,
"day30": null,
"day90": null
},
"history": { "firstTrackedAt": "2026-10-23T12:14:12.901Z", "snapshotCount": 2 }
}

The trend needs a previous observation at least 12 hours old, so this short-gap run has none yet. The long-history example further down shows the filled version.

{
"username": "nike",
"trend": { "growthTrend": "INSUFFICIENT_HISTORY", "weeklyGrowthPct": null, "growthAcceleration": "INSUFFICIENT_HISTORY", "recentFollowersPerDay": null, "priorFollowersPerDay": null, "signals": [], "milestones": [] },
"alertTriggered": false,
"alertReasons": [],
"changedFields": [],
"usernameChanged": false,
"previousUsername": null
}

Engagement & posting tab

Coca-Cola posts about 1.4 times a week, so its 12 analyzed posts reach back past 30 days and both window counts are filled.

{
"username": "cocacola",
"engagement": { "postsAnalyzed": 12, "avgLikes": 12064.8, "medianLikes": 3823.5, "avgComments": 313.3, "medianComments": 313, "avgViews": 31202, "engagementRate": 0.003658 },
"growth": { "engagementRateDelta": 0.000006, "engagementGrowthPct": 0.164 },
"activity": { "latestPostAt": "2026-10-22T18:33:27.000Z", "postsInLast7Days": 2, "postsInLast30Days": 5, "postsPerWeek": 1.43 }
}

Profile tab

{
"username": "nasa",
"userId": "528817151",
"profile": {
"profileImageUrl": "https://scontent-lga3-2.cdninstagram.com/v/t51.2885-19/29090…",
"fullName": "NASA",
"profileUrl": "https://www.instagram.com/nasa/",
"category": "Government Agencies",
"accountType": "business",
"isVerified": true,
"isPrivate": false,
"isBusinessAccount": true,
"externalUrl": "https://www.nasa.gov/",
"bio": "Making the seemingly impossible, possible. ✨"
}
}

Status & errors tab: a private profile

The tesla handle is a small private account (not the company's), so it shows the private-profile row: counters are tracked and charged as a snapshot, with no engagement.

{
"input": "tesla",
"username": "tesla",
"rowType": "instagram_growth_snapshot",
"status": "PROFILE_PRIVATE",
"errorMessage": "Private profile: public counters are tracked; recent-post engagement and posting metrics are not available.",
"trackerKey": "readme-demo",
"mode": "TRACK",
"historySaved": true,
"historySkipReason": null,
"source": "direct",
"previous": { "observedAt": "2026-10-23T12:14:27.137Z", "followersCount": 178 },
"observedAt": "2026-10-23T12:49:21.255Z"
}

After a few months of daily runs

A compared row then looks like this (illustrative values, trimmed):

{
"rowType": "instagram_growth_snapshot",
"status": "SUCCESS",
"trackerKey": "competitor-watch",
"username": "examplecreator",
"userId": "123456789",
"observedAt": "2026-10-17T08:00:00.000Z",
"isBaseline": false,
"historySaved": true,
"profile": { "followersCount": 148500, "followingCount": 612, "postsCount": 1284, "isVerified": true, "isPrivate": false, "accountType": "creator" },
"previous": { "observedAt": "2026-10-16T08:00:00.000Z", "followersCount": 146900, "followingCount": 610, "postsCount": 1283 },
"growth": { "followersDelta": 1600, "followersGrowthPct": 1.089, "followingDelta": 2, "postsDelta": 1, "elapsedHours": 24, "followersPerDay": 1600 },
"growthPeriods": {
"day7": { "baselineAt": "2026-10-10T08:00:00.000Z", "followersDelta": 7200, "followersGrowthPct": 5.095, "followersPerDay": 1028.57 },
"day30": { "baselineAt": "2026-09-17T08:00:00.000Z", "followersDelta": 18400, "followersGrowthPct": 14.143, "followersPerDay": 613.33 }
},
"trend": { "growthTrend": "SURGING", "weeklyGrowthPct": 5.095, "growthAcceleration": "ACCELERATING", "signals": ["FOLLOWER_SURGE", "ACCELERATING_GROWTH"], "milestones": [] },
"activity": { "postsAnalyzed": 12, "latestPostAt": "2026-10-16T19:12:00.000Z", "postsInLast7Days": 4, "postsPerWeek": 4.2 },
"engagement": { "postsAnalyzed": 12, "avgLikes": 9200, "medianLikes": 7100, "avgComments": 318, "medianComments": 244, "engagementRate": 0.0641 },
"changedFields": [],
"alertTriggered": true,
"alertReasons": ["FOLLOWERS_GROWTH_PCT>=1"],
"history": { "firstTrackedAt": "2026-07-17T08:00:00.000Z", "lastObservedAt": "2026-10-17T08:00:00.000Z", "snapshotCount": 93 },
"source": "direct"
}

Status values

StatusMeaningCharged
SUCCESSObservation compared with history✅
BASELINE_CREATEDFirst observation saved✅
PROFILE_PRIVATEPrivate account: counters tracked, no engagement✅
POSTS_UNAVAILABLECounters tracked; recent posts couldn't be fetched✅
STATE_WRITE_ERRORObservation returned but couldn't be savedfree
PROFILE_NOT_FOUND / USERNAME_CHANGED_UNKNOWN / PROFILE_UNAVAILABLEAccount missing, renamed or unavailablefree
PARTIAL_PROFILECounters missing; nothing savedfree
RATE_LIMITED / BLOCKED / TEMPORARY_FETCH_ERROR / PROVIDER_ERRORFetch failed after retries; history untouchedfree
STATE_READ_ERRORStored history couldn't be readfree
INVALID_INPUTNot a profile username/URLfree

Run summary

The RUN_SUMMARY record has: profiles requested and succeeded, baselines created, profiles compared, growing, stable and declining counts, follower surges, milestones, alerts, profile and username changes, failed and private profiles, history rows written, state conflicts, duration and fetch latency.

Scale and performance

Up to 1,000 profiles per run. Profile-only tracking (engagement and posting metrics off) is the fastest: one profile lookup each. Engagement adds up to one feed page per 12 posts analyzed (often none for 12 or fewer, when Instagram includes the latest posts with the profile). For very large watchlists, split them into several tasks with their own trackerKey, or schedule them at different times.

Pricing

Pay per event:

  • Profile snapshot: per profile successfully observed (see the ✅ statuses above).
  • Recent-posts add-on: per block of up to 12 recent posts analyzed for engagement and posting metrics. 12 posts is one block and 24 is two. It's charged only when includeEngagementMetrics or includePostingMetrics is on and posts were actually analyzed. It's never charged for private profiles or when posts couldn't be fetched. Turn both off for cheaper, counters-only tracking.

Not charged: invalid inputs, duplicates, missing, unavailable or failed profiles, and rows whose history couldn't be saved. There is no start fee. Rates can differ by Apify plan, so see the Pricing tab for the current rates on yours. This README deliberately doesn't quote figures.

The actor respects the spending limit you set for a run. Before each profile it checks that the limit still covers a snapshot plus the planned add-on blocks. When the limit covers only the snapshot, recent posts are skipped, with a note on the row. When it covers nothing more, the run stops cleanly.

🚦 Proxy policy

Use Apify Datacenter proxy (the default) or no proxy for normal runs. Both work for Instagram profile lookups at this actor's conservative concurrency.

Apify Residential proxy is not supported. The actor fails at startup if apifyProxyGroups includes RESIDENTIAL. In pay-per-event actors, residential bandwidth is billed per GB to the developer, not the run user, so a single bandwidth-heavy run could cost more than the per-result revenue.

If you need residential routing, supply your own residential provider in the proxy editor's Custom proxy URLs field. That traffic goes through your provider, not Apify, and is unaffected:

http://user:pass@proxy.iproyal.com:12321
http://user:pass@proxy.brightdata.com:22225
http://user:pass@proxy.oxylabs.io:7777

API and MCP

Call it like any Apify actor: through the Apify API, an Apify client library (JavaScript, Python), or Apify's MCP server so AI agents can use it as a tool. See the API tab for ready-made snippets. A typical integration runs a saved Task on a schedule, then reads the run's dataset (or the instagram-growth-history dataset for full time series) from a webhook.

Interpretation and limitations

  • Unofficial. This is not Instagram or Meta analytics.
  • Discrete observations. Metrics are what Instagram showed publicly at each run. Growth between runs is a difference, not an exact time of acquisition.
  • History begins at your first observation.
  • Instagram rounds and caches some counters, so very small changes on very large accounts can lag.
  • Deleted or archived posts change the total post count.
  • Engagement depends on public post metrics, which Instagram may hide.
  • Trends, signals and milestones are Coregent-derived analytics.
  • Not provided: follower demographics, organic vs paid follower growth, reach, impressions, story metrics, or any history before tracking started.

This is an unofficial tool. It is not affiliated with, endorsed by or sponsored by Instagram or Meta. It processes only publicly accessible information and never accesses private content. Profile data can be personal data. You are responsible for having a lawful basis for collecting, storing and processing it (for example under GDPR or CCPA), including the history this actor keeps in your account, and for complying with Instagram's terms in your use of the data.

Local development

cd actor
npm install
npm test # unit tests
npm start # runs with INPUT.json

History is stored locally under actor/storage/ in the same named stores, so repeated local runs produce real deltas.