# Telegram view-to-subscriber survey — 9 September 2026

The dataset behind <https://novamya.com/telegram-growth/telegram-view-ratios/>.

**430 public Telegram channels**, read between **20:26:38Z and 20:57:09Z on
2026-09-09** — a 31-minute window. **325** of them published everything the
measurement needs; the other 105 are in `exclusions.csv` with the reason. That gives
**5,166 posts**, each with a view count, a timestamp, and the subscriber count of the
channel it sits on.

The channels span **30 to 9,593,612 subscribers** (median 2,149), drawn across small,
mid and large bands and across nine language lists, because the question is about the
market rather than about one corner of it.

Everything comes from the two pages Telegram serves to anyone with a browser:
`t.me/<channel>`, which prints the exact subscriber count, and `t.me/s/<channel>`,
which lists roughly the last twenty posts with a view counter and a timestamp on each.
No account was created, nothing was joined, no API was called, no search API was used,
and no private or restricted channel was touched. `t.me` serves no `robots.txt`
(HTTP 404); we rate-limited to one request every two seconds anyway, under a
User-Agent that names us.

All 430 channels were then **read again about 2.5 hours later** (22:57:40Z–23:31:18Z),
and again after that. That is what makes the age question answerable: re-reading the
same post id turns "views by post age" from an inference across different posts into
an observed measurement of one post. Across the three same-night readings it yields
**9,976 pairs** where the same post was counted twice — and those pairs say that a
post less than an hour old **gained a median 148.9%** by the second or third reading
(112.8% at the second, about 2.5 hours later; 207.5% at the third, about 6 hours
later), while a post over a week old gained less than the view counter can display in
those hours. (An earlier version of this file quoted 5,015 pairs and 113%, the figures
after the second reading only.)

On **2026-09-13, 21:24:58Z–21:55:30Z**, all 430 channels were read a fourth time, a
median of 97 hours after the first reading. `analyse.py` keeps that reading apart
(`age_curve_followup` in `stats.json`, `post_growth_followup.csv`) so none of the
same-night figures move. It gives **3,396 pairs** on the 244 channels whose first-night
posts were still in the preview, and it shows that a post under a day old at the first
reading carried a median of 46% of the views it had four days later, that posts one to
two weeks old still gained a median 11.2% over those four days, and that only posts
older than a month stood still. The 244 channels post far less often and are far
smaller than the 81 that dropped out (a median 0.43 against 13.99 posts a day, 1,007.5
against 58,808 subscribers); see `selection_note` and `why_no_pair`.

## What it answers

- What the view-to-subscriber ratio actually looks like across public channels —
  median, quartiles, and how it moves with channel size.
- How many channels show **more views than subscribers**, and why that is ordinary
  rather than suspicious.
- How views accumulate as a post ages, measured three ways, two of which are evidence
  and one of which is shown precisely because it is not.
- How much a single channel's own consecutive posts vary — the baseline anyone asking
  "why did my views drop?" is missing.

## Files

| file | what it is |
|---|---|
| `posts.csv` | one row per post: channel, subscribers, post id, UTC timestamp, age at capture, views, ratio, forward and media flags |
| `channels.csv` | one row per channel: subscribers, size band, posts captured, median ratio, spread |
| `post_growth.csv` | one row per post seen in more than one same-night wave: views then, views later, the gap, and the counter's resolution |
| `post_growth_followup.csv` | one row per first-wave post seen again four days later (wave 4), with the first reading as a share of the later one |
| `exclusions.csv` | every channel fetched and not used, with the reason |
| `stats.json` | every aggregate figure an article would quote |
| `fetchlog.tsv` | one row per HTTP request: URL asked for, URL that answered, status, bytes, UTC timestamp, content hash |
| `method.md` | sampling frame, exclusions, limitations, what the evidence does and does not support |
| `pages/frame/*.html.gz` | the public directory pages the channel list was built from |
| `pages/wN/<channel>.about.html.gz` | that channel's contact card, wave N, exactly as served |
| `pages/wN/<channel>.posts.html.gz` | that channel's web preview, wave N, exactly as served |
| `candidates.tsv`, `sample.tsv` | the frame and the drawn sample, both reproducible from a fixed seed |
| `harvest.py`, `analyse.py` | the two scripts. `analyse.py` never touches the network; run it against `pages/` and it reproduces every number |
| `post-type.py` | media vs text-only, photo vs video, and forwarded-in vs original, each compared inside the same channel, plus a label-shuffle check; reads `posts.csv` and `pages/w1/`, never the network. Behind <https://novamya.com/telegram-growth/photo-vs-text-post-views/> |
| `post-type-stats.json` | the output of `post-type.py`; every figure that article quotes beyond `stats.json` |
| `cadence-by-size.py` | posting frequency against view ratio inside each size band: within-band Spearman, cadence terciles, a partial rank correlation on subscriber count, a burst-proof cadence (median gap between posts), an age-restricted ratio (posts 2–30 days old) and a within-channel check on posts sent minutes apart; reads `channels.csv` and `posts.csv`, never the network. Behind <https://novamya.com/telegram-growth/posting-frequency/> |
| `cadence-by-size-stats.json` | the output of `cadence-by-size.py`; every figure that article quotes beyond `stats.json` |

## The 105 channels that did not make it

Nothing was dropped quietly. Of 430 usernames requested:

| | |
|---|---|
| 45 | `t.me/s/<name>` redirected to the plain contact card — Telegram declines to render those channels on the web. Both URLs are in `fetchlog.tsv`, so each one is checkable. |
| 37 | the contact card carried no subscriber line at all: the username no longer resolves to a public channel |
| 19 | fewer than five posts carried a view counter — too thin to take a median from |
| 3 | the preview listed only service rows ("pinned…"), which have no view counter |
| 1 | the preview rendered and was empty |

The loss is not spread evenly, and that matters more than the total: it runs from
about half of the small-channel stratum down to roughly a tenth of the large one,
because the deep pages of an activity ranking are full of abandoned and throwaway
usernames. `stats.json → frame_yield_by_stratum` has the per-stratum rates. Channel
size was never itself a reason to exclude anything.

## What this is not

**Not a ranking, and not an accusation.** The finding is about a distribution, not
about any channel in it. Channel usernames are in the CSVs so the numbers can be
re-derived from the stored pages, and for no other reason. A channel with more views
than subscribers is not thereby doing anything wrong: forwarding, sharing outside
Telegram, search traffic, the public web preview itself, and a subscriber count that
has fallen since the post went up all produce exactly the same reading.

**Not the whole market.** The sample is drawn from channels that appear in public
directories. Channels nobody lists are absent by construction. Every headline here is
of the form "across the N channels we could read on this date", and that is the only
form it supports.

**Not the in-app numbers.** `t.me/s/` counters may lag or differ from what the Telegram
app shows a channel owner. We never saw the app.

**Not a history.** The web preview shows roughly the last twenty posts — a few hours
for a busy channel, a year for a quiet one. These are recent posts, not a sample of
any channel's past.

## Waves

Every channel was read **three times**: a primary pass on 2026-09-09 between 20:26:38Z
and 20:57:09Z, then two revisits, the first about 2.6 hours later and the second about
six hours after that. 2,642 HTTP requests in total.

The revisits are the point. Reading different posts of different ages tells you how
views vary *across* posts; reading the *same* post again tells you how one post
actually grew. `post_growth.csv` holds 9,976 such pairs, and the growth figures in
`stats.json` come from them rather than from the cross-sectional cut.

One limit worth stating here rather than burying in `method.md`: `t.me` prints view
counts to three significant figures, so a change smaller than the counter's own step
is invisible. Growth figures are restricted to pairs whose step is under 20% of the
reading, and they therefore *understate* small increases.

## Licence

[Creative Commons Attribution 4.0 International](https://creativecommons.org/licenses/by/4.0/)
(CC BY 4.0). Reuse it commercially, republish it, build on it; the one condition is
attribution.

Cite as:

> Novamya (2026). *Telegram view-to-subscriber survey, 9 September 2026.* Dataset.
> https://novamya.com/data/telegram-view-ratios/
