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, theuseTakt()composable, thev-takt-eventdirective, theTaktPlugin, the<TaktBadge>/<TaktEmbed>widget components and thecreateStats()stats client re-exported from the core.@vskstudio/takt-vue/directives— thev-takt-eventdirective +init/track/pageview/optOut/optInfunctions re-exported from the core.@vskstudio/takt-vue/element— the<takt-analytics>web component for plain HTML.
<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:
| Prop | Type | Default | Role |
|---|---|---|---|
domain | string | location.hostname | Site identifier |
endpoint | string | https://taktlytics.com/api/event | Ingestion URL. Pass /api/event for a same-origin first-party proxy. |
scriptOrigin | string | — | First-party origin to derive the endpoint from (the origin followed by /api/event). endpoint wins over it. |
spa | boolean | true | Tracks client navigation (auto pageviews) |
track404 | boolean | false | Reports a 404 event on error pages ([data-takt-404] / <meta name="takt:404"> marker, or a 404 HTTP status). |
outbound | boolean | false | Tracks outbound links |
files | boolean \| string[] | false | Tracks downloads (optional extension list) |
tagged | boolean | false | Auto-tracks [data-takt-event] elements |
respectDnt | boolean | true | Respects Do Not Track |
excludeLocalhost | boolean | true | Ignores localhost / private IPs |
enabled | boolean | true | Master switch — false disables all tracking |
sampleRate | number | 1 | Fraction of sessions to sample (0–1) |
trackQuery | boolean | false | Preserves the query string in page URLs |
queryParams | string[] | — | Params preserved when trackQuery is false (allowlist) |
exclude | string[] | — | Path prefixes never tracked. Segment-bounded: /app matches /app and /app/… but not /application. |
scrubUrl | (url: string) => string | — | Transforms each URL before it is sent |
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, plusquery-paramsandexcludewhich 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.