takt

Vue

Vue a un wrapper dédié : @vskstudio/takt-vue (composant, composable, directive, plugin, web component), bâti sur le cœur @vskstudio/takt-core.

Le cœur est une dépendance peer : installe les deux paquets.

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

vue (^3.3.0) et @vskstudio/takt-core (>=0.10.0 depuis la 0.8.0) sont des peer dependencies. Le package expose trois sous-chemins :

  • @vskstudio/takt-vue : le composant <Takt>, le composable useTakt(), la directive v-takt-event, le TaktPlugin, les composants widgets <TaktBadge> / <TaktEmbed>, le client stats createStats() et les fonctions de consentement optOut() / optIn() / isOptedOut() réexportés du cœur.
  • @vskstudio/takt-vue/directives : la directive v-takt-event + les fonctions init/track/pageview/optOut/optIn/isOptedOut réexportées du cœur.
  • @vskstudio/takt-vue/element : le web component <takt-analytics> pour du HTML pur.
Seuls <Takt>, TaktPlugin et <takt-analytics> sont sûrs au SSR : ils n'initialisent qu'au montage, côté navigateur. Le init() du sous-chemin /directives touche location et history dès l'appel. L'exécuter au niveau module d'un plugin Nuxt universel ou dans un <script setup> le fait tourner au rendu serveur et lève ReferenceError: history is not defined. Appelle-le depuis onMounted, ou depuis un plugin Nuxt .client.ts.

Composant <Takt> + useTakt()

Place <Takt> une fois (typiquement dans App.vue) : il initialise l’instance au montage, émet le pageview initial, câble la navigation SPA et publie l’instance à l’échelle de l’application. useTakt() la récupère depuis n’importe quel composant (un store de module sert de relais), et pas seulement sous <Takt>.

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

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

Appelle useTakt() dans le gestionnaire, pas au niveau du <script setup> : le setup s’exécute avant le onMounted de <Takt>, et en Vue le mounted du parent passe après celui des enfants. Même un onMounted d’enfant est donc trop tôt. Une instance capturée là serait le no-op définitif, et tous les events partiraient dans le vide. Avec TaktPlugin muni d’options, l’instance existe dès l’installation du plugin : la capture au niveau setup y est valide.

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

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

<template>
  <button @click="inscription">S'inscrire</button>
</template>

Props du composant <Takt> :

PropTypeDéfautRôle
domainstringlocation.hostnameIdentifiant du site
endpointstringhttps://taktlytics.com/api/eventURL d’ingestion. Passe /api/event pour un proxy first-party same-origin.
scriptOriginstringaucunOrigine first-party dont dériver l’endpoint (l’origine suivie de /api/event). endpoint l’emporte.
spabooleantrueSuit la navigation client (pageviews auto)
track404booleanfalseSignale un événement 404 sur les pages d’erreur (marqueur [data-takt-404] / <meta name="takt:404">, ou statut HTTP 404).
outboundbooleanfalseSuit les liens sortants
filesboolean \| string[]falseSuit les téléchargements (liste d’extensions optionnelle)
taggedbooleanfalseSuit automatiquement les éléments [data-takt-event]
respectDntbooleantrueRespecte Do Not Track
excludeLocalhostbooleantrueIgnore localhost / IP privées
enabledbooleantrueInterrupteur général : false coupe toute mesure
sampleRatenumber1Fraction de sessions échantillonnées (0 à 1)
trackQuerybooleanfalseConserve la query string dans les URL
queryParamsstring[]aucunParamètres conservés quand trackQuery est false (liste blanche)
excludestring[]aucunPréfixes de chemin jamais suivis. Bornés au segment : /app couvre /app et /app/… mais pas /application.
scrubUrl(url: string) => stringaucunTransforme chaque URL avant envoi (page, referrer, url des liens sortants et des téléchargements, path des 404)
debugbooleanfalseTrace chaque payload dans la console avant l’envoi
redactRoutesstring[]aucunMotifs de routes sensibles : un chemin qui correspond part sous la forme du motif, ex. ['/verify/:token'] (voir Masquage de routes)
redactUndecodablePathsbooleantrueNon exposée par ce wrapper : se règle sur le SDK core (init() / createTakt()), voir Chemins illisibles
routeTemplatesbooleanfalseEnvoie chaque page sous la forme de son gabarit de route au lieu du chemin réel
routeTemplate() => string \| null \| undefinedaucunRésolveur du gabarit de la route courante, lu seulement quand routeTemplates est actif
routerRouterLikeaucunInstance Vue Router : avec routeTemplates et sans routeTemplate, vueRouterTemplate(router) est utilisé. Non transmis au cœur
Le composant forwarde toutes ces options au cœur : les réglages avancés (enabled, sampleRate, trackQuery, queryParams, exclude, scrubUrl) sont disponibles en props, sans passer par le sous-chemin /directives, tout comme debug depuis la 0.7.0.

useTakt() ne lève pas : appelé avant le montage de <Takt> ou pendant le SSR, il renvoie une instance no-op et avertit une fois en console (useTakt() called before <Takt> mounted). Ce message est le symptôme du piège ci-dessus. Les appels de consentement font exception : ils agissent réellement, voir Consentement.

Consentement

optOut, optIn et isOptedOut sont exportés depuis la racine du package (et depuis ./directives). Ils n’ont besoin d’aucune instance : une bannière de consentement peut les appeler partout, avant ou après le montage de <Takt>, et l’instance créée ensuite respecte le choix. Sur l’instance no-op, useTakt().optOut(), useTakt().optIn() et useTakt().isOptedOut() délèguent aussi à ces fonctions.

<script setup lang="ts">
import { ref, onMounted } from 'vue'
import { optOut, optIn, isOptedOut } from '@vskstudio/takt-vue'

const optedOut = ref(false)
onMounted(() => {
  optedOut.value = isOptedOut()
})

function toggle() {
  if (optedOut.value) optIn()
  else optOut()
  optedOut.value = isOptedOut()
}
</script>

<template>
  <button @click="toggle">{{ optedOut ? 'Accepter la mesure' : 'Refuser la mesure' }}</button>
</template>

isOptedOut() lit le localStorage : sur un composant rendu côté serveur, appelle-le dans le navigateur (onMounted ou un gestionnaire d’événement).

Directive v-takt-event

Pour du simple suivi de clic, lie la directive plutôt qu’un handler. Elle est réactive (changer la valeur liée met à jour ce qui est suivi) et le listener est nettoyé au démontage. Au clic, elle suit via l’instance active (celle fournie par <Takt> ou TaktPlugin), avec repli sur l’instance par défaut du cœur si tu pilotes init() toi-même :

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

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

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

La directive et les fonctions du cœur sont aussi disponibles depuis le sous-chemin ./directives si tu préfères un import fonctionnel :

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

Plugin

app.use(TaktPlugin) enregistre la directive v-takt-event et les composants globaux <TaktBadge> / <TaktEmbed> (plus besoin de les importer par composant). En passant des options, il bootstrappe aussi une instance unique (pageview + autocapture) sans composant <Takt> :

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

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

Sans options, seuls ces enregistrements ont lieu. Utilise <Takt> pour le cycle de vie de l’instance dans ce cas. Le bootstrap est ignoré côté serveur.

Masquage de routes

La query string est retirée par défaut, mais le chemin part en clair : /verify/abc123 transmet le jeton. Liste les routes sensibles dans redactRoutes : un chemin qui correspond part sous la forme de son motif, toutes les autres pages gardent leur chemin réel.

createApp(App)
  .use(TaktPlugin, { domain: 'exemple.fr', redactRoutes: ['/verify/:token', '/reset/:code'] })
  .mount('#app')

Les motifs acceptent la syntaxe Vue Router (:param, :param?, *, **) ainsi que la syntaxe à crochets ([param], [[optionnel]], [...reste]). La règle couvre aussi le referrer du même site, les liens sortants et les téléchargements, et le chemin des 404.

Pour une application entièrement privée, routeTemplates: true envoie chaque page sous la forme de son gabarit (/users/42 devient /users/:id). Passe ton routeur et le plugin lit la route trouvée pour toi :

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

createApp(App)
  .use(router)
  .use(TaktPlugin, { domain: 'exemple.fr', routeTemplates: true, router })
  .mount('#app')

Le composant fonctionne de la même façon : <Takt domain="exemple.fr" route-templates :router="router">. En interne, c’est vueRouterTemplate(router), exporté depuis la racine du package, qui renvoie le path de l’enregistrement le plus profond de la route trouvée (Vue Router le stocke déjà en chemin complet normalisé, ex. /users/:id). Passe ton propre routeTemplate pour le remplacer. Le helper est typé structurellement : le package ne dépend pas de vue-router. Sur un site public, ce mode fusionne tous les articles en une seule ligne : préfère redactRoutes. Détails dans Vie privée.

Web component <takt-analytics>

Pour du HTML pur ou un framework non-Vue, importe le sous-chemin ./element (auto-enregistré, HTMLElement natif, aucun runtime Vue embarqué ; seul le cœur est bundlé, donc aucun build ni import map requis) :

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

<takt-analytics domain="exemple.fr" outbound></takt-analytics>

Les attributs miroir des props :

  • Drapeaux (présence = actif, valeur ignorée) : outbound, files, track404.
  • Actifs par défaut, mets ="false" (ou ="0") pour les couper : spa, respect-dnt, exclude-localhost.
  • Valeurs : domain, endpoint, script-origin, enabled, sample-rate, track-query, debug (lu seulement si l’attribut est présent), ainsi que query-params, exclude et redact-routes qui prennent une liste séparée par des virgules.

tagged s’active à la présence de l’attribut, mais honore ="false" et ="0" pour rester coupé. L’élément n’a pas de routeur, donc pas de mode routeTemplates. files ne prend pas de liste d’extensions ici, et scrubUrl n’a pas d’équivalent : ce sont des fonctions et des tableaux que le composant <Takt> reçoit en props, hors de portée d’un attribut HTML.

<takt-analytics domain="exemple.fr" spa="false" respect-dnt="false"></takt-analytics>

defineTaktElement() est aussi exporté pour un enregistrement explicite et idempotent. Le bundle est sûr au SSR : l’importer côté serveur est un no-op tant que customElements n’existe pas.