Guide · server-side
Server-side analytics: measure from your backend, not the browser.
Almost every analytics tool loads a script in each visitor’s browser. Server-side analytics does the opposite: your application already receives every request, so it counts the visit itself.
This guide covers what changes, what you gain, what you miss, and how runomine does it.
Reviewed on October 14, 2026
What server-side analytics is
“Server-side” is used for two different things:
- Server-side tagging: the browser still loads a script, but sends its events to an intermediate server that forwards them to Google Analytics, Meta and others. The path changes, not the origin.
- Server-side collection: your backend records the visit as it answers, with nothing in the browser. Business events (a signup, a confirmed payment) are sent from where they happen: your code, a job, a webhook.
runomine is the second, with an optional beacon for what your backend never sees.
Backend vs browser: what each one sees
| Library in your backend | Script in the browser | |
|---|---|---|
| What’s in the browser | Nothing | A script and, often, cookies |
| Ad blockers | Can’t see what your server does | Can block the script or its requests |
| Pages served from the CDN cache | Never reach your backend: you need the beacon | Counted |
| Navigation inside an SPA | Only the first load; the rest, with the beacon | Counted if the script follows pushState |
| Business events | Where they happen: in your code, a job or a webhook | Only if the browser is still on the page |
| Bots | All of them arrive: they must be filtered (runomine does it centrally) | Many don’t run JavaScript |
| Page weight | Zero bytes; sending happens after the response | One more script to download and run |
| The visitor’s IP | Can stay on your server | Reaches the vendor with every request |
Counting unique visitors without cookies
Without a cookie there’s no identifier stored in the browser. runomine uses a daily hash: IP, user agent and host, with a salt derived from your token and the UTC date.
The same person on the same day gives the same hash; the next day, a different one. So you get unique visitors per day, and nobody can be followed across days or sites.
The PHP, Node, Python and Rust libraries compute it on your server and are tested against the same vector. With the beacon, runomine computes it with the same formula and discards the IP, so a person seen by both counts once.
# Computed on your server, by the library
day = "2026-10-13" # today, UTC
salt = hex(HMAC-SHA256(key = token, "runomine:" + day))
visitor = hex(SHA256(salt + "|" + ip + "|" + user_agent + "|" + host))[0:16]
# Test vector every implementation reproduces
token = "rm_live_test_0123456789abcdef"
ip = "203.0.113.9" host = "example.com"
visitor = 5f9e1bebe31e8bf5
# What travels to runomine: the hash, never the IP
{ "type": "pageview", "url": "https://example.com/pricing",
"visitor": "5f9e1bebe31e8bf5", "user_agent": "Mozilla/5.0 …" }
Library, beacon, or both
-
Library
For apps with a backend. Pageviews from a middleware and events with
track(). The IP never leaves your server. -
Beacon
For static sites, CDN-cached pages and SPAs. Under 1.5 KB, no cookies or localStorage, and it drops visits with Do Not Track or GPC.
-
Both
They give the same visitor hash, so nobody counts twice. The library for what goes through your backend; the beacon for the rest.
How to start on your stack
-
Laravel
An auto-discovered middleware and
Rom::track(). Laravel guide. -
Express and Next.js
@runomine/node: Express middleware and a helper for the Next.jsmiddleware(App Router). Node 18+, no dependencies. -
Django and FastAPI
runominefor Python 3.10+: Django middleware and ASGI middleware for FastAPI or Starlette. Standard library only. -
Rust
A layer for axum, actix-web or any tower stack, also in blocking mode.
-
Any other backend
POST /api/v1/eventswith your token: up to 500 events per call, idempotent by id. -
Static sites
One
<script>tag with the beacon. No cookies.
FAQ
Frequently asked questions
Does server-side analytics get past ad blockers?
Doesn’t it count bots too?
What about pages my CDN caches?
Is this the same as server-side Google Tag Manager?
Does it slow my application down?
Sources
Public pages and documentation, checked on October 14, 2026. If something has changed, we will fix it.
Keep reading
- runomine vs Google Analytics What you gain and lose by leaving GA4, and how to switch without flying blind.
- runomine vs Plausible Two cookieless tools. The difference: where it’s measured and how the money arrives.
- Laravel analytics Pageviews from a middleware, events with Rom::track, and Stripe sales by source.
Count what matters.
Visits, sales and servers in one place. Installed in less time than it took to read this page.