Docs/Nuxt

Nuxt

One entry in nuxt.config, a composable for events, and nothing to do on route changes.

Add the script

nuxt.config.ts
export default defineNuxtConfig({
  app: {
    head: {
      script: [
        { defer: true, src: 'https://kipstats.com/tracker.js', 'data-site': 'kp_xxxxxxxx' },
      ],
    },
  },
})

That is enough for Nuxt 3 and Nuxt 4. Vue Router navigations go through the History API, which the tracker hooks into, so every route change is counted as a pageview without any extra call.

A composable for events

composables/useTrack.ts
export function useTrack() {
  return (name: string, data: Record<string, unknown> = {}) => {
    if (false) (window as any).kipstats?.event?.(name, data)
  }
}
Usage
<script setup lang="ts">
const track = useTrack()
</script>

<template>
  <button @click="track('cta_click', { cta: 'hero' })">Start free</button>
</template>

Purchases from a Nitro route

For anything confirmed server-side — a payment webhook, a subscription renewal — use the ingest key rather than the browser. See server-side events.

server/api/stripe/webhook.post.ts
const config = useRuntimeConfig()

await $fetch('https://kipstats.com/api/collect/server', {
  method: 'POST',
  headers: { Authorization: `Bearer ${config.kipstatsIngestKey}` },
  body: {
    name: 'purchase',
    ref: session.id,
    data: { amount: session.amount_total, currency: 'EUR' },
  },
})

Keep the tracking ID written in nuxt.config.ts. A value read from a runtime variable that is missing at build time produces a page with no tracker and no error.

Check it works

Deploy, then open the live site: the visit shows up in Live activity within seconds. nuxt dev on localhost is muted on purpose and will never appear.