The four big numbers at the top of the analytics dashboard look simple, but they're each computed differently. Here's exactly what they mean.
Visits
Every line in your Nginx access log counts as one visit. That includes:
- Page loads (HTML pages)
- Static asset requests (images, CSS, JS, fonts)
- API calls
- Failed requests (4xx and 5xx)
- Bot requests
So "visits" is really "HTTP requests" — the same definition AWStats uses. A visitor loading a page that contains 30 images counts as 31 visits in this metric, not 1.
If you want a "page views" number that excludes assets, the Top Pages table is closer to what you want — it only counts pages that match URL patterns visitors actually browse to.
Unique Visitors
This is an estimated count of distinct visitors over the selected range. The exact union of unique IPs across hours is not stored on disk (it would defeat the bucket aggregation that makes the system fast and cheap), so the dashboard uses a heuristic:
estimated_unique = max(unique_in_any_hour) + (sum_of_hourly_uniques - max) / 3
The intuition: the busiest single hour gives a lower bound. The remaining hourly counts have heavy overlap (same visitors returning later), so we discount them by 2/3.
This is accurate to within ±10% for typical traffic patterns. For exact unique counts you'd need a full-fidelity tracker like Plausible — but for "are my visitors growing?" this is enough.
Bandwidth
Total bytes sent in HTTP response bodies. This is the $body_bytes_sent field that Nginx logs for each request. It does NOT include:
- Response headers (negligible — a few hundred bytes per request)
- Bytes consumed by the TLS handshake on HTTPS connections
- Bytes that never made it to the visitor (failed connections, aborted downloads)
So the dashboard's bandwidth number is slightly lower than what your hosting provider's billing meter would show, but it's the most useful number for sizing assets — it's the bytes of actual content you served.
For "real" billing-grade bandwidth, check your hosting provider's dashboard. They count network-layer bytes including overhead.
Bot Traffic
The percentage of visits that came from bots, calculated as bot_visits / total_visits × 100.
A bot visit is any request whose User-Agent matches a known bot signature:
- Search engine crawlers (Googlebot, Bingbot, YandexBot, ...)
- SEO tools (AhrefsBot, SemrushBot, MJ12bot, DotBot)
- Social media link previewers (facebookexternalhit, Twitterbot, LinkedInBot)
- Programmatic clients (curl, wget, Python requests, Go HTTP client)
- Anything containing the words
bot,crawler,spider,scraper
Bot traffic is normal — every public site gets some. Healthy ranges:
| Bot % | Health |
|---|---|
| 5-20% | Normal — mostly Google + Bing + a few SEO tools |
| 20-40% | High but typical for new sites being heavily crawled |
| 40-70% | Investigate — you might have an aggressive scraper |
| > 70% | Something's wrong — block the offender or rate-limit it |
Why bot visits aren't included in Top Pages / Countries / Browsers
When a request is identified as a bot, the agent counts it in bot_visits and the status code histogram, but not in the Top Pages, Top Referrers, Top Countries, Top Browsers, or Top OS tables.
This keeps the human-traffic stats clean. Otherwise Googlebot would dominate the Top Pages list and the United States would always be the top country (because most search engine crawlers run from US data centers).
The downside is that the total visits in the stat card won't equal the sum of per-page or per-country counts — that's intentional. The stat card includes bots, the breakdown tables don't.