If you want to track follower count over time, the API call is the easy part. Any profile endpoint returns today's number; call it on a schedule and you have a series. The hard part is what your series says about the hours you did not call — and the default answer most code gives, "same as the last value", was wrong on almost every account I measured.
I sell a social-data API, and one endpoint, profile/history, returns the follower series we have recorded for a public profile. On 2026-10-03 at 12:49 UTC I queried the table behind it: 4,043 snapshots of 37 profiles on 10 platforms, from 2026-09-08 20:00 UTC to 2026-10-03 12:00 UTC. This post is what those rows say about gaps, and how to handle them in your own tracker.
Your series will have holes
A snapshot is written when someone asks for a profile — a customer, or our own route checks. At most one row per profile per UTC hour; the first capture of the hour wins. So the series is a record of observations, not a continuous measurement.
Across the 4,006 intervals between consecutive snapshots of the same profile:
| gap between snapshots | intervals |
|---|---|
| exactly 1 hour | 202 |
| 2–3 hours | 3,611 |
| 4–6 hours | 118 |
| 7–24 hours | 56 |
| more than 24 hours | 19 |
Those 19 long gaps cover 2,067 hours between them. The longest is 402 hours: khaby.lame on TikTok was read on 2026-09-08 20:00 UTC and not again until 2026-09-25 14:00 UTC, when the count was 222,503 higher.
One of the long gaps is worth reading closely. On 2026-09-10 at 21:00 UTC, every platform went quiet at once — TikTok, Instagram, GitHub, Pinterest, SoundCloud and Bluesky for 42 hours, Mastodon, Medium and Threads for longer. Nine platforms do not stop having followers in the same hour. The thing that stopped was the caller. That is the first rule for anyone building a tracker: a gap that starts at the same moment on every account is your outage, not theirs, and it should be labelled as such, not smoothed over.
Forward-fill is the wrong default
The most common way to make a gappy series look continuous is forward-fill: carry the last known value until a new one arrives. In pandas it is one call, ffill(), and in SQL it is "latest row at or before this time". It draws a staircase, and a staircase says "nothing changed" for every hour you did not look.
To see how wrong that is, I ran a leave-one-out test on every profile with more than 50 snapshots. For each interior snapshot, I hid its value and predicted it two ways from its neighbours:
- forward-fill: the previous snapshot's value;
- linear interpolation: a straight line between the previous and the next snapshot, read at the hidden hour.
Then I compared both to the real value.
| profile | median error, forward-fill | median error, linear | linear closer |
|---|---|---|---|
TikTok nasa |
1,250 | 107.8 | 175 of 175 |
Bluesky bsky.app |
1,391.5 | 76.4 | 178 of 178 |
Instagram natgeo |
2,399.5 | 569.8 | 107 of 138 |
Instagram bbcnews |
692.5 | 122 | 118 of 134 |
Threads zuck |
135.5 | 20.3 | 130 of 148 |
SoundCloud edsheeran |
57 | 7 | 172 of 176 |
GitHub torvalds |
14.5 | 2.5 | 172 of 180 |
On every profile in the test, the median error of forward-fill was higher than the median error of a straight line. On fast-growing accounts it was not close: TikTok nasa went from 1,624,072 to 1,942,690 followers between 2026-09-10 and 2026-10-03, rose in 176 of 176 intervals, and forward-fill lost to interpolation every single time.
The close calls are the slow accounts. GitHub nasa and SoundCloud nasa had a median forward-fill error of 1 follower. Medium markmanson kept the same count in 76 of 113 intervals. Mastodon eugen@mastodon.social sat at 49 followers for all 143 snapshots. If you only track small accounts, forward-fill will look fine — until you add one that moves.
Interpolation is a better guess, and still a guess
A straight line wins because, over three or four hours, most accounts move roughly in one direction. Over a week, that stops being safe.
Instagram natgeo is the clearest case in the data. It fell from 268,602,449 to 268,451,227 followers over the period, and across its 139 intervals it dropped 111 times and rose 28. Its first gap is 164 hours long, from 2026-09-08 20:00 to 2026-09-15 16:00 UTC, and the count on the other side was 53,953 lower. Forward-fill draws that week as flat. Interpolation draws it as a steady decline. Neither is a measurement — I have no idea whether the drop happened on day one or day six, and nothing in the data can tell me.
So the rule I would use, and the one our endpoint follows:
- Store what you observed, with the time you observed it. Never write a filled value back into the same table as a real one.
- Fill at read time, and only short gaps. A few hours of linear interpolation on a big account is a reasonable estimate. A week is a drawing.
- Mark every estimated point. A separate boolean column, a dashed line, a different colour — anything a reader can see.
- Report coverage next to the number. "Up 222,503" means one thing over a continuous week and another across one 402-hour hole.
Some analytics vendors already do a version of rule 3. Socialinsider's help centre, read on 2026-10-03, says its system "automatically calculates estimated follower counts for the missing periods" and that "all estimated data appears as dashed lines on charts", without describing how the estimate is made (Socialinsider help). Showing the dashes is the important part.
The code: read the series, then fill honestly
Our endpoint returns only observed points, and says how far the record goes. Fields come straight from the database function behind the route: observations, covered_from, covered_to, truncated, followers_change, and series, where each point has window, followers, following, posts, verified and private.
curl "https://honesthook.com/api/v1/tiktok/history?handle=nasa&from=2026-10-02T18:00:00Z" \
-H "Authorization: Bearer hk_live_..."
These are the real points for TikTok nasa in that range, as stored on 2026-10-03:
{
"platform": "tiktok",
"handle": "nasa",
"observations": 7,
"covered_from": "2026-10-02T18:00:00+00:00",
"covered_to": "2026-10-03T12:00:00+00:00",
"series": [
{ "window": "2026-10-02T18:00:00+00:00", "followers": 1924009, "following": 23, "posts": 51, "verified": true, "private": false },
{ "window": "2026-10-02T21:00:00+00:00", "followers": 1927313, "following": 23, "posts": 52, "verified": true, "private": false },
{ "window": "2026-10-03T00:00:00+00:00", "followers": 1930528, "following": 23, "posts": 52, "verified": true, "private": false },
{ "window": "2026-10-03T03:00:00+00:00", "followers": 1933299, "following": 23, "posts": 52, "verified": true, "private": false },
{ "window": "2026-10-03T06:00:00+00:00", "followers": 1936143, "following": 23, "posts": 52, "verified": true, "private": false },
{ "window": "2026-10-03T09:00:00+00:00", "followers": 1940439, "following": 23, "posts": 52, "verified": true, "private": false },
{ "window": "2026-10-03T12:00:00+00:00", "followers": 1942690, "following": 23, "posts": 52, "verified": true, "private": false }
]
}
The response also carries from, to, truncated, followers_change (18,681 for this range) and the billing fields charged, quota_used, quota_total and balance, left out above. Then, in Python, put the points on an hourly grid, interpolate only short gaps, and keep a flag:
import pandas as pd
points = resp.json()["series"]
s = (pd.DataFrame(points)
.assign(window=lambda d: pd.to_datetime(d["window"], utc=True))
.set_index("window")["followers"]
.astype("float"))
hourly = s.resample("1h").asfreq() # holes become NaN, not copies
observed = hourly.notna()
# fill at most 6 consecutive missing hours, and only between two real points
filled = hourly.interpolate(method="time", limit=6, limit_area="inside")
out = pd.DataFrame({
"followers": filled,
"estimated": ~observed & filled.notna(), # draw these dashed
"unknown": filled.isna(), # draw nothing here
})
The limit=6 is my choice, not a constant of nature. Based on the leave-one-out test, a few hours is where a line is usually close; past that, leave the hole visible.
If you do not have history yet, the same series can be built from any profile endpoint — for example TikTok profile or Bluesky profile — called on a schedule and stored with its timestamp. I wrote about the trap of choosing which follower field to read in the field next to the right one, and about the other timestamp column in this same table in two timestamps per row.
Limits, and what I did not confirm
- This is not a reconstruction of the past. The history covers only the hours in which someone asked for the profile. Nobody can photograph yesterday today, so a handle nobody queried returns
observations: 0and an empty series — a 200, not a 404. - The test sample is small and biased. 37 profiles, mostly large public accounts, over about 25 days. Accounts with a few hundred followers may behave differently.
- Leave-one-out tests short gaps. Most hidden points sat between neighbours a few hours apart. I did not test how either method does across a week, because I have no ground truth inside those weeks.
- I do not know why
natgeoandnasaon Instagram lost followers in this period. The data shows the drop, not the cause. - I did not test Socialinsider's estimates. The quote above is from their help page as published on 2026-10-03.
The endpoint costs 1 credit, charged only when the range holds at least one snapshot; it is listed in the OpenAPI spec, and the rest of the API is in the docs. Get a free key, and if you build a tracker of your own, store the hours you looked — and draw the ones you did not as holes.