Installing the script

One line in the head of every page. The Install screen of each site gives these lines with its name filled in, and checks a page for you.

1 · The line

Put it in the head of every page you want counted, with the site's name as you added it to tidekeeper:

<script defer src="/t.js" data-site="your-site.example"></script>

The script is under 2 KB gzipped, sets no cookie, reads no storage and writes none. A build that grows it past its ceiling is not released.

2 · Serve it from your own domain

The line above asks your own site for /t.js. Your web server passes that, and the hits the script sends, on to tidekeeper. Your visitors' browsers then talk only to your site: no third party for a blocker or a content policy to stop. With nginx, in the site's server block:

location = /t.js  { proxy_pass https://tidekeeper.example/t.js?s=your-site.example; }location = /t/hit {  proxy_pass https://tidekeeper.example/api/v1/hit;  proxy_set_header X-Tidekeeper-Address $remote_addr;   # whose visit it is: tidekeeper sees only your server  proxy_set_header Cookie "";   # your site's cookies are not ours to see  access_log off;                # so the address is not written to your log either}

With Caddy:

handle /t.js {  rewrite * /t.js?s=your-site.example  reverse_proxy https://tidekeeper.example}handle /t/hit {  rewrite * /api/v1/hit  reverse_proxy https://tidekeeper.example {    header_up X-Tidekeeper-Address {remote_host}    header_up -Cookie  }  log_skip}

Your Install screen has these with this tidekeeper's own address in place of tidekeeper.example. Without a proxy, the script can be loaded from tidekeeper directly; the Install screen gives that line too.

3 · If your pages set a content policy

Served from your own domain, the script needs nothing beyond what most policies already allow:

script-src 'self'connect-src 'self'

The Install screen also gives the script's integrity hash, for a site that pins its scripts.

4 · Check it

The Install screen has a box that fetches a page of your site and says whether the line is on it and the script answers. A dry run then shows the first view arriving, and what tidekeeper would keep of it, without writing it.

Events, goals, and a backend