Asking before analytics
Analytics that only start after a yes, asked in a small terminal prompt instead of a cookie banner.
This site uses Vercel Web Analytics, so I can see which pages are read. It sets no cookies, and it doesn't measure anything until you say yes. And the question doesn't come as a cookie banner. It is a small terminal prompt in the bottom corner of the page.
Why ask without cookies
No cookies doesn't mean nothing is sent. For each page view, the analytics script sends Vercel the page address, the referring page, your browser, the device type and a rough location that comes from your IP address. That's why the privacy policy names your consent as the legal basis, and nothing is measured before a yes.
The prompt itself needs JavaScript, because a script decides whether it shows and handles the answer. Without JavaScript the prompt stays hidden, but then the analytics script can't load either, so there is nothing to ask about.
A small script in the head
The consent logic is a small inline script in the head of each page, like the one for the theme, so it runs before the rest of the page. The script reads your earlier answer and turns it into one of three states. Here stored is the value from localStorage and gpc says whether your browser sends Global Privacy Control.
const state = stored === "on" || stored === "off" ? stored : gpc ? "off" : "ask";
So a saved on or off wins, Global Privacy Control counts as no, and only without either do you see the question. Your answer stays on your device, so you are asked once.
With the state known, the script adds the class consent-ask to the html element when it has to ask, and the CSS shows the prompt only under that class. After a yes, it adds the analytics script to the page. In this snippet d is the document, src is the address of Vercel's script, and loaded remembers that it was already added.
if (state === "on" && !loaded) {
loaded = true;
const s = d.createElement("script");
s.src = src;
s.defer = true;
d.head.appendChild(s);
}
The script is part of every page, so a test keeps it under 2.5 KB. It runs the exact string that ships, and right now that string is about 2.2 KB.
Saying no later
A no has to work after a yes too, but by then Vercel's script is already running in the page. Vercel's script accepts a beforeSend function, which it calls with each event before it sends it. The consent script passes one through a small helper va. It calls window.va, and if Vercel's script hasn't set that up yet, it first puts in a stand-in that collects the calls in window.vaq.
const va = (...args: unknown[]) => {
w.va = w.va || function () {
(w.vaq = w.vaq || []).push(arguments);
};
w.va(...args);
};
With that helper, a no after a yes registers a beforeSend that returns null, so every further event in this page view is dropped.
} else if (state !== "on" && loaded) {
// The script is already running in this page view: drop every further event.
va("beforeSend", () => null);
}
On the next page view the state is off, so Vercel's script isn't loaded at all. You can change your answer any time. The footer of every page has a Privacy settings button that opens the prompt again. The terminal on the home page has the command analytics for it too, which shows the current state, while analytics off stops the measuring and analytics on allows it. The consent script puts its functions on window.losoftConsent, and the terminal calls set("on") or set("off") there, the same function behind the prompt's buttons.
A prompt, not an overlay
There is no overlay, so the page stays usable while the prompt shows. It asks analytics --enable? in the colours of the terminal, with two buttons, [y] allow and [n] decline. The keys y and n work too, but only while focus is inside the prompt, never across the whole page. After you answer, focus moves to the main content, so it isn't lost with the prompt.
Because the prompt is fixed to the bottom of the screen, it could cover the link you just tabbed to. WCAG 2.2 says focus must not be hidden like that, and the checks from the note “Testing WCAG 2.2” look for it at every Tab stop. So the same consent-ask class that shows the prompt also gives the page extra space at the bottom, and focused elements scroll clear of it.
html.consent-ask {
scroll-padding-bottom: 264px;
}
.consent-ask body {
padding-bottom: 264px;
}
When you answer, the script removes the class, so the prompt and the extra space go away together. The one state that the script in the head works out decides both what you see and what is measured.