Skip to content

feat(docs): GDPR cookie consent banner with Google Consent Mode v2 #219

@polaz

Description

@polaz

Summary

GDPR-compliant cookie consent for VitePress docs site using @structured-world/vue-privacy:

  • EU-only consent banner with geo-detection (Cloudflare → IP API → timezone fallback)
  • Google Consent Mode v2 — all 4 signals (analytics_storage, ad_storage, ad_user_data, ad_personalization)
  • SPA page tracking — automatic navigation tracking via VitePress router
  • Non-EU users: analytics enabled silently, no banner shown

Goal: Legally comply with GDPR by showing consent banner to EU users before enabling Google Analytics tracking.


Architecture

@structured-world/vue-privacy (npm package)
├── Core: Consent Manager + Google Consent Mode v2
├── Geo: EU detection (Cloudflare / IP API / Timezone)
├── Storage: Cookie-based consent persistence (365 days)
└── VitePress: enhanceWithConsent() — auto SPA tracking

Flow

  1. enhanceWithConsent() initializes consent manager with sendPageView: false
  2. Geo-detection determines if user is in EU
  3. EU → show banner, GA defaults to denied; Non-EU → grant silently
  4. User accepts/rejects → consent stored in cookie, GA signals updated
  5. Router watch tracks SPA navigation with page_view events via nextTick

Integration (theme/index.ts)

Replace manual gtag implementation with vue-privacy:

import { h } from "vue";
import DefaultTheme from "vitepress/theme";
import type { Theme } from "vitepress";
import { enhanceWithConsent } from "@structured-world/vue-privacy/vitepress";
import "./style.css";
import BugReportWidget from "./components/BugReportWidget.vue";

const GA_ID = import.meta.env.VITE_GA_ID || "G-RY1XJ7LR5F";

const baseTheme = enhanceWithConsent(DefaultTheme, {
  gaId: GA_ID,
  banner: {
    title: "Cookie Consent",
    message: "We use cookies for analytics to improve documentation.",
    privacyLink: "/privacy",
  },
});

export default {
  ...baseTheme,
  Layout() {
    return h(DefaultTheme.Layout, null, {
      "layout-bottom": () => h(BugReportWidget),
    });
  },
} satisfies Theme;

Implementation Tasks

  • Implement SPA page tracking in vue-privacy (feat: SPA page tracking support for VitePress and Vue Router vue-privacy#21)
  • Publish vue-privacy v1.1.0 to npm (via semantic-release after PR merge)
  • Add @structured-world/vue-privacy to devDependencies
  • Replace manual gtag code in docs/.vitepress/theme/index.ts
  • Add /privacy page to docs
  • Test: EU user sees banner, non-EU doesn't
  • Test: GA4 DebugView shows correct consent signals and page_view events
  • Test: SPA navigation tracked correctly

Dependencies

References

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions