When we built Follower Change, the first architectural decision was also the constraint everything else had to survive: the analysis runs entirely in the user's browser. A follower export is someone's whole social graph. We didn't want it on our servers, so the parser, the comparison engine, and the results all live client-side. No upload endpoint exists for follower data — there's nothing to call.
That decision sounds simple until you meet the actual export formats. "Download your data" turns out to mean something different on every platform:
Instagram gives you JSON, but the shape depends on which list you asked for. Followers arrive as a top-level array of entries, each carrying string_list_data with a value (the username) and a timestamp. Following comes wrapped in a relationships_following object instead. And on larger accounts the followers list is split across shard files — followers_1.json, followers_2.json, and so on — which a user may upload one at a time. (An early lesson: shards from different platforms behave differently; our parser merges Facebook's shards and X's parts automatically, and we had to be explicit with users that Instagram's split files each need uploading.)
X doesn't give you JSON at all. Its archive contains JavaScript files:
window.YTD.follower.part0 = [ { "follower": { "accountId": "1252851", ... } }, ... ]
Executing that in the browser would be an obvious non-starter — uploaded bytes are untrusted input. We strip the window.YTD.<key>.part<N> = prefix as text and JSON.parse the remainder. Same rule everywhere in the pipeline: no eval, no DOM injection, no executing anything a user uploads.
HTML exports (Instagram offers one) get parsed inertly: we harvest instagram.com profile links and nothing else — no scripts run, no markup is rendered.
Underneath the formats, the pipeline is deliberately boring:
upload → validation → format detection → parser → normalize → dedupe → compare
Three details from that pipeline are worth stealing for any file-processing tool:
- Never trust the MIME type or the extension. Format detection goes magic bytes → content sniffing → extension, in that order. Users rename files; platforms mislabel them.
-
Normalize usernames aggressively, but honestly.
@Alice,Alice, and a full profile URL all canonicalize toalicebefore deduplication, or your comparison fills with phantom differences. But normalization has rules you can't invent: when we documented the spreadsheet version of this comparison, the correct formula removes@only when it's the first character — blanket replaces corrupt usernames that legitimately contain odd characters. - Cap everything. ZIPs (we unzip in-browser with fflate) get a hard entry cap — ours is 200 entries — plus traversal guards, because an archive is just a polite name for a bundle of untrusted files. Oversized full-account archives are the common failure, so the error message tells users to upload the follower files directly instead.
What does the comparison itself look like once the data is clean? Two set operations, honestly labeled. Followers minus following (and vice versa) on a current export tells you who doesn't follow you back. Comparing two snapshots from different dates tells you which accounts were present before and absent later — and we label that "may have unfollowed" / "lost followers," never "unfollowed you," because absence from a later export doesn't prove intent, timing, or even that the account still exists. An analyzer that claims more than the data supports is lying to its users in a friendly font.
The browser-only constraint costs us things a server would make easy: no background processing for huge archives, no cross-device history unless a user saves a report to their account. We think it's the right trade. The data was never ours to hold.
If you want to try it: Follower Change works from the official exports of Instagram, Threads, TikTok, X, Facebook, YouTube, and LinkedIn. A free account includes 100 credits and an analysis costs 10 — the account exists for credits and saved reports; your follower files still never leave your browser.
I'm happy to answer questions about any of the export formats — especially if you've fought the X archive or TikTok's JSON before. Those two have the most surprises per kilobyte.
Top comments (0)