Product analytics for Vue
Pug’s Web SDK is framework-agnostic JavaScript, so Vue needs no special plugin. Initialise it in main.ts before you mount the app and autocapture does the rest, including Vue Router navigations.
Add Pug to Vue
Four steps, start to first insight. Everything below uses the Web SDK exactly as it ships. There is no Vue wrapper in between.
-
Install the Web SDK
The same package every browser framework uses. Vite resolves it from the package root; there is no plugin to register and nothing to add to your Vue config.
npm install @pug-sh/browser # or: pnpm add @pug-sh/browser · yarn add @pug-sh/browser · bun add @pug-sh/browser -
Initialize before you mount
Call init() in main.ts ahead of createApp().mount() so the first page view lands and the History wrappers are installed before Vue Router takes over navigation.
src/main.tsimport { createApp } from 'vue' import { init } from '@pug-sh/browser' import App from './App.vue' import router from './router' init(import.meta.env.VITE_PUG_PROJECT_ID, { apiKey: import.meta.env.VITE_PUG_PUBLIC_KEY, }) createApp(App).use(router).mount('#app') -
Identify people, reset on sign-out
A composable is the natural home for this in Vue: identify() on sign-in merges the anonymous session into the profile, reset() clears it so a shared browser does not carry one person’s identity into the next session.
src/composables/useAnalytics.tsimport { identify, reset, track } from '@pug-sh/browser' export function useAnalytics() { return { signIn: (id: string, email: string) => identify(id, { email }), signOut: () => reset(), track, } } -
Name the events your funnels need
Autocapture covers the ambient interactions. The steps you actually report on (signup, trial started, checkout) are worth naming explicitly so they survive a redesign of the button that triggers them.
src/components/CheckoutButton.vue<script setup lang="ts"> import { track } from '@pug-sh/browser' const props = defineProps<{ cartValue: number }>() function onCheckout() { track('checkout_started', { value: props.cartValue, currency: 'USD' }) } </script> <template> <button @click="onCheckout">Checkout</button> </template>
What to watch for in Vue
The specifics that decide whether the numbers you see are the numbers that happened.
Vue Router navigations are captured
The SDK wraps history.pushState and history.replaceState and listens for popstate, which is exactly how Vue Router changes the URL in web history mode. Route changes produce a page_view with no navigation guard of your own.
Nuxt: initialise from a client plugin
Under SSR there is no browser to track, so put init() in a .client.ts plugin: Nuxt only loads those in the browser. Server routes that need to emit events use the Node SDK with a private key instead.
Autocapture is an allowlist, not switches
autoCapture: { pageView: true, click: true } enables exactly those two and leaves the other four off. There is no "everything except one" form, which is why the type rejects an explicit false.
Cookieless until someone answers
By default no identifier is written to the device: events flow against a server-derived identity that rotates daily, and a banner wired to optInTracking() upgrades that when the visitor agrees.
Product analytics in your Vue app
-
Autocapture, six trackers
Page views, clicks, scrolls, form starts and submits, rage clicks, and dead clicks: all on after one init(), or narrowed with a per-listener allowlist.
-
One profile per person
identify() merges the anonymous session into the signed-in profile and keeps it joined across devices and later visits.
-
Your own events
track() takes a name and typed properties, with a generated list of well-known event kinds so your names match what the insights expect.
-
Every insight type
Trends, funnels, retention cohorts, segmentation, user flows, and top-K run over the same events, no separate instrumentation per report.
Read it in the docs
The Web SDK reference goes deeper than a setup page can: every option, every event, and the edge cases.
Pug + Vue: common questions
Is there a Vue plugin for Pug?
You don’t need one. Pug ships a single framework-agnostic Web SDK; in Vue you import @pug-sh/browser and call init() in main.ts before mounting. Autocapture and the identify()/track() API work the same as anywhere else.
Does it capture Vue Router navigations?
Yes. The SDK wraps history.pushState and history.replaceState and listens for popstate (the mechanism Vue Router uses in web history mode), so client-side routing produces a page_view automatically. Initialise before mounting so the wrappers are in place for the first navigation.
How do I set it up in Nuxt?
Put init() in a client-only plugin (a file ending .client.ts), so it never runs during server rendering. Everything after that is identical to plain Vue. For events raised inside Nuxt server routes, use the Node SDK with a private key.
Can I run the backend myself?
Yes. Pug is AGPL-3.0 and self-hostable on a single Go binary, or free on the cloud during open beta. Point the SDK at your own deployment with the endpoint option.
What happens before a visitor answers the cookie banner?
The SDK starts cookieless: events are sent, but no identifier is stored on the device: attribution uses a server-derived identity that rotates daily. Nothing is retroactively linked when consent is later granted, so pre-consent activity stays anonymous.
Add Pug to your Vue app.
Open-source product analytics with unified profiles. Self-host under AGPL-3.0, or use the free cloud during open beta.
Questions? Email hello@pug.sh