@structured-world/vue-privacy
v1.10.0
Published
Add Google Analytics (GA4) to Vue 3, VitePress, and Quasar with one line of code. Works with Nuxt 3 via the Vue plugin. GDPR/CCPA compliant cookie consent with Google Consent Mode v2, EU auto-detection, and SPA page tracking.
Downloads
2,678
Maintainers
Readme
@structured-world/vue-privacy
GDPR-compliant cookie consent with Google Consent Mode v2 support for Vue 3, Quasar, VitePress, and plain HTML.
Documentation · GitHub · npm
Features
- Google Consent Mode v2 — Full support for
analytics_storage,ad_storage,ad_user_data,ad_personalization - EU Detection — Auto-detect EU users via Cloudflare headers, IP API, or timezone heuristics
- Consent Banner — Customizable GDPR/CCPA banner with dark mode support
- Preference Center — OneTrust-style modal with category toggles (necessary, analytics, marketing, functional)
- Script Blocking — Block third-party scripts until consent is granted
- i18n — 13 built-in locales (en, de, fr, es, it, pt, nl, pl, ru, uk, ja, zh, ko)
- Remote Storage — Pluggable backend for cross-device consent sync
- GA4 Event Tracking — Typed helpers for ecommerce and conversion events
- Framework Support — Vue 3, Quasar, VitePress, Nuxt 3
- UMD/CDN — Use via
<script>tag, no build tools needed - TypeScript — Full type safety
- Lightweight — ~11kB gzip (UMD), no external dependencies
- SSR Safe — Works with server-side rendering
- Accessible — ARIA-compliant components with focus trap
Installation
npm install @structured-world/vue-privacy
# or
yarn add @structured-world/vue-privacy
# or
pnpm add @structured-world/vue-privacyQuick Start
Vue 3
import { createApp } from 'vue';
import { createConsentPlugin } from '@structured-world/vue-privacy/vue';
import router from './router';
import App from './App.vue';
const app = createApp(App);
app.use(router);
app.use(createConsentPlugin({
gaId: 'G-XXXXXXXXXX',
euDetection: 'auto',
router: router, // Enables automatic SPA page tracking
}));
app.mount('#app');<template>
<div id="app">
<ConsentBanner position="bottom" />
<ConsentPreferenceModal />
</div>
</template>VitePress
TypeScript users: Add
vue-routeras a dev dependency for type resolution:npm i -D vue-router(not needed at runtime)
// docs/.vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme';
import { enhanceWithConsent } from '@structured-world/vue-privacy/vitepress';
export default enhanceWithConsent(DefaultTheme, {
gaId: 'G-XXXXXXXXXX',
});Fire GA4 events from frontmatter:
---
ga4Title: Pricing Page
ga4Event:
name: view_pricing
params:
page_type: pricing
---Quasar
// src/boot/consent.ts
import { boot } from 'quasar/wrappers';
import { consentBoot } from '@structured-world/vue-privacy/quasar';
export default boot(consentBoot({
gaId: 'G-XXXXXXXXXX',
}));CDN / Script Tag
<script src="https://unpkg.com/@structured-world/vue-privacy"></script>
<script>
const manager = VuePrivacy.createConsentManager({
gaId: 'G-XXXXXXXXXX',
euDetection: 'auto',
});
manager.init();
</script>Configuration
interface ConsentConfig {
// Google Analytics measurement ID
gaId?: string;
// Locale for UI text (auto-detected if not set)
// Supported: en, de, fr, es, it, pt, nl, pl, ru, uk, ja, zh, ko
locale?: SupportedLocale;
// Consent categories
categories?: {
analytics?: boolean; // Default: false
marketing?: boolean; // Default: false
functional?: boolean; // Default: true
};
// Banner UI
banner?: {
title?: string;
message?: string;
acceptAll?: string;
rejectAll?: string;
customize?: string;
privacyLink?: string;
privacyLinkText?: string;
};
// Preference center UI
preferenceCenter?: {
title?: string;
description?: string;
savePreferences?: string;
acceptAll?: string;
categories?: {
necessary?: { name?: string; description?: string };
analytics?: { name?: string; description?: string };
marketing?: { name?: string; description?: string };
functional?: { name?: string; description?: string };
};
};
// Cookie settings
cookie?: {
name?: string; // Default: 'consent_preferences'
expiry?: number; // Days, default: 365
domain?: string;
path?: string; // Default: '/'
};
// Remote consent storage (pluggable backend)
storage?: ConsentStorage;
// EU detection mode
euDetection?: 'auto' | 'cloudflare' | 'api' | 'always' | 'never';
// Consent version (changing resets all consents)
version?: string;
// Callbacks
onConsentChange?: (consent: StoredConsent) => void;
onBannerShow?: () => void;
onBannerHide?: () => void;
onPreferenceCenterShow?: () => void;
onPreferenceCenterHide?: () => void;
}Composables
<script setup>
import { useConsent } from '@structured-world/vue-privacy/vue';
const {
// Consent management
acceptAll,
rejectAll,
hasConsent,
resetConsent,
showPreferenceCenter,
// GA4 event tracking
trackEvent,
trackPurchase,
trackAddToCart,
trackViewItem,
trackSignUp,
trackLogin,
} = useConsent();
// Track custom event
trackEvent('button_click', { button_id: 'hero-cta' });
// Track purchase
trackPurchase({
transaction_id: 'T12345',
value: 99.99,
currency: 'USD',
items: [{ item_id: 'SKU123', item_name: 'Product', price: 99.99 }],
});
</script>
<template>
<button @click="showPreferenceCenter">Manage Cookies</button>
</template>Script Blocking
Block third-party scripts until consent is granted:
<script type="text/plain" data-consent-category="analytics"
src="https://example.com/analytics.js"></script>
<script type="text/plain" data-consent-category="marketing"
src="https://example.com/ads.js"></script>Scripts are automatically unblocked when the matching category is accepted.
Remote Consent Storage
Sync consent across devices with a pluggable backend:
import { createConsentManager, createKVStorage } from '@structured-world/vue-privacy';
// Built-in Cloudflare KV adapter
const manager = createConsentManager({
gaId: 'G-XXXXXXXXXX',
storage: createKVStorage('/api/consent'),
});
// Or implement your own
const manager = createConsentManager({
storage: {
get: (uid, version) => fetch(`/api/consent?id=${uid}`).then(r => r.json()),
set: (uid, consent) => fetch('/api/consent', {
method: 'POST',
body: JSON.stringify({ id: uid, ...consent }),
}).then(r => r.json()).then(d => d.id),
},
});Core API (Framework-agnostic)
import { createConsentManager } from '@structured-world/vue-privacy';
const manager = createConsentManager({
gaId: 'G-XXXXXXXXXX',
});
await manager.init();
// Programmatic consent
await manager.acceptAll();
await manager.rejectAll();
await manager.savePreferences({ analytics: true, marketing: false });
// Preference center
manager.showPreferenceCenter();
// Check state
const consent = manager.getConsent();
const isEU = manager.isEUUser();
// Cleanup
manager.destroy();EU Detection
Auto (Recommended)
createConsentPlugin({ euDetection: 'auto' })Tries in order:
- Cloudflare
X-Is-EU-Countryheader - IP API (ipapi.co)
- Timezone heuristics fallback
Styling
The banner and preference center use CSS custom properties:
:root {
--consent-bg: #ffffff;
--consent-text: #1a1a1a;
--consent-text-secondary: #666666;
--consent-link: #0066cc;
--consent-btn-accept-bg: #0066cc;
--consent-btn-accept-text: #ffffff;
--consent-btn-reject-bg: #e0e0e0;
--consent-btn-reject-text: #1a1a1a;
--consent-font: system-ui, -apple-system, sans-serif;
}Dark mode is automatically supported via prefers-color-scheme.
Current Features
| Feature | Status | |---------|--------| | Consent banner component | ✅ | | Preference center modal | ✅ | | Google Consent Mode v2 | ✅ | | GA4 integration | ✅ | | GA4 event tracking (ecommerce, conversions) | ✅ | | EU geo-detection | ✅ | | Script blocking | ✅ | | i18n (13 locales) | ✅ | | Vue 3 / VitePress / Quasar / Nuxt 3 | ✅ | | UMD/CDN build | ✅ | | Remote consent storage | ✅ | | Dark mode support | ✅ |
Planned
| Feature | Description | |---------|-------------| | CCPA support | California Consumer Privacy Act compliance | | Analytics dashboard | Opt-in rates, banner interactions (via privacy.structured.world) |
Related Projects
- vue-privacy-worker — Cloudflare Worker for server-side consent storage
License
Apache 2.0 — see LICENSE
