Vanilla JS
@vskstudio/takt-core est le cœur agnostique sur lequel tous les wrappers sont bâtis. Entièrement typé, zéro dépendance, il fonctionne dans n'importe quel bundler, et embarque aussi le snippet CDN.
L'import est sûr côté serveur : le module ne touche aucune API navigateur au chargement, et track() / pageview() sont des no-op tant que init() n'a pas tourné. optOut(), optIn() et isOptedOut() n'ont besoin d'aucune instance (ils lisent et écrivent le choix stocké dans le navigateur, et ne font rien côté serveur). En revanche init() lui-même s'appelle dans le navigateur : il câble history et lit location.
pnpm add @vskstudio/takt-core
# ou : npm install @vskstudio/takt-core
# ou : yarn add @vskstudio/takt-core
# ou : bun add @vskstudio/takt-core init() + track()
Appelle init() une seule fois au démarrage : il crée l’instance partagée, émet le pageview initial et câble la navigation SPA (pushState/replaceState/popstate/hashchange). Ces deux derniers points sont pilotés par l’option auto : avec auto: false, ni le patch d’historique ni le pageview de boot ne sont posés. Ensuite, émets tes events de n’importe où avec track().
import { init, track } from '@vskstudio/takt-core'
// Une fois, au démarrage de l'app.
init({ domain: 'exemple.fr', outbound: true })
// Partout ailleurs.
track('Signup', { props: { plan: 'pro' } }) init() est idempotent : un second appel détache les listeners de l’instance précédente avant d’en créer une nouvelle. La liste complète des options vit dans la configuration et la référence API.
Revenue
track() accepte un objet revenue en plus des props, le montant est une chaîne qui matche \d+(\.\d{1,2})?, la devise un code à 3 lettres (envoyée en majuscules) :
import { track } from '@vskstudio/takt-core'
track('Purchase', {
props: { plan: 'pro' },
revenue: { amount: '29.00', currency: 'EUR' }
}) Si le montant ou la devise ne valide pas, le revenue est abandonné (avertissement en console) mais l’event est quand même envoyé.
L’instance renvoyée par init(), ou par createTakt(), qui construit une instance isolée sans singleton, expose exactement la même signature, utile si tu préfères ne pas dépendre du singleton :
const takt = init({ domain: 'exemple.fr' })
takt.track('Purchase', { revenue: { amount: '29.00', currency: 'EUR' } }) pageview() + consentement
pageview() émet un pageview à la main. Il est rarement utile tant que auto est actif, puisque la navigation est alors suivie toute seule ; c’est en revanche le bon outil quand tu as désactivé auto (c’est ce que fait l’intégration Astro). optOut() / optIn() pilotent le consentement par visiteur, persisté dans localStorage sous la clé takt_ignore, et isOptedOut() le relit :
import { pageview, optOut, optIn, isOptedOut } from '@vskstudio/takt-core'
optOut() // aucun event envoyé
optIn() // reprend le tracking
isOptedOut() // true après optOut(), pour afficher l'état d'un interrupteur
pageview() Depuis la 0.9.0, ces trois fonctions marchent sans instance : une bannière de consentement peut les appeler avant init(), et toute instance créée ensuite respecte le choix. Une instance issue de createTakt() expose aussi optOut(), optIn() et isOptedOut(), branchés sur le même état stocké.
import { init, isOptedOut, optOut } from '@vskstudio/takt-core'
function onConsentRefused() {
optOut()
}
function startAnalytics() {
if (!isOptedOut()) init({ domain: 'exemple.fr' })
} Voir Vie privée pour l’ordre exact des garde-fous.
Masquage de routes
Depuis la 0.10.0, redactRoutes remplace le chemin des routes sensibles par leur motif, et routeTemplates envoie toutes les pages sous forme de gabarit :
import { init } from '@vskstudio/takt-core'
init({ domain: 'exemple.fr', redactRoutes: ['/verify/[token]', '/reset/:code'] }) L’option redactUndecodablePaths (depuis 0.12.0, défaut true) se règle au même endroit : init({ domain: 'exemple.fr', redactRoutes: ['/verify/[token]'], redactUndecodablePaths: false }) compare un chemin illisible aux routes au lieu de le masquer. Voir Chemins illisibles.
Sans framework, le cœur ne connaît pas ton routeur : pour routeTemplates, fournis un résolveur routeTemplate qui renvoie le gabarit de la route courante, ou null quand aucune ne correspond.
init({
domain: 'app.exemple.fr',
routeTemplates: true,
routeTemplate: () => router.currentRoute?.pattern ?? null
}) Les wrappers de framework branchent ce résolveur sur leur routeur. Voir Masquage de routes pour la syntaxe des motifs et le compromis sur les statistiques par page.
Snippet CDN
Pas de bundler ? Le même package fournit un script prêt à l’emploi : une seule balise dans le <head>, l’init se fait depuis les attributs data-* :
<script defer src="https://cdn.jsdelivr.net/npm/@vskstudio/takt-core/dist/takt.js" data-domain="exemple.fr"></script> Sans data-endpoint ni data-script-origin, le snippet envoie vers https://taktlytics.com/api/event, comme le SDK npm. Passe data-endpoint="/api/event" pour un proxy first-party same-origin.
Côté snippet, seul window.takt(...) (la fonction track) est exposé : voir Installation pour le shim de file d’attente et la référence API pour le global. Le snippet ne gère pas redactRoutes ni routeTemplates : le chemin part en clair.
Côté serveur
Le même package expose une entrée Node, @vskstudio/takt-core/server, pour envoyer pages vues et événements serveur à serveur avec createServerTakt(). Voir Node.js (serveur).
@vskstudio/takt-core.