Cookieless analytics in the EU: Umami, GDPR and Poland's art. 399
Cookieless is not automatically consent-free. What GDPR and art. 399 of Poland's electronic communications law say, and three positions you can defend.
Cookieless analytics such as Umami avoid cookies, but not the EU rule on reading information from a visitor's device. In Poland that rule is art. 399 of the Prawo komunikacji elektronicznej (the electronic communications law), and it has no exemption for analytics. Three positions are defensible: ask for consent, skip the banner but disclose and honour opt-outs, or run no analytics in the browser. This site takes the second.
TL;DR
- Two rules: GDPR covers personal data; art. 399, Poland's version of the ePrivacy device rule, covers storing or reading anything on the device, cookie or not.
- Still access: the EDPB treats a script that makes the browser send data as access, and art. 399 has no exemption for audience measurement.
- This site: no banner, Umami without cookies, a privacy policy that says what the script reads, an opt-out, and no script at all under Do Not Track or Global Privacy Control.
Not legal advice: I'm a developer who read the primary sources for my own site. If the decision matters to your business, ask a lawyer.
Which two rules apply?
GDPR covers personal data. Analytics needs a legal basis. For a small site that is usually art. 6(1)(f), legitimate interests: processing "necessary for the purposes of the legitimate interests pursued by the controller", unless the visitor's rights override them. Art. 21 lets people object to that processing at any time, on grounds relating to their particular situation.
The ePrivacy Directive (2002/58/EC), art. 5(3), covers storing information on the user's device or reading it from there, personal data or not. Poland implements it in the Prawo komunikacji elektronicznej (Dz.U. 2024 poz. 1221), in force since 10 November 2024. The device rule is its art. 399.
"Cookieless" answers a question about cookies. The device rule asks a broader one.
What does art. 399 actually say?
In my own abridged translation of ust. 1, storing information in a user's terminal equipment, or reading what is already stored there, is allowed only if:
- the user is first told, clearly and simply, the purpose and how to set conditions in their software or service settings;
- the user then consents;
- the storage or access doesn't change the configuration of the device or its software.
Ust. 3 lifts these conditions when the storage or access is necessary to transmit a message over a public network. It also lifts them for a service "żądanej przez abonenta lub użytkownika końcowego", one the user asked for. Art. 400 adds that consent follows the data protection rules.
Three things follow from the text:
- It binds whoever stores or reads. There is no "business" condition.
- It covers access, not only storage.
- The exemptions are transmission and a service the user asked for. Audience measurement isn't one.
Does a cookieless script "access" the device?
The European Data Protection Board says yes, in the common case. In its Guidelines 2/2023 (§ 33), JavaScript code "where the accessing entity instructs the browser of the user to send asynchronous requests with the targeted information" clearly falls within art. 5(3).
Umami's tracker is open source, so you can check what it does. In the current code it:
- reads the screen's width and height and the browser language, and sends them with each event;
- reads one
localStoragekey,umami.disabled, to know if you opted out; - checks the browser's Do Not Track setting when you turn that option on;
- sends requests without credentials by default and sets no cookie.
The Umami FAQ agrees: "Umami does not use any cookies in the tracking code". No cookies, then, but on the EDPB reading, still access. That is why the tracker's code matters more than its landing page: a vendor's promise is not a legal source.
The same guidelines (§ 56) add that being in scope "does not systematically mean that consent needs to be collected". Whether an exemption applies is judged case by case, and in Poland the exemptions are art. 399 ust. 3. Analytics fits them badly.
The Article 29 Working Party said so in 2012 (WP194): first-party analytics "are not strictly necessary to provide a functionality explicitly requested by the user". It also found them "not likely to create a privacy risk" when limited to first-party aggregate statistics, with clear information, "a user friendly mechanism to opt-out" and anonymisation. It even suggested lawmakers "might appropriately add a third exemption criterion".
The Polish act has no such criterion. WP194 predates both GDPR and the act: useful as a risk profile, not binding.
What do Polish practice and the fines look like?
UODO, Poland's data protection authority, uses Plausible Analytics on its own site. Its privacy policy says Plausible "nie wykorzystuje plików cookie i nie zbiera danych osobowych" (uses no cookies and collects no personal data) and describes no consent step. UODO doesn't enforce art. 399, though: fines for breaking it come from the President of UKE, the electronic communications regulator (art. 444 ust. 1 pkt 82 with art. 446).
The ceilings in the statute: up to 3% of the previous year's revenue (art. 446 ust. 1). With no revenue in the three preceding calendar years, or no more than 500 000 zł in that period, the cap is 15 000 zł (art. 446 ust. 3). These are maximums, not a price list.
Which positions can you defend?
| Position | What you do | What it costs |
|---|---|---|
| (a) Consent prompt | Ask before loading analytics; load only after a yes | A prompt on the first visit; statistics only from people who agree |
| (b) No banner, full disclosure | Explain it in the privacy policy, offer an opt-out, and don't track when the browser sends Do Not Track or Global Privacy Control | A residual risk under a literal reading of art. 399 |
| (c) No client-side analytics | No tracker script; at most aggregate counts from the server | You lose screen sizes, languages and click events |
(a) is the safest on the letter of art. 399, and (b) matches the WP194 risk profile and the practice above. (c) narrows the question without removing it. Your server still receives IP addresses, and the EDPB guidelines (§ 55) treat an IP address sent from the user's device as in scope too.
What does this site do?
Position (b), decided on every visit:
- 01 Page loads Only a small inline loader runs; the Umami script isn't requested yet.
- 02 Signals Do Not Track or Global Privacy Control on? Stop: no script.
- 03 Opt-out umami.disabled stored in this browser? Stop.
- 04 Umami Added after the load event, counting this site's own domain only. No cookies.
- 05 Events Values from fixed lists, such as which button or which language. Nothing typed.
Section 7 of the privacy policy, in all three of the site's languages, says what the script reads and how to switch it off. It names itself as the information art. 399 ust. 1 asks for. The switch sits on the privacy page. Storing its flag is something the visitor asked for, which is what ust. 3 pkt 2 describes. The pause button follows the same rule: it remembers your choice only after you press it (motion that respects people).
How do you wire it with Umami?
Do Not Track is one attribute: Umami's data-do-not-track will "Respect user's Do Not Track browser setting". Global Privacy Control has no Umami setting; neither the docs nor the tracker code mention it. You could cancel each send in Umami's data-before-send hook (return a falsy value), but it's cleaner not to load the script at all. A simplified version of this site's loader:
const optedOut = () => {
try {
return !!localStorage.getItem("umami.disabled");
} catch {
return false; // storage blocked
}
};
if (!navigator.globalPrivacyControl && navigator.doNotTrack !== "1" && !optedOut()) {
addEventListener("load", () => {
const script = document.createElement("script");
script.src = "https://cloud.umami.is/script.js";
script.dataset.websiteId = "YOUR-WEBSITE-ID";
script.dataset.domains = "your-site.com";
script.dataset.doNotTrack = "true";
document.head.append(script);
});
}
The opt-out is the key from Umami's "Exclude my own visits" page, behind a switch that sets or clears it:
optOutButton.addEventListener("click", () => {
try {
if (localStorage.getItem("umami.disabled")) localStorage.removeItem("umami.disabled");
else localStorage.setItem("umami.disabled", "1");
} catch {
// storage blocked: nothing is saved, and the loader can't read it either
}
});
Default
With GPC Umami's server matters too. In its open-source code, a session ID is a hash of the website ID, the IP address, the user agent and a salt that rotates monthly by default. No cookie is involved, but IP addresses are, so treat it as personal data under GDPR: name the basis, explain it in the policy and honour objections.
Limits
- This is a developer's reading of primary sources, not a lawyer's opinion. Position (b) keeps a residual risk under a literal reading of art. 399; if that isn't acceptable to you, (a) is a legitimate answer.
- Do Not Track and Global Privacy Control reach only some visitors. MDN marks
navigator.doNotTrackas deprecated, with a discontinued specification, andnavigator.globalPrivacyControlas experimental and missing from some widely used browsers. - The opt-out lives in one browser. Clearing site data or switching devices forgets it.
- Your context changes the answer: a shop, an app with accounts or a company site is not a personal portfolio.
The other place where visitor data meets this site is the contact form, which sends mail without a key in the browser. The whole build is in the case study, and if you want to talk about any of this, here's how to reach me.
Sources
- Ustawa z dnia 12 lipca 2024 r. Prawo komunikacji elektronicznej, Dz.U. 2024 poz. 1221 (Sejm ELI API) (opens in a new tab) (accessed )
- EDPB Guidelines 2/2023 on Technical Scope of Art. 5(3) of ePrivacy Directive, version 2.0 (opens in a new tab) (accessed )
- Regulation (EU) 2016/679 (GDPR), EUR-Lex (opens in a new tab) (accessed )
- Article 29 Working Party, Opinion 04/2012 on Cookie Consent Exemption (WP194) (opens in a new tab) (accessed )
- Umami docs: Tracker configuration (opens in a new tab) (accessed )
- Umami docs: Exclude my own visits (opens in a new tab) (accessed )
- Umami docs: FAQ (opens in a new tab) (accessed )
- Umami tracker source (src/tracker/index.ts) (opens in a new tab) (accessed )
- Umami collect endpoint source (src/app/api/send/route.ts) (opens in a new tab) (accessed )
- Navigator: globalPrivacyControl property (MDN) (opens in a new tab) (accessed )
- Navigator: doNotTrack property (MDN) (opens in a new tab) (accessed )
- UODO, Polityka prywatności (opens in a new tab) (accessed )