Skip to content

Cookie consent (GDPR) — design

How Raklet asks for, stores, and respects cookie consent for non-essential analytics/marketing trackers. Engineering reference (tracker map, code paths): GDPR cookie consent — implementation.

  • Ticket: ENG-276 (Security milestone), split from ENG-273
  • PR: #14330
  • Shipped: 2026-06 · own-build, no vendor

Why

A customer security review (Zachęta termination notice, 2026-06-25) flagged that Raklet loaded analytics/marketing trackers — Google Analytics, Mixpanel, Clarity, HubSpot, Intercom, org-injected scripts — with no consent mechanism at all (only an environment != "local" check). Under GDPR/ePrivacy, non-essential trackers need prior, opt-in consent, must be off by default, and consent must be withdrawable as easily as it was given. ENG-273 removed Mixpanel and its public-IP injection; ENG-276 adds the consent layer for everything else.

Decisions

Build vs buy → own-build. Third-party CMPs (Cookiebot, CookieYes, Osano) price per-domain or per-pageview, which fights Raklet's multi-tenant model (every org permalink + custom domain is a separate "site"); they also can't see behind our auth to gate manager-only trackers, and add yet another third-party script — the exact thing the complaint was about. A lightweight own-build banner slots into the existing server-rendered tracker partials, costs nothing recurring, and gives full control. ~3-4 days vs an enterprise CMP quote.

Two categories, default-deny. Non-essential trackers are split into Analytics (GA, RakletAnalytics, Clarity, Mixpanel-until-removed) and Marketing (HubSpot, Twitter, Facebook, Bing, Intercom). Strictly-necessary cookies are never gated. Nothing non-essential loads until the visitor opts in.

Per-org portals, shared Raklet properties. Each organisation's member portal is its own data controller, so portal consent is per-org (host-only cookie). Raklet's own login + admin are shared on raklet.com (like www), so one choice spans them. Strict per-org isolation that also ignores the Raklet-level cookie was considered and deliberately not taken (accepted nuance documented in the eng ref).

What shipped

Consent banner — on every user-facing surface (portal, admin SPA, login, legacy admin + Manager/Login areas). Accept all / Reject non-essential / Manage preferences.

Consent banner

Per-category preferences — expand to toggle Analytics / Marketing individually; Strictly-necessary is locked on.

Manage preferences

Withdraw anywhere — after a decision a persistent "Cookie preferences" entry point stays on every page, reopening the panel (withdraw as easily as granted).

Persistent withdrawal link

Privacy settings card — logged-in members manage cookies from Settings → Privacy, alongside the existing Visibility and Communication consent cards.

Privacy settings card

Deliberately cut / deferred

  • Org-injected CustomJs left ungated — it can carry operational code, so auto-gating it risks breaking tenant sites. Needs a product call (tenant responsibility vs gate vs per-org "is-tracker" flag).
  • Translations — English now; other locales fall back until translated.
  • DPA / §12.3 alignment — confirm the tracker classification matches our DPA.
  • Mixpanel removal owned by ENG-273 / #14325.