We run analytics on every site we ship without a single cookie banner. The stack is self-hosted Umami on our own Postgres, served from a first-party subdomain, storing zero cookies and no cross-site identifiers. Under both GDPR and the Texas Data Privacy and Security Act, analytics that set no cookies and collect no personal identifiers do not trigger a consent requirement — so the banner, the consent-mode plumbing, and the 30% of visitors who bounce off a modal all disappear. What we lose is per-person tracking. What we keep is enough aggregate signal to make product decisions, and a page that loads faster because it isn't dragging a third-party tag manager behind it.
This is a deliberate trade, not a compromise we backed into. Most teams reach for Google Analytics 4 by reflex, inherit the entire consent workstream that comes with it, and then never actually use the per-user data they took on all that liability to collect. We decided the aggregate is what matters and built the stack around that.
Why no banner is legally required
The banner exists because of tracking, not analytics. GDPR requires consent for storing or reading information on a user's device (the ePrivacy 'cookie' rule) and for processing personal data. TDPSA — which, unlike California's law, has no revenue threshold and applies to essentially any Texas business — gives consumers rights over personal data and requires opt-in for sensitive categories. Both of those hinge on the same thing: are you handling data that identifies a person?
- No cookies or localStorage identifiers — nothing is stored on the device, so the ePrivacy consent trigger never fires.
- No cross-site tracking — we don't sell or share data, so the TDPSA 'Do Not Sell/Share' obligation and its opt-out link don't apply.
- IP addresses are used transiently to derive coarse country/region, then discarded — never stored raw, never joined to a profile.
- We honor Global Privacy Control at the edge regardless, because it costs us nothing to respect a signal we're already not acting against.
The practical rule we follow: the moment a client wants to add Meta Pixel or GA4 for an ad campaign, the banner comes back and the entire consent-mode workstream comes with it. We tell them that up front so the decision is made with eyes open, not discovered during a compliance review.
Why self-hosted, first-party
Umami is open-source, runs in a single Docker container against Postgres, and fits our house stack exactly. We deploy it on the same Hetzner box as the app it measures and serve the script from analytics.<domain> — a first-party subdomain on the same registrable domain as the site. That first-party origin is the whole game:
- 01First-party requests aren't blocked by the tracker lists that kill third-party analytics domains, so the numbers are more complete than a hosted SaaS tag would report.
- 02The data lives in our Postgres, under our backup and retention policy, never on a vendor's servers — which makes the data-processing section of the privacy policy short and honest.
- 03One defer script tag, no tag manager, no dataLayer. The measured LCP cost is in the low tens of milliseconds, not the third-of-a-second a GTM container routinely adds.
The privacy policy has to describe what the site actually loads. A cookieless stack is the only version of that document we can write in one sitting and defend without an asterisk.
What we actually log
The point of dropping per-user tracking is to force discipline about what signal is real. We collect: page URL and referrer, a coarse country/region, device class (desktop/mobile/tablet), browser and OS family, and named events we fire deliberately — a contact-form submit, a pricing-page CTA click, a docs search. That's it. There's no user id, no session stitching across devices, no funnel that pretends to follow one human through a month.
For the questions a marketing site or e-commerce store actually asks — which pages pull traffic, where conversions happen, which referrers send people who convert — aggregate event counts answer all of them. When a product genuinely needs funnels, flags, and session replay, that's a different tool for a different job: we reach for PostHog on the product surface behind the login, where there's a real account relationship and a privacy policy scoped to it. The marketing front door stays cookieless.
The one failure mode to watch
The stack's weakness isn't privacy or performance — it's silent breakage on deploy. If a build knocks out the analytics subdomain, or a robots/CSP change blocks the first-party script, you lose data quietly and no APM will page you about it. So we treat the analytics endpoint as a monitored URL like any other, alert on a collection drop, and check it in the post-deploy pass. Cookieless is the easy part. Not letting it fail in the dark is the part that takes actual operational attention.