Is InsTF - Instagram follower & unfollower tracker safe?
InsTF sends the signed-in user's Google email address and Instagram profile statistics to Mixpanel on account sign-in and follower-tracking task execution.
When a user signs in via Google OAuth, the extension forwards their email address and membership status to Mixpanel's People API, linked to a persistent UUID stored in chrome.storage.sync. Each time the user runs a follower-tracking task against their own Instagram account, it also sends their Instagram username, follower count, following count, and media count to Mixpanel. Task lifecycle events — including the target Instagram account ID and task type — are transmitted to api-js.mixpanel.com on task start and completion.
Who publishes itNeo Ext Team - 2 other listings from the same operator, none carrying a finding
Neo Ext Team - 2 other listings from the same operator, none carrying a finding
What this publisher told the store about itself, and the other listings that told it the same thing.
Same store account
2 other listings published from this account, 11k+ users between them, none of them carrying a finding.
Shared hosts - 1 hostname
Hostnames hardcoded in this extension that few other listings call. That can mean one operator behind both, and it can equally mean a small shared vendor, so it is context rather than a conclusion. Hosts that many listings call are left out: they are services, not connections.
AI-generated. Findings may contain errors. Those marked Verified have been manually reviewed.
Publishers can request a review.
Findings
Google email and Instagram task data sent to Mixpanel
After Google sign-in and follower-tracking actions, code shows the extension attaches your email, membership fields, Instagram stats, and download counts to a Mixpanel profile/event.
Captured POSTs only showed page-view/profile analytics.
What actually happens
You sign in with Google or start an Instagram follower-tracking task.
Download actions from scraped Instagram results also trigger analytics events.
The extension adds account, profile, task, and count fields to Mixpanel profile updates or event calls.
The sensitive sign-in and task fields are shown in code; the available captured Mixpanel traffic did not include those fields.
Fields the shipped code passes to Mixpanel
- Analytics identifier6fce7a7d-4c0e-4e5b-9bc6-6b0dc81db0e2 (illustrative)
Lets Mixpanel tie future sign-in, task, and download events to the same browser profile.
- Google account emailalex.rivera@example.com (illustrative)
Identifies the Google account used to sign in to the extension.
- Membership recordmembership: Pro; is_yearly: true; starts_at: 2026-01-15T00:00:00.000Z; ends_at: 2027-01-15T00:00:00.000Z (illustrative)
Adds subscription context to the same analytics profile.
- Instagram profile statisticsusername: alexruns; media_count: 92; follower_count: 1842; following_count: 730; profile_url: https://www.instagram.com/alexruns/ (illustrative)
Links your Instagram username and follower counts to the analytics profile when you track your own account.
- Task target and settingstarget: 17841400001234567; actionType: getProfile; loopType: follower; total: 250 (illustrative)
Shows which Instagram account or list the extension was asked to process and how the task was configured.
- Downloaded contact countsfilter: email; total: 250; emailCount: 18; phoneCount: 4 (illustrative)
Summarizes how many scraped profiles had email or phone fields in the downloaded result set.
Captured request
Observed during dynamic analysis from www.listmore.info; the recorded body contained page-view token/current_url analytics, not the sign-in or task fields shown in code.
Captured request
Observed during dynamic analysis from www.listmore.info; the recorded body contained profile set-once token/current_url analytics, not the sign-in or task fields shown in code.
The code that does this
Mixpanel setup, profile updates, task events, and download events
Persistent Mixpanel identifier in deobfuscated code
dist/contentScripts/index.global.jsasync function MV() { let t = (await it.storage.sync.get("MIXPANEL_USER_ID")).MIXPANEL_USER_ID; return t || (t = globalThis.crypto.randomUUID(), await it.storage.sync.set({ MIXPANEL_USER_ID: t })), t}Mixpanel token, identify, and first-seen update in deobfuscated code
dist/contentScripts/index.global.jsconst Vk = { InsTF: { mixpanel_token: "8f728f9dda62790d6831ca89119dee88", sentry_DSN: "https://9d1a7261a888a4a542c01ad9396072b8@o4507079421394944.ingest.us.sentry.io/4507079424081920" } }, qk = Vk.InsTF.mixpanel_token;async function XG() { try { _r.init(qk, { debug: !1, persistence: "localStorage" }), _r.register({ ext_name: "InsTF", ext_version: "6.1.11" }); const e = await MV(); _r.identify(e), _r.people.set_once({ "First Seen": new Date().toISOString() }) } catch (e) { console.error("Failed to initialize Mixpanel:", e) }}XG();Google sign-in profile fields sent to Mixpanel in deobfuscated code
dist/contentScripts/index.global.jsasync function a() { try { o.value = !0; const w = await nA("launch-web-auth-flow", { url: n.href }), b = new URL(w.redirectedTo), E = new URLSearchParams(b.hash.substring(1)), { data: T, error: k } = await s.auth.signInWithIdToken({ provider: "google", token: E.get("id_token") || "" }); if (k) throw k; { fs("signInWithGoogle", T.user); const S = T.user; await l({ id: S.id, email: S.email, full_name: S.user_metadata.full_name }), ["InsC", "InsGrow", "InsFo"].includes("InsTF") && await u() } } catch (w) { fs("signInWithGoogle catch error", w, it.runtime.lastError) } finally { o.value = !1 }}async function l(w) { const { data: b, error: E } = await s.from("InsTF").upsert({ ...w }, { onConflict: "id" }).select().single(); E && (console.error(`createOrUpdateSupabaseUser error: ${JSON.stringify(E)}`), s.auth.signOut(), lt.value = {}), fs("createOrUpdateSupabaseUser", b), lt.value = b, b.created_at || await s.from("InsTF").update({ created_at: new Date().toISOString() }).eq("id", b.id), _r.people.set({ email: b.email, membership: b.membership, is_yearly: b.is_yearly, starts_at: b.starts_at, ends_at: b.ends_at })}Task profile stats and task object sent to Mixpanel in deobfuscated code
dist/contentScripts/index.global.jsRt(async () => { const g = PV(), p = g.uuid; r.value = (await it.storage.local.get(p))[p], await d(l.value); async function m() { const x = Wn.getMyId(); if (!x) return _r.track("Not Login", { profileId: x }), !1; const y = (await it.storage.local.get("trackMySelfInfo")).trackMySelfInfo || {}; if (x !== y.id) { const w = await Wn.getProfile(x); await it.storage.local.set({ trackMySelfInfo: { id: w.id, username: w.username } }), y.id = w.id, y.username = w.username } return r.value.username === y.username } async function _() { return await m() ? (n.value = !0, await Wn.getProfile(Wn.getMyId())) : await Wn.getProfile(r.value.username, "username") } if (!r.value.target && r.value.username) try { const x = await _(); r.value.target = x.id, r.value.profile = x, o.value.unshift(p), a.value.unshift(r.value), await it.storage.local.set({ [p]: r.value, [l.value]: [...o.value] }) } catch (x) { Gp(x, { ...r.value, isTrackMySelf: n.value }); return } if (fs("trackTask", r.value), n.value) { const x = r.value.profile; _r.people.set({ username: x.username, media_count: x.media_count, follower_count: x.follower_count, following_count: x.following_count, profile_url: x.profile_url }) } _r.track("Task Start", { ...r.value }), c.value = u.value.length === 0, g.isFirstTrack && (c.value = !0)});async function f() { r.value.isCompleted = !0, await it.storage.local.set({ [r.value.uuid]: r.value }), await d(l.value), _r.track("Task Completed", { ...r.value })}Download event counts sent to Mixpanel in deobfuscated code
dist/contentScripts/index.global.jsfunction c(g) { const p = ["email", "phone"].includes(g) ? l(g) : r.items; a(p, n.value), _r.track("Download", { target: r.target, loopType: r.loopType, actionType: r.actionType, format: n.value, filter: g, total: r.items.length, emailCount: p.filter(m => m.email).length, phoneCount: p.filter(m => m.phone).length })}function u() { a(r.items, n.value), _r.track("Download", { target: r.target, loopType: r.loopType, actionType: r.actionType, format: n.value, total: r.items.length })}function h() { if (d.value) { const g = NV(r.items); a(g, n.value, `${i.value}-distinct-${g.length}`), _r.track("Download", { target: r.target, loopType: r.loopType, actionType: r.actionType, format: n.value, total: g.length }) } else u(); f.value = !1}Analytics destinations observed or configured by the extension
- api-js.mixpanel.com
Mixpanel analytics API receiving profile updates and tracked events from the extension code.
- o4507079421394944.ingest.us.sentry.io
Sentry error-reporting endpoint configured next to the Mixpanel token; not the destination for the Mixpanel profile and task events in this claim.
Where it sends data
Destinations our analysis observed InsTF - Instagram follower & unfollower tracker contacting. Sending data somewhere is not a finding on its own - an extension that syncs your settings has to talk to its own server - but it is where your data can go, and who else it goes to.
- api-js.mixpanel.comwidely used
InsTF - Instagram follower & unfollower tracker sends data to api-js.mixpanel.com. A widely used service: 48 other extensions we have analyzed send data here.