Documentation
¶
Overview ¶
Package stats counts the public site's page views without cookies and without storing anything about visitors. Add an instance with:
app.Use(stats.Module())
The instance has the key "stats", used in the template functions below; stats.Module(stats.Named("visits", "Visits")) chooses another key and title.
Every public HTML page that answers 200 to a GET is counted: views and visitors per day and per page, referrer hosts, device classes (desktop, mobile, tablet) and languages (the first path segment). Not counted are the paths WebThings serves itself (webthings.App.CorePaths: the admin, visitor actions (/_/), media, assets, theme files, sitemap.xml, robots.txt, /healthz, /readyz and /metrics), files with an extension, HEAD requests, prefetches, htmx fragments, bots and editors who are signed in to the admin (frontend.Editor). Nor are pages that ask not to be kept, so their addresses never show up in the admin or in "most read" lists: answers with "X-Robots-Tag: noindex" (or none), "Cache-Control: private" or <meta name="robots" content="noindex">, such as search results and registrations looked up by their code. A bare "Cache-Control: no-store" still counts, since forms, polls and comments send it to stay fresh.
A visitor is recognised by a hash of a random salt, the IP address (frontend.ClientIP, so list a reverse proxy in Config.TrustedProxies) and the user agent. The salt lives in memory only and changes every day, so visitors cannot be followed from day to day and nothing in the database leads back to a person. After a restart the same day's visitors count once more.
Views are counted in memory and written at most 30 seconds later, so a page never waits for the database. Closing the app writes what is left.
The admin shows the last 7, 30 or 90 days with a chart per day, the top pages, referrers, devices and languages, and a retention setting that deletes older days. The module has no page of its own.
Template functions:
{{pageViews "stats" .URL}} views of a path, e.g. "read {{pageViews "stats" .URL}} times";
an empty path is the current page
{{range popular "stats" 5 30}} the 5 most viewed pages in the current language
<a href="{{.Path}}">{{.Title}}</a> of the last 30 days, without the home page;
{{end}} each has Path, Title, Views and Visitors;
a limit of 0 lists all pages
{{range popular "stats" 5 30 "news"}} the same below the page of a module instance,
{{range popular "stats" 5 30 "/blog"}} or below a path (without the language prefix),
without that page itself: "most read" posts
Title is the page's HTML <title> when it was last viewed, without the site name the layout adds before or after it ("Hello · My site" is stored as "Hello"; the separators ·, |, -, –, —, :: and / are recognised).
Index ¶
- func Module(opts ...Option) webthings.Module
- type Bar
- type Count
- type DashboardView
- type Day
- type Option
- type Page
- type RangeLink
- type Report
- type Row
- type Service
- func (s *Service) Flush(ctx context.Context) error
- func (s *Service) Popular(ctx context.Context, locale string, limit, days int) ([]Page, error)
- func (s *Service) PopularIn(ctx context.Context, locale, within string, limit, days int) ([]Page, error)
- func (s *Service) Prune(ctx context.Context) error
- func (s *Service) Report(ctx context.Context, days int) (Report, error)
- func (s *Service) Retention(ctx context.Context) (int, error)
- func (s *Service) SetRetention(ctx context.Context, days int) error
- func (s *Service) Views(ctx context.Context, path string) (int, error)
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Bar ¶
type Bar struct {
// Date is the day in the admin language, such as "5 okt 2026".
Date string
Views int
Visitors int
Height int
}
Bar is one day of the chart. Height is a percentage of the busiest day.
type Count ¶
Count is the number of views by one referrer host, device class (desktop, mobile or tablet) or language.
type DashboardView ¶
type DashboardView struct {
Title string
Days int
Ranges []RangeLink
Views int
Visitors int
// From and To are the first and last day of the chart, in the admin
// language.
From string
To string
Bars []Bar
Pages []Row
Referrers []Row
Devices []Row
Locales []Row
// Settings is the retention form, for users who may edit.
Settings *form.RenderModel
SettingsErrors form.FieldErrors
}
DashboardView is the data of the admin dashboard.
type Day ¶
type Day struct {
// Date is YYYY-MM-DD.
Date string `db:"day"`
Views int `db:"views"`
Visitors int `db:"visitors"`
}
Day is one day of a report.
type Page ¶
type Page struct {
// Path is the page's address, for example /en/news/hello.
Path string `db:"path"`
// Title is the page's HTML title when it was last viewed, without the
// site name.
Title string `db:"title"`
Views int `db:"views"`
Visitors int `db:"visitors"`
}
Page is a path with its number of views.
type Report ¶
type Report struct {
Days int
// Views and Visitors are the totals. A visitor is recognised for one day
// only, so Visitors adds up the visitors of each day.
Views int
Visitors int
Daily []Day
Pages []Page
Referrers []Count
Devices []Count
Locales []Count
}
Report is the statistics of the last Days days, including today.
type Service ¶
type Service struct {
// contains filtered or unexported fields
}
Service is one Stats instance, for the website's own code.
func (*Service) Flush ¶
Flush writes the page views counted in memory. It runs by itself every 30 seconds after a page view and when the app closes; call it to read up-to-date numbers, for example in tests.
func (*Service) Popular ¶
Popular returns the limit most viewed pages in locale of the last days days, without the home page, for "most read" lists. A limit of 0 or less returns all of them.
func (*Service) PopularIn ¶
func (s *Service) PopularIn(ctx context.Context, locale, within string, limit, days int) ([]Page, error)
PopularIn is Popular for the pages below within, without that page itself, for example the most read posts of a blog. within is a path without the language prefix, such as "/blog", or the key of a module instance, whose page in locale is used; an instance that is not on a page has no popular pages. A limit of 0 or less returns all of them.
func (*Service) Prune ¶
Prune deletes the days that are older than the retention. Flush calls it once a day.
func (*Service) Report ¶
Report sums up the last days days (1 to 366), today included. It reads what was flushed; call Flush first for up-to-the-second numbers.
func (*Service) SetRetention ¶
SetRetention keeps statistics for days days (0 keeps them all) and deletes older ones right away.