Back to Ideas 7 min read

We Promised Not to Watch. Then We Needed to See.

E
EkoHacks Team
·

The first post of this series ended with a promise about the second half. We had written in our privacy policy that we used no cookies, no analytics, no tracking pixels, and it was true. It was also why we had no idea whether anyone read the fifty posts in the repository. This post is where that changes, and the change is made in the open, in one commit, so that the code and the promise cannot drift apart.

The reframe

Measuring is not surveillance. The line between them is not whether you count, it is what you refuse to know. A counter that records that a page was read, from which country, on what kind of device, and knows nothing else, tells a writer what a writer needs and a stranger nothing. A tracker that assigns you an identity, follows you across sites and days, and sells the trail is a different thing that happens to use the same word. We wanted the first and we wrote down why the second is out.

So before choosing a tool we wrote the refusals. No cookies, because a cookie is an identifier and we do not want one. No fingerprinting, for the same reason by another route. No personal data: no IP address kept, no user identity, no cross site anything. Hosted in the European Union, by a company subject to the same law as us. Aggregated figures only. And no consent banner, not as a convenience but as a consequence: if nothing identifies you, there is nothing to consent to, and a banner would be theatre.

What we chose

Plausible, a small Estonian company's service, met every refusal as written. Its script is under a kilobyte, sets no cookies, stores nothing on the device, and derives a country from the IP address and then drops the address. Within one day it counts visits using a hash of a daily salt, the site, the address and the browser; the salt changes every twenty four hours and the old one is destroyed, so yesterday's hash cannot be recomputed and we cannot recognise a reader from one day to the next. The figures it keeps are totals.

We are naming the tool because we name the tools we use. We are not comparing it with anything, because we did not evaluate anything else against the refusals; it met them, and meeting them was the whole requirement.

One commit

The policy said we did not do this. Adding the script and then, at some later point, remembering to update the policy would have left a window in which the site did one thing and the document said another. The series rule for this post was that the two land together, and they did:

4c248b1 We promised not to watch, then we needed to see
  web/app/plugins/plausible.client.ts | 14 ++++++++++++++
  web/content/legal/privacy-policy.md | 14 ++++++++++++--

Fourteen lines each. The script is a plugin that attaches the counter only when the page is served from ekohacks.com, so the preview deploys we use to test changes, the development server, and any copy of the site somewhere else are not readers:

export default defineNuxtPlugin(() => {
  if (typeof window === "undefined") return;
  if (window.location.hostname !== "ekohacks.com") return;
  const script = document.createElement("script");
  script.defer = true;
  script.dataset.domain = "ekohacks.com";
  script.src = "https://plausible.io/js/script.js";
  document.head.appendChild(script);
});

The policy change is four edits. The sentence in section 2 that said we used no analytics now says we count page views with one service that sets no cookies and cannot identify you, and points at section 3. Section 3 gained a part that says what is recorded, in plain words: the page address, the referring site, the browser and operating system family, the device type, the country, and that the IP address is discarded. It names the legal basis, legitimate interest, and says what that interest is. Section 6 lists the company as a processor, and section 8 says what is kept and for how long: the daily hash for a day, the totals indefinitely, because totals are not about anyone.

The date at the top of the policy moved from June to August. Because our legal pages are files in the same repository as the site, the sitemap picked the new date up on its own, and the full history of the change, every word that moved, is in the commit. A later post makes that history visible on the page itself.

What we will see, and what we will not

From the dashboard we will be able to say how many people read a post, which country they were in, whether they came from a search engine or a link, and which pages they arrived on and left from. We will not be able to say who any of them were, whether a reader today is the one from yesterday, or anything about what they do anywhere else. When the measurement post at the end of the series reports numbers, those are the numbers it will have.

The script went live on the evening of the twenty second of August. Within the hour the dashboard showed its first reader: one visitor, the home page, from Greece, direct. The next day, the counter's first full day, a Sunday, it showed nobody at all. Zero visitors, zero page views. We pulled that zero through the API with the same script that will pull the ninety day numbers, and committed it to the evidence folder like any other measurement, because a counter that shows zero and a counter that is broken look identical unless you write the zero down.

That is the truthful starting line for the second half of this series. A site that search showed 174 times last month, with six clicks, does not have readers to count yet. The counter is not here to flatter us; it is here so that when the findability work of the first seven posts reaches the index, the change is measured against an honest floor, and the floor is zero.

The number for today: one reader on the first evening, zero on the first full day, and a privacy policy that says exactly how we know.

E

Written by

EkoHacks Team

More from Ideas

·6 min read

What the Nullable Gave Back

One file, seven behaviours held fixed, the database swapped for a Nullable: about 180 times less time inside the tests, and coverage flat to two decimals.

E
EkoHacks Team
·6 min read

Twenty Six More Tests, Four Fewer Behaviours

Removing the mocks grew the suite from 44 tests to 70 and quietly deleted four behaviours, every one of them a failure path. Test count is not coverage.

E
EkoHacks Team
·6 min read

The Best Coverage Number in the Room

Same commit, same spec, same test count. The mocked suite ran 5.6 times faster, covered 3.5 fewer points of real code, and posted the best branch coverage.

E
EkoHacks Team