Add Privacy-First Analytics to Your Nuxt 3 App
Nuxt 3 makes it easy to build fast, SEO-friendly Vue applications. But most analytics solutions undo that work — Google Analytics loads 45KB of JavaScript, sets cookies, and requires consent banners that hurt Core Web Vitals.
Measure.events is a 900-byte script with no cookies and no consent banners. It has an MCP server so your AI coding tools can query your traffic directly. Here’s the Nuxt 3 setup.
Option 1: Nuxt Plugin (Recommended)
Create a client-side plugin that loads the tracking script:
// plugins/measure.client.ts
export default defineNuxtPlugin(() => {
const config = useRuntimeConfig()
const script = document.createElement('script')
script.defer = true
script.dataset.siteKey = config.public.measureSiteKey
script.src = `https://lets.measure.events/api/script/${config.public.measureSiteKey}`
document.head.appendChild(script)
// Track route changes for SPA navigation
const router = useRouter()
router.afterEach(() => {
if (window.measure) {
window.measure.trackPageview()
}
})
})
Add your site key to nuxt.config.ts:
// nuxt.config.ts
export default defineNuxtConfig({
runtimeConfig: {
public: {
measureSiteKey: 'YOUR_SITE_KEY'
}
}
})
The .client.ts suffix ensures the plugin only runs client-side — no SSR issues.
Option 2: useHead in app.vue
For a simpler setup, use Nuxt’s useHead composable:
<!-- app.vue -->
<script setup>
useHead({
script: [
{
defer: true,
'data-site-key': 'YOUR_SITE_KEY',
src: 'https://lets.measure.events/api/script/YOUR_SITE_KEY'
}
]
})
</script>
<NuxtPage />
This approach works for basic page tracking. For SPA route change tracking, pair it with the router afterEach hook from Option 1.
Custom Event Tracking
Track events from any Nuxt component or composable:
<script setup>
function handlePurchase() {
window.measure?.track('purchase', { plan: 'pro', value: 29 })
}
</script>
<template>
<button @click="handlePurchase">Subscribe</button>
</template>
Create a reusable composable for consistent usage:
// composables/useMeasure.ts
export function useMeasure() {
return {
track(event: string, data: Record<string, any> = {}) {
if (import.meta.client && window.measure) {
window.measure.track(event, data)
}
},
trackPageview(path?: string) {
if (import.meta.client && window.measure) {
window.measure.trackPageview(path ? { path } : undefined)
}
}
}
}
Static Generation (nuxi generate)
If you’re using nuxi generate for static site generation, the tracking script works perfectly. Each generated HTML page includes the script tag (via useHead or plugin), and page loads are tracked automatically. For navigation between pre-rendered pages, the SPA router hooks handle tracking.
Why Not @nuxtjs/google-analytics?
The Nuxt Google Analytics module adds GA4’s full 45KB payload to every page. It requires cookie consent management (usually another module). And it gives you a dashboard you have to visit manually.
Measure.events loads 900 bytes, uses no cookies, and the MCP server means your AI tools can answer questions like “which blog posts got the most traffic this week?” without you opening a browser tab.
For Nuxt developers shipping production apps where performance and privacy matter, that’s a meaningful difference.
Nuxt Content Integration
If you’re using @nuxt/content for a blog or docs site, Measure.events automatically tracks every content page. No additional configuration needed beyond the base setup. The tracking script captures the rendered URL, which includes your content routes.
To see which content pages perform best, use the Measure.events dashboard or ask via MCP:
"What are my top blog posts by pageviews this week?"
Getting Started
- Sign up at lets.measure.events
- Create a Nuxt plugin (
plugins/measure.client.ts) with your site key - Add the router
afterEachhook for SPA navigation tracking - Optional: install the MCP server for AI-powered analytics
Setup time: under 5 minutes. No npm packages to install. No build step impact.
Ready to see accurate analytics?
No cookies. No consent banners. No personal data. $29/mo with a 14-day free trial.
Start free trial →