Skip to content

Google Analytics for VitePress

Add GDPR-compliant Google Analytics to your VitePress site with one line of code.

One-Line Setup

typescript
// 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', // Your GA4 measurement ID
});

TypeScript Users

Add vue-router as a dev dependency for type resolution: npm i -D vue-router

This is only needed for TypeScript compilation — vue-router is not used at runtime (VitePress has its own router).

That's it. This automatically:

  • Loads gtag.js with Google Consent Mode v2 defaults
  • Detects EU users and shows a consent banner when required
  • Tracks page views on every VitePress navigation (SPA-aware)
  • Stores consent in a cookie for 365 days

How SPA Tracking Works

VitePress is a single-page app — navigating between pages doesn't trigger a full page reload. Standard Google Analytics misses these navigations.

enhanceWithConsent handles this automatically:

  1. Sets send_page_view: false to prevent duplicate page views on init
  2. Tracks the initial page view after initialization (skipped if analytics consent was denied)
  3. Watches VitePress router for every navigation
  4. Sends page_view events with correct page_path and page_title after DOM updates

You don't need to write any router watching code.

Frontmatter Events

Fire GA4 events automatically when users visit specific pages using frontmatter:

md
---
# docs/pricing.md
ga4Title: Pricing Page
ga4Event:
  name: view_pricing
  params:
    page_type: pricing
---

# Pricing

Choose your plan...
md
---
# docs/signup-success.md
ga4Title: Registration Complete
ga4Event:
  name: sign_up
  params:
    method: docs
---

# Welcome!

Thank you for signing up.

Supported frontmatter fields:

FieldTypeDescription
ga4TitlestringCustom page title for page_view event
ga4Event{ name, params? }GA4 event to fire on page view

Events fire automatically when the user navigates to the page. This is useful for:

  • Tracking conversions (sign up pages, thank you pages)
  • Measuring engagement with specific content
  • A/B testing page variations

Custom Theme with Layout Slots

If you need to add components to VitePress layout slots alongside the consent banner:

typescript
// docs/.vitepress/theme/index.ts
import { h } from 'vue';
import DefaultTheme from 'vitepress/theme';
import type { Theme } from 'vitepress';
import { enhanceWithConsent } from '@structured-world/vue-privacy/vitepress';

const consentTheme = enhanceWithConsent(DefaultTheme, {
  gaId: 'G-XXXXXXXXXX',
});

export default {
  ...consentTheme,
  Layout() {
    return h(DefaultTheme.Layout, null, {
      // Replace with your own component
      'layout-bottom': () => h('div', 'Custom footer content'),
    });
  },
} satisfies Theme;

Manual Setup (Advanced)

If you need full control over the consent plugin:

typescript
// docs/.vitepress/theme/index.ts
import DefaultTheme from 'vitepress/theme';
import { createConsentPlugin, ConsentBanner } from '@structured-world/vue-privacy/vue';
import type { Theme } from 'vitepress';
import { h } from 'vue';

export default {
  extends: DefaultTheme,
  enhanceApp({ app }) {
    app.use(createConsentPlugin({
      gaId: 'G-XXXXXXXXXX',
      sendPageView: false, // Important: disable for SPA
    }));
  },
  Layout() {
    return h(DefaultTheme.Layout, null, {
      'layout-bottom': () => h(ConsentBanner),
    });
  },
} satisfies Theme;

SPA Page Tracking

When using manual setup, you'll need to implement your own router watching for SPA page tracking. The enhanceWithConsent function does this automatically.

Skip Initial Tracking

enhanceWithConsent always tracks the initial page view. If you need to skip it (e.g., for custom analytics logic), use the manual setup and implement your own tracking with useConsent().trackPageView().

Configuration

All standard options are supported:

typescript
enhanceWithConsent(DefaultTheme, {
  gaId: 'G-XXXXXXXXXX',
  euDetection: 'auto',         // 'auto' | 'cloudflare' | 'api' | 'always' | 'never'
  banner: {
    title: 'Cookie Preferences',
    message: 'This site uses cookies for analytics.',
    acceptAll: 'Accept',
    rejectAll: 'Decline',
    privacyLink: '/privacy',
  },
  cookie: {
    name: 'docs_consent',
    expiry: 365,
  },
});

Event Tracking

Track custom events in your VitePress components:

vue
<!-- docs/components/DownloadButton.vue -->
<script setup>
import { useConsent } from '@structured-world/vue-privacy/vue';

const { trackEvent } = useConsent();

function onDownload(file: string) {
  trackEvent('file_download', {
    file_name: file,
    file_extension: file.split('.').pop(),
  });
}
</script>

<template>
  <button @click="onDownload('guide.pdf')">Download PDF</button>
</template>

Lead Generation

Track documentation-specific conversions:

vue
<script setup>
import { useConsent } from '@structured-world/vue-privacy/vue';

const { trackGenerateLead, trackSignUp } = useConsent();

// Newsletter signup
function onSubscribe(email: string) {
  trackGenerateLead({ lead_source: 'docs_newsletter' });
}

// Account creation
function onCreateAccount() {
  trackSignUp('docs');
}
</script>

See Ecommerce Tracking for more event types.

Styling

The banner inherits VitePress CSS variables when possible. Override with:

css
/* docs/.vitepress/theme/custom.css */
:root {
  --consent-bg: var(--vp-c-bg);
  --consent-text: var(--vp-c-text-1);
  --consent-btn-accept-bg: var(--vp-c-brand);
}

Import in your theme:

typescript
import './custom.css';

Released under the Apache 2.0 License. Powered by structured.world