takt

Vue

Vue has a dedicated wrapper: @vskstudio/takt-vue (component, composable, directive, plugin, web component), built on the @vskstudio/takt-core core.

The core is a peer dependency: install both packages.

pnpm add @vskstudio/takt-vue @vskstudio/takt-core
# or: npm install @vskstudio/takt-vue @vskstudio/takt-core
# or: yarn add @vskstudio/takt-vue @vskstudio/takt-core
# or: bun add @vskstudio/takt-vue @vskstudio/takt-core

vue (^3.3.0) and @vskstudio/takt-core (>=0.8.1) are peer dependencies. The package exposes three subpaths:

  • @vskstudio/takt-vue — the <Takt> component, the useTakt() composable, the v-takt-event directive, the TaktPlugin, the <TaktBadge> / <TaktEmbed> widget components and the createStats() stats client re-exported from the core.
  • @vskstudio/takt-vue/directives — the v-takt-event directive + init/track/pageview/optOut/optIn functions re-exported from the core.
  • @vskstudio/takt-vue/element — the <takt-analytics> web component for plain HTML.
Only <Takt>, TaktPlugin and <takt-analytics> are SSR-safe: they initialize on mount, in the browser. The init() from the /directives subpath touches location and history as soon as it is called — running it at the module level of a universal Nuxt plugin or in a <script setup> executes it during server rendering and throws ReferenceError: history is not defined. Call it from onMounted, or from a .client.ts Nuxt plugin.

<Takt> component + useTakt()

Place <Takt> once (typically in App.vue): it initializes the instance on mount, emits the initial pageview, wires up SPA navigation and publishes the instance application-wide. useTakt() retrieves it from any component — a module store acts as the relay — not only below <Takt>.

<!-- App.vue -->
<script setup>
import { Takt } from '@vskstudio/takt-vue'
</script>

<template>
  <Takt domain="example.com" :outbound="true" :files="['pdf', 'zip']">
    <RouterView />
  </Takt>
</template>

Call useTakt() inside the handler, not at the <script setup> level: setup runs before <Takt>’s onMounted, and in Vue a parent’s mounted fires after its children’s — so even a child onMounted is too early. An instance captured there would be the permanent no-op, and every event would go nowhere. With TaktPlugin given options, the instance exists as soon as the plugin is installed: capturing it at setup level is valid there.

<script setup>
import { useTakt } from '@vskstudio/takt-vue'

function onSignup() {
  useTakt().track('Signup', {
    props: { plan: 'pro' },
    revenue: { amount: '29.00', currency: 'EUR' }
  })
}
</script>

<template>
  <button @click="onSignup">Sign up</button>
</template>

<Takt> component props:

PropTypeDefaultRole
domainstringlocation.hostnameSite identifier
endpointstringhttps://taktlytics.com/api/eventIngestion URL. Pass /api/event for a same-origin first-party proxy.
scriptOriginstringFirst-party origin to derive the endpoint from (the origin followed by /api/event). endpoint wins over it.
spabooleantrueTracks client navigation (auto pageviews)
track404booleanfalseReports a 404 event on error pages ([data-takt-404] / <meta name="takt:404"> marker, or a 404 HTTP status).
outboundbooleanfalseTracks outbound links
filesboolean \| string[]falseTracks downloads (optional extension list)
taggedbooleanfalseAuto-tracks [data-takt-event] elements
respectDntbooleantrueRespects Do Not Track
excludeLocalhostbooleantrueIgnores localhost / private IPs
enabledbooleantrueMaster switch — false disables all tracking
sampleRatenumber1Fraction of sessions to sample (0–1)
trackQuerybooleanfalsePreserves the query string in page URLs
queryParamsstring[]Params preserved when trackQuery is false (allowlist)
excludestring[]Path prefixes never tracked. Segment-bounded: /app matches /app and /app/… but not /application.
scrubUrl(url: string) => stringTransforms each URL before it is sent
The component forwards all of these options to the core: the advanced settings (enabled, sampleRate, trackQuery, queryParams, exclude, scrubUrl) are available as props, without going through the /directives subpath. Only debug is not exposed.

useTakt() does not throw: called before <Takt> mounts or during SSR, it returns a no-op instance — and warns once in the console (useTakt() called before <Takt> mounted). That message is the symptom of the trap above.

v-takt-event directive

For simple click tracking, bind the directive instead of a handler. It is reactive (changing the bound value updates what gets tracked) and the listener is cleaned up on unmount. At click time it tracks through the active instance (the one provided by <Takt> or TaktPlugin), falling back to the core default instance if you drive init() yourself:

<script setup>
import { vTaktEvent } from '@vskstudio/takt-vue'
</script>

<template>
  <button v-takt-event="{ name: 'Signup', props: { plan: 'pro' } }">
    Sign up
  </button>

  <button v-takt-event="{ name: 'Purchase', revenue: { amount: '29.00', currency: 'EUR' } }">
    Buy
  </button>
</template>

The directive and the core functions are also available from the ./directives subpath if you prefer a functional import:

import { vTaktEvent, track, pageview, optOut, optIn } from '@vskstudio/takt-vue/directives'

Plugin

app.use(TaktPlugin) registers the v-takt-event directive and the global <TaktBadge> / <TaktEmbed> components (no per-component import needed). Passing options also bootstraps a single instance (pageview + autocapture) without a <Takt> component:

import { createApp } from 'vue'
import { TaktPlugin } from '@vskstudio/takt-vue'
import App from './App.vue'

createApp(App)
  .use(TaktPlugin, { domain: 'example.com', outbound: true })
  .mount('#app')

Installing without options performs only those registrations — use <Takt> for instance lifecycle in that case. Bootstrapping is skipped on the server.

<takt-analytics> web component

For plain HTML or a non-Vue framework, import the ./element subpath (auto-registered, a native HTMLElement — no Vue runtime bundled; only the core is, so no build step or import map is needed):

<script type="module">
  import '@vskstudio/takt-vue/element'
</script>

<takt-analytics domain="example.com" outbound></takt-analytics>

Attributes mirror the props:

  • Flags (presence = on, value ignored): outbound, files, track404.
  • On by default, set ="false" (or ="0") to turn them off: spa, respect-dnt, exclude-localhost.
  • Values: domain, endpoint, script-origin, enabled, sample-rate, track-query, plus query-params and exclude which take a comma-separated list.

tagged turns on when the attribute is present, but honours ="false" and ="0" to stay off. files takes no extension list here, and scrubUrl has no equivalent: those are functions and arrays the <Takt> component receives as props, out of reach of an HTML attribute.

<takt-analytics domain="example.com" spa="false" respect-dnt="false"></takt-analytics>

defineTaktElement() is also exported for explicit, idempotent registration. The bundle is SSR-safe: importing it on the server is a no-op until customElements exists.