Integration

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.

Pug Web SDK: one SDK for the browser @pug-sh/browser Open source, AGPL-3.0

Setup

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.

  1. 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
  2. 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.ts
    import { 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')
  3. 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.ts
    import { identify, reset, track } from '@pug-sh/browser'
    
    export function useAnalytics() {
      return {
        signIn: (id: string, email: string) => identify(id, { email }),
        signOut: () => reset(),
        track,
      }
    }
  4. 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>
Framework notes

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.

What you get

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.

FAQ

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