Coverage and methodology
Public hashtag activity observed by this index across participating and monitored servers.
Why a complete count is impossible
The Fediverse has no centre. Each server knows about posts its own members wrote, plus posts that reached it because somebody there follows the author, or because a relay forwarded them. Two servers looking at the same hashtag see overlapping but different sets of posts.
So this index reads several well-connected servers and merges what they report. That gives a broad view. It is not a complete one, and the shortfall cannot be estimated reliably, because the size of what is missing is exactly the thing no server can see.
Reading one hashtag from three servers at the same moment returned 40 posts from any single server and 50 unique posts from all three together. Adding servers keeps finding more, with diminishing returns and no point at which the curve is known to have finished.
How coverage is shown
Every count is published with the number of servers monitored, the number reporting successfully, which servers contributed, the median number of servers that saw each post, and the time of the last successful update.
That median is the most useful number on a tag page. If a typical post was seen by six of eight monitored servers, the index is watching the well-connected middle of the network. If most posts were seen by one server, it is catching fragments, and the count should be read as a lower bound.
What is counted
Public posts only, meaning posts a logged-out visitor could read on the origin server. Unlisted, followers-only and direct posts are excluded, as are posts from servers that have opted out. Windows are cut on the post's own timestamp, not on when this index saw it.
Author counts are exact for what was observed, and are produced without keeping a list of authors. Each handle is hashed with a secret salt before storage, which gives a stable key for counting distinct people and nothing that identifies them.
Trends
A trend compares a window against the window immediately before it. That comparison only holds if the index saw about as much in both periods, so when servers were unreachable during either window no trend is shown at all. An absent trend means the comparison could not be made honestly, not that activity was flat.
How tags are chosen
This index polls a limited number of hashtags, because every tracked tag costs requests and database writes and the budget is fixed. So tags have to earn a slot, and some have to lose one.
Most tags arrive by being noticed rather than by being asked for. A post collected for one hashtag usually carries others, and those become candidates. It costs nothing to see them, because the request has already been made.
Three tests, and why it took three tries
A candidate needs at least 5 distinct authors, at least 3 distinct origin servers, and no more than 5 authors per server before it is polled.
The author count is the obvious test. It stops a single enthusiastic account earning a slot by posting the same tag two hundred times, and counting distinct people rather than uses is what makes that impossible rather than merely unlikely.
It is not enough on its own, and the reason is worth explaining because it took two failed attempts to get right. An automated news feed running fifteen accounts on two servers has fifteen genuinely distinct authors. By author count it is indistinguishable from a conversation.
The first attempt required a minimum number of origin servers. That worked on the sample it was built from, where the feeds sat at 2 to 3 servers and genuine tags at 31 to 69. Twelve hours later the feeds had reached 4 to 7 servers and were passing the test. Breadth grows the longer you watch, so a threshold set from a snapshot ends up in the wrong place.
The second attempt was posts per author, which looked independent of scale and
was not. It would have retired #news, one of the most active genuine
tags in the index, because a busy tag accumulates posts against a stable pool of
authors and its ratio climbs just as a feed's does.
What holds still is authors per server:
| Tag | Authors | Servers | Authors per server |
|---|---|---|---|
| an automated feed | 67 | 4 | 16.8 |
| another | 33 | 4 | 8.3 |
| #news | 384 | 99 | 3.9 |
| #photography | 161 | 65 | 2.5 |
| #buddhism | 7 | 3 | 2.3 |
A publisher adds accounts without adding servers. A conversation spreads across servers as it gains people, so both numbers grow together and the ratio stays flat however large the tag gets. Measured at two points twelve hours apart, the feeds sat at 7 to 30 and the genuine tags at 2.3 to 3.9, and neither cluster moved.
What these tests cost
The server floor is deliberately low, at three, because it is no longer doing the work of spotting publishers. It only excludes hashtags confined to one or two servers. Those are a single server's local timeline rather than activity across the network, and this index would see them at all only if it happened to monitor that server.
Keeping it low matters. An earlier, higher floor would have excluded
#buddhism, a real community of seven people across three servers. Small
communities are exactly what an index like this should surface, so a test that
mistakes small for fake is a bad test.
Losing a slot
A tag stops being polled when it has produced nothing for a day and nobody has asked about it for a week, or when it turns out to be a publisher rather than a community on the figures above. Both thresholds are applied to tags already being polled, not only to new ones, so a tag admitted before a rule existed is judged by it too.
A hashtag somebody has asked about recently is never dropped. Someone watching a quiet tag is a perfectly good reason to keep watching it.
Asking for a tag
Searching for a hashtag counts as asking for it, and a request goes ahead of anything found automatically, because you are waiting on the answer and a noticed tag is not. If the index is at capacity your request is recorded and takes the next free slot. The page will say plainly that the tag is not being collected yet rather than showing you windows and letting you assume it is.
One signal recorded but not acted on
The average number of hashtags on the posts carrying a tag is measured and shown on the all tags page. A post with fifteen hashtags is a broadcast and a person tagging usually manages three. It is published rather than enforced, because nothing has yet slipped through that it would have caught, and guessing at thresholds without evidence is precisely what the two failed attempts above did wrong.
Monitored servers
Capability is probed per server and re-probed weekly. It is never inferred from software version, because version does not predict it: a server running a 4.8 development build was found refusing requests that 4.7.0 servers allowed.
timeline (7)
Public hashtag timelines readable without a token. Fully collected.
fosstodon.org, hachyderm.io, mas.to, mastodon.online, mastodon.social, mastodon.world, techhub.social
tags_only (2)
Hashtag timelines refused, daily tag counters readable. Used for corroboration only.
infosec.exchange, mstdn.social
Known limitations
- Coverage is partial by an amount that cannot be measured.
- Servers requiring authentication for public timelines are largely invisible, except where their posts reach a monitored server through federation.
- Deletions are not visible. Polling provides no deletion signal. No post content is stored and records expire after 25 hours.
- Edits are not tracked. A post is counted once, at its original timestamp.
- Monitored servers are weighted by their own federation reach, and the index cannot tell when a region of the network is missing entirely.
- Non-Mastodon platforms are covered only incidentally, when their posts reach a monitored Mastodon server.
- Counts can fall as well as rise, because retention expires and opted-out servers are removed retrospectively.
Opting out
Servers. Email neil@bleepsystems.com, or serve a
robots.txt disallowing fediverse-hashtag-index.
Polling stops on the next collection tick, and observations attributed to the server are
removed at the next retention sweep. The server is then listed here as opted out, so its
absence is visible rather than silent.
Authors. Email the same address. The handle is hashed and added to a suppression list holding hashes only, and existing observations matching it are deleted. An author whose handle changes will need to ask again.
The collector identifies itself on every request as
fediverse-hashtag-index/0.1 (+https://fediverse-hashtag-index.neil-charlton.workers.dev/coverage; public hashtag activity index, opt-out on that page; neil@bleepsystems.com) and is never disguised.