GDPR Art. 25 (data protection by design) requires that analytics configurations minimize data collection by default — and the default GA4 configuration does not do this. Without Consent Mode v2 and analytics_storage: 'denied' as the default state, GA4 collects full IP addresses and sets cookies before any user consent is obtained. ePrivacy Art. 5(3) makes this unlawful for EU users without prior consent. ISO-27001:2022 A.5.34 requires that privacy controls be applied at the point of processing, not as an afterthought. Passing raw user email to analytics.identify() also creates a direct PII leak to a third-party processor — this is an Art. 28 issue on top of the consent failure.
Info because misconfigured analytics is a procedural privacy failure rather than a direct security vulnerability, but regulators treat it as a consent mechanism failure and issue fines accordingly.
Initialize GA4 with Consent Mode v2 so analytics is denied by default and only activates after the user accepts in the consent banner.
// In your <head>, before the GA4 script tag loads:
window.dataLayer = window.dataLayer || []
function gtag(...args: unknown[]) { window.dataLayer.push(args) }
// Deny all by default
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
})
// Call after user accepts analytics in the consent banner:
gtag('consent', 'update', { analytics_storage: 'granted' })
For identity calls, pass a pseudonymous ID (see pii-separation pattern) never the raw email. If migrating is complex, consider switching to Plausible or Fathom — both are GDPR-compliant by design with no cookies, no IP storage, and no consent banner requirement for basic analytics.
ID: data-protection.compliance-documentation.analytics-privacy-configured
Severity: info
What to look for: Enumerate every relevant item. Check the analytics service configuration in the codebase. For Google Analytics 4 (GA4): look for the gtag initialization in the HTML layout — verify that Consent Mode v2 is configured (gtag('consent', 'default', ...)) and that analytics_storage: 'denied' is the default until consent is granted. For GA Universal/GA3: check for anonymize_ip: true in the config. For Segment: verify that PII fields (email, name, phone) are not passed to analytics.identify(). For Mixpanel or Amplitude: check identify() calls. For Plausible or Fathom: these are privacy-friendly by design (no IP storage, no cookies) — confirm the correct tracking script is in use and check their configuration for custom domains.
Pass criteria: At least 1 of the following conditions is met. Analytics service has IP masking or anonymization enabled (or uses a privacy-first tool like Plausible/Fathom that doesn't store IPs). User IDs sent to analytics are pseudonymous (UUID or hash), not email or name. Analytics scripts are only loaded/activated after the user grants analytics consent.
Fail criteria: IP masking disabled in GA configuration. User email or name passed directly to analytics identify calls. Analytics loads before or without consent.
Skip (N/A) when: Application does not use analytics.
Detail on fail: Example: "GA4 configured without Consent Mode v2. analytics_storage not set to 'denied' by default. Full IP addresses logged." or "Segment identify() called with user.email as the userId without consent check.".
Remediation: Configure analytics for privacy compliance:
// GA4 Consent Mode v2 — initialize before gtag loads
// In your <head>, before the GA4 script tag:
window.dataLayer = window.dataLayer || []
function gtag(...args: unknown[]) { window.dataLayer.push(args) }
// Default: deny all until user consents
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied',
})
// After user accepts analytics in consent banner:
gtag('consent', 'update', { analytics_storage: 'granted' })
For pseudonymous user IDs in all analytics tools, see the remediation for pii-separation check above. If budget allows, migrate to Plausible or Fathom — both are GDPR-compliant by design, require no consent banner for analytics, and provide simpler compliance posture.