Install

Install Track

Track counts the visits on your server, with a middleware in Go. No script goes in the page and no cookie in the browser.

Your server sends the visits to Track in one go every ten seconds, and a page never waits for that.

In four steps

  1. Put the token in your server's environment, for example in the .env file or your container's configuration:

    TRACK_TOKEN=trk_…
  2. Get the library:

    go get github.com/savage-software-com/track-client
  3. Wrap your website's handler in the middleware:

    import track "github.com/savage-software-com/track-client"
    
    tracker, err := track.New(track.Config{
    	Token: os.Getenv("TRACK_TOKEN"),
    })
    if err != nil {
    	log.Fatal(err)
    }
    defer tracker.Close(context.Background())
    
    http.ListenAndServe(":8080", tracker.Middleware(handler))

    A site on go-webthings adds the module, next to or instead of the stats module (go get github.com/savage-software-com/track-client/trackwt):

    app.Use(trackwt.Module(track.Config{Token: os.Getenv("TRACK_TOKEN")}))
  4. Open a page of your website in your browser. Within ten seconds your server sends the visit; the dashboard shows it right away.

What the middleware counts

Pages a person opens: GET requests that answer with 200 and HTML, without a file extension in the path. Not counted are files, form posts, prefetches, htmx fragments (boosted links are), bots and monitors, and pages that ask not to be stored: X-Robots-Tag: noindex, Cache-Control: private or <meta name="robots" content="noindex">. Pages that answer with 404 go in the ‘Not found’ list, answers of 500 or higher under ‘Server errors’. Files such as .pdf, .zip and .docx count as a download; a PDF fetched in parts counts once. Bots, crawlers and scripts, including AI assistants such as ChatGPT-User, only count by name, never as a visitor.

What your server sends to Track

Per visit: the host, the path (without query), the page's title, how long your server took, the host of the referring website or, for a link within your site, the previous page, utm_source or ref, utm_medium and utm_campaign, the browser's first language, the user agent and the IP address without its last part. So the full address doesn't leave your server. With the shortened address Track looks up the country and city, and recognises the visitor for that day with a hash using a secret that changes daily; the address and user agent are then forgotten. See what Track measures.

Settings

Token
Your website's token. Without a token the tracker counts nothing, so your development environment runs without Track.
Hostname
Your website's host name, if a proxy changes the Host header. Track only counts visits to the registered domain and its subdomains.
TrustedProxies
The proxies (addresses or ranges like 10.0.0.0/8) whose X-Forwarded-For gives the visitor's address. Without proxies the visitor is r.RemoteAddr, which is right if middleware such as go-router's or chi's has already put the address there.
SiteName
The name your layout adds to every title, such as ‘About us · My site’; Track leaves it out, so the dashboard shows the pages' own titles.
Skip
A function that skips requests, such as those of your own editors.
Downloads
The extensions that count as a download; by default .pdf, .zip, .docx, .xlsx and other files to keep. An empty list counts no downloads.

Your own events

Count what happens on your website, such as a sign-up or a download. Track shows them under ‘Goals’:

tracker.Event(r, "newsletter sign-up")

On a go-webthings site: trackwt.Of(app).Event(r, "…"). Make an event, a page or a download a goal in your website's settings; Track then shows which part of the visitors gets there.

Campaigns

Links with ?utm_source=newsletter&utm_medium=email&utm_campaign=autumn or ?ref=newsletter appear under ‘Sources’. Other parts of the query are never sent, since those sometimes hold personal data.

Security

Under ‘Security’ you can have Track look at your website from outside every day: open files, the certificate, HTTPS, security headers and known vulnerabilities in what your server is built with. For this the middleware proves with your token that the site is yours, from client v0.2.5. This way Track finds known problems; finding none doesn't mean a site is safe.

Disguised bots

Some programs call themselves a browser. Over HTTPS modern browsers always send headers such as Sec-Fetch-Mode, and Chrome also Sec-Ch-Ua; when those are missing, the middleware puts suspect in the event, without sending the values themselves. Under ‘Bots’ Track shows how many views that were, along with views without a language, from very old browser versions and from the networks of large hosting companies. For now they still count as visitors: someone with a VPN comes from a data centre too.

Weekly overview

Every Monday at 08:00, on your website's clock, you get a mail per website about the week before: visitors, views, the most popular pages, the sources and the state of security. Track sends nothing extra to your website for this; it only uses the totals it already has. You turn it off in your website's settings.

Objecting

Visitors must be able to say easily that they don't want to be counted. For this the middleware answers /track-opt-out, a small page in the visitor's language, with one button. Link to it in the footer or in your privacy statement. The choice is kept in one cookie, set only on that request. A browser that sends Global Privacy Control or Do Not Track is left out by itself. Bots and scan attempts always count, since nothing about a person is in them.

The endpoint

The library posts batches to https://track.savage-software.com/api/v1/collect with the header Authorization: Bearer <token>. A batch is {"events": [...]} with at most 1000 events; see the type track.Event. Visits Track can't reach wait in your server's memory and are sent again later.