·Ferret Media
The page ships no JavaScript, and that was the easy part
How a link-in-bio page ends up as one request with an inlined stylesheet — and why the hard problem was counting the visit afterwards.
Open any Linker page and view the source. There is no script tag. Not a small one, not a deferred one — none.
This is less impressive than it sounds, and more interesting than it sounds, for two different reasons.
Why it is less impressive than it sounds
A link-in-bio page is a heading, a picture, some text and a column of buttons. It has no state. It has no navigation. Nothing on it changes after it arrives. The interactive element people expect — a button that lifts slightly under the pointer — is a CSS rule.
So the correct amount of JavaScript for this page was always zero. The unusual thing is not that we got there; it is that the industry default would have shipped a framework, a hydration step and a client bundle to render four anchors, and nobody would have blinked.
The theme works the same way. Every option in the editor — the background, the
corner radius, the shadow, the button fill and its transparency, the blur behind
it, what a hover does — comes out the other end as a CSS custom property in a
style attribute. Choosing a theme is choosing about a dozen numbers. Rendering
one is substituting them.
The pleasant side effect is that the dashboard’s live preview and the public page are two components reading the same properties, so what you see while editing is genuinely what ships. There is no second renderer to keep in step, only a stylesheet to agree on.
Why it is more interesting than it sounds
Here is the part that took actual thought: if there is no JavaScript on the page, nothing in the browser can report that the page was viewed.
Analytics, as normally practised, is a script that phones home. Take the script away and the obvious replacement is to count on the server — which we do. The renderer reports each view as it renders.
But that collides with the other thing you want, which is caching. The page used
to be cached at the edge with s-maxage=300, and a cached response never
reaches the worker. A visit that never reaches the worker cannot be counted. We
would have been counting cache misses and calling them people.
So the caching moved down a layer. The HTML is no longer cached; the upstream reads behind it are — the atproto lookups that fetch your identity, your links and your theme. A repeat visit still costs nothing upstream, and the worker still runs, which is what makes the number mean something. Rendering the page was never the expensive part.
The filter is the whole game
The last problem is the one nobody warns you about. A link-in-bio URL exists to be pasted into chat apps, and every one of them fetches the page to build a preview card. Left alone, your “visits” would be mostly Discord, Slack, Telegram and Twitterbot.
So each view goes through four checks. One is a maintained blocklist of
crawlers. The other three go the opposite way round: rather than naming what to
exclude, they ask for the marks a real navigation leaves — a user agent that at
least claims to be a browser, a Sec-Fetch-Dest: document header, and no
Sec-Purpose: prefetch.
The bias is deliberately towards under-counting. A number that is slightly low is still usable. A number inflated by preview bots is not, and from the outside you cannot tell which kind you have.
And because the count happens on our side, there is nothing in the page to block, nothing to consent to, and no address stored anywhere. A visitor is a hash of the day, the page, the IP and the user agent — with the day inside the message, so tomorrow they are somebody else entirely.