takt

React

React a un wrapper dédié : @vskstudio/takt-react (provider, hooks, widgets, web component), bâti sur le cœur @vskstudio/takt-core.

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

react (^18 || ^19) et @vskstudio/takt-core (>=0.8.1) sont des peer dependencies : le cœur n’est pas installé automatiquement, ajoute-le explicitement.

Le package est entièrement typé et sûr au SSR / RSC (l’init n’a lieu qu’au montage, côté navigateur). L’entrée . embarque la directive 'use client', donc il s’intègre directement à l’App Router de Next.js. Il expose deux points d’entrée :

  • @vskstudio/takt-react — le provider <Takt>, les hooks useTakt() et useTaktEvent(), le composant <TaktEvent>, les widgets <TaktBadge> et <TaktEmbed>, ainsi que les helpers du cœur réexportés (badgeUrl(), embedUrl(), createStats(), PublicApiError).
  • @vskstudio/takt-react/element — le web component <takt-analytics> sans React, pour du HTML pur.

Provider <Takt> + useTakt()

Place <Takt> une fois près de la racine : il initialise l’instance au montage, émet le pageview initial et câble la navigation SPA. useTakt() récupère l’instance partagée dans n’importe quel composant descendant pour émettre des events.

// app/layout.tsx (ou ton composant racine)
import { Takt } from '@vskstudio/takt-react'

export default function RootLayout({ children }) {
  return (
    <html lang="fr">
      <body>
        <Takt domain="exemple.fr" outbound files>
          {children}
        </Takt>
      </body>
    </html>
  )
}

<Takt> ne rend qu’un provider autour de ses enfants : sous l’App Router de Next.js, c’est bien au layout racine de rendre les balises <html> et <body>.

import { useTakt } from '@vskstudio/takt-react'

function SignupButton() {
  const takt = useTakt()
  return (
    <>
      <button onClick={() => takt.track('Signup', { props: { plan: 'pro' } })}>
        S'inscrire
      </button>
      <button
        onClick={() =>
          takt.track('Purchase', {
            props: { plan: 'pro' },
            revenue: { amount: '29', currency: 'EUR' }
          })
        }
      >
        Acheter
      </button>
    </>
  )
}

Props du provider <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.
scriptOriginstringOrigine first-party dont dériver l’endpoint (l’origine suivie de /api/event). endpoint l’emporte.
outboundbooleanfalseSuit les liens sortants
filesboolean \| string[]falseSuit les téléchargements (liste d’extensions optionnelle)
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).
taggedbooleanfalseSuit automatiquement les clics sur 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[]Paramètres conservés quand trackQuery est false (liste blanche)
excludestring[]Préfixes de chemin jamais suivis. Bornés au segment : /app couvre /app et /app/… mais pas /application.
scrubUrl(url: string) => stringTransforme chaque URL avant envoi

Les props de config sont lues une seule fois au montage de <Takt> — les changer ensuite n’a aucun effet ; remonte le composant pour reconfigurer.

Le provider transmet toute cette configuration au cœur : les réglages avancés (enabled, sampleRate, trackQuery, queryParams, exclude, scrubUrl) sont disponibles en props, sans piloter le cœur à côté. Seul debug n'est pas exposé : pour l'activer, instancie le cœur toi-même avec createTakt() — et n'utilise pas <Takt> en même temps, sous peine de doubler les pageviews. N'appelle jamais init() au niveau module dans un fichier rendu côté serveur : le cœur touche history à l'instanciation.

scrubUrl est une fonction : elle ne peut pas traverser la frontière serveur → client de Next.js. Rends <Takt> depuis un composant client si tu la passes.

useTakt() ne lève jamais : appelé hors d’un <Takt> ou pendant le SSR, il renvoie une instance no-op. Les appels restent inoffensifs, mais le premier track() / pageview() émet un console.warn signalant que <Takt> n’est pas monté.

Hook useTaktEvent() + <TaktEvent>

Pour du tracking de clic déclaratif, useTaktEvent() renvoie un { onClick } que tu étales sur n’importe quel élément. L’instance est résolue au moment du clic (pas de closure périmée), avec un repli sur le track() du cœur :

import { useTaktEvent } from '@vskstudio/takt-react'

function BuyButtons() {
  const signup = useTaktEvent({ name: 'Signup', props: { plan: 'pro' } })
  const purchase = useTaktEvent({
    name: 'Purchase',
    revenue: { amount: '29', currency: 'EUR' }
  })
  return (
    <>
      <button {...signup}>S'inscrire</button>
      <button {...purchase}>Acheter</button>
    </>
  )
}

<TaktEvent> enveloppe un unique enfant et compose son onClick existant, pour annoter un élément sans toucher à son handler. Il forwarde les refs vers l’enfant :

import { TaktEvent } from '@vskstudio/takt-react'

function Cta({ onClick }) {
  return (
    <TaktEvent name="Signup" props={{ plan: 'pro' }}>
      <button onClick={onClick}>S'inscrire</button>
    </TaktEvent>
  )
}

Le onClick d’origine de l’enfant se déclenche toujours ; le tracking tourne en parallèle.

Widgets <TaktBadge> et <TaktEmbed>

Pour afficher les statistiques publiques d’un site (voir Widgets), le package fournit deux composants prêts à poser :

import { TaktBadge, TaktEmbed } from '@vskstudio/takt-react'

function Footer() {
  return (
    <>
      <TaktBadge domain="exemple.fr" variant="b" glyph="dash" lang="fr" />
      <TaktEmbed domain="exemple.fr" theme="dark" lang="fr" />
    </>
  )
}

<TaktBadge> rend une <img> (loading="lazy", decoding="async") : variant vaut a, b ou d, glyph vaut unplug, dash, off ou eyeoff. <TaktEmbed> rend une <iframe> de 404×264 par défaut, loading="lazy" et sandboxée : theme vaut light, dark ou auto. Les deux acceptent lang (fr / en), une prop host pour pointer une autre origine Takt, et forwardent le reste de leurs attributs à l’élément rendu.

Web component <takt-analytics>

Pour du HTML pur ou un framework non-React, importe l’élément sans React (auto-enregistré) :

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

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

Les attributs miroir des props, en kebab-case :

  • Drapeaux (présence = actif, valeur ignorée) : outbound, files, tagged.
  • 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, ainsi que query-params et exclude qui prennent une liste séparée par des virgules.
<takt-analytics domain="exemple.fr" spa="false" respect-dnt="false"></takt-analytics>

files ne prend pas de liste d’extensions ici, et scrubUrl n’a pas d’équivalent : ce sont des valeurs que seul le provider <Takt> reçoit en props. La détection 404 passe elle aussi par la prop track404. Le bundle est sûr au SSR : l’importer côté serveur est un no-op tant que customElements n’existe pas.