Laravel
Le bridge Laravel vskstudio/takt-laravel câble le cœur PHP dans le conteneur : une directive Blade pour le snippet, une façade pour le S2S et une config publiable. 0.5.x — PHP 8.1+, Laravel 10 / 11 / 12.
composer require vskstudio/takt-laravel Le TaktServiceProvider est auto-découvert : SnippetRenderer (rendu du snippet) et Takt (client S2S) sont liés dans le conteneur d’après la config, et l’IP / l’User-Agent sont forwardés au client S2S lorsqu’une requête HTTP est disponible.
Cette page est la référence des options. Pour l’intégration de bout en bout et son piège principal — l’attribution des envois S2S émis hors requête visiteur, dans un job en file, une commande Artisan ou un webhook — voir le guide analytics sans cookie dans une application Laravel.
Configuration
php artisan vendor:publish --tag=takt-config takt-config est le seul tag publiable du paquet. config/takt.php lit les variables d’environnement :
TAKT_DOMAIN=exemple.fr
TAKT_API_KEY=tk_… # requis seulement pour le S2S
TAKT_MODE=inline # inline (défaut) | cdn | asset | sdk
TAKT_ENDPOINT=https://taktlytics.com/api/event # voir « Endpoint et origine first-party »
TAKT_SCRIPT_ORIGIN=https://analytics.exemple.fr # origine first-party servant le tracker
TAKT_EXCLUDE_LOCALHOST=false # défaut : true — rien n'est mesuré depuis localhost
TAKT_NONCE=… # nonce CSP de la balise script
TAKT_OUTBOUND=true
TAKT_FILES=true
TAKT_TAGGED=true
TAKT_NOT_FOUND=true
TAKT_FILE_EXTENSIONS=pdf,zip,docx
# Options avancées — laisser vide garde le défaut du tracker
TAKT_SAMPLE_RATE=0.5 # n'envoie qu'une fraction (0–1) des hits
TAKT_TRACK_QUERY=true # conserve la query string + le hash (défaut : strippés)
TAKT_QUERY_PARAMS=utm_source,utm_medium # allowlist quand track_query est off
TAKT_EXCLUDE=/app,/account # préfixes de chemin jamais suivis — requiert TAKT_MODE=sdk
TAKT_RESPECT_DNT=false # cesse de respecter Do-Not-Track
TAKT_ENABLED=false # coupe-circuit : snippet no-op TAKT_EXCLUDE_LOCALHOST vaut true par défaut : en développement local, rien n’est mesuré tant que tu ne l’as pas passé à false.
Modes de rendu
TAKT_MODE choisit la source du runtime navigateur :
TAKT_MODE | Rendu |
|---|---|
inline (défaut) | Le bundle takt.auto.js vendoré est embarqué dans une balise <script> inline : aucune requête en plus, mais du JS inline dans chaque page — sous CSP stricte, renseigne TAKT_NONCE |
cdn | <script defer src="https://cdn.jsdelivr.net/npm/@vskstudio/[email protected]/dist/takt.auto.js"> |
asset | <script defer src="/takt/takt.auto.js"> — copie auto-hébergée, préfixée de TAKT_SCRIPT_ORIGIN si l’origine est définie |
sdk | <script type="module">import{init}…;init({…})</script> — SDK complet, chargé depuis jsDelivr ou depuis /takt/takt.esm.js sur TAKT_SCRIPT_ORIGIN |
TAKT_OUTBOUND, TAKT_FILES, TAKT_TAGGED et TAKT_NOT_FOUND ajoutent chacun un token (outbound, downloads, tagged, 404) à l’unique attribut data-auto que lit le bundle, en modes inline, cdn et asset ; en mode sdk ce sont des clés booléennes (outbound, files, tagged, notFound) de l’objet passé à init().
public/. Pour TAKT_MODE=asset, copie vendor/vskstudio/takt-core-php/resources/takt.auto.js vers public/takt/takt.auto.js — par exemple depuis un script post-update-cmd de ton composer.json, pour que la copie suive les mises à jour du paquet.Options réservées au mode sdk
TAKT_SCRUB_URL — une fonction JS brute de réécriture d’URL, injectée verbatim dans la page, à réserver au dev : ne la construis jamais à partir d’entrées utilisateur — et TAKT_EXCLUDE n’existent que dans le SDK complet. Posées dans un autre mode, elles ne sont pas ignorées : la construction du SnippetRenderer lève une InvalidArgumentException, donc une 500 sur toutes les pages qui rendent le snippet.
TAKT_MODE=sdk
TAKT_SCRUB_URL="(u) => u.split('#')[0]"
TAKT_EXCLUDE=/app,/account Endpoint et origine first-party
TAKT_ENDPOINT alimente deux consommateurs qui ne lisent pas la même chose dans la valeur :
- le snippet rendu par
@taktla reçoit telle quelle (attributdata-endpoint, ou cléendpointde l’appelinit()en modesdk) et POSTe sur cette URL exacte ; - la façade
Taktla traite comme une origine de base et lui ajoute/api/eventà chaque envoi.
TAKT_ENDPOINT | Le snippet POSTe sur | La façade POSTe sur |
|---|---|---|
https://taktlytics.com (défaut du paquet) | https://taktlytics.com — hors point d’ingestion | https://taktlytics.com/api/event |
https://taktlytics.com/api/event | https://taktlytics.com/api/event | https://taktlytics.com/api/event/api/event — hors point d’ingestion |
Aucune valeur unique ne convient aux deux usages. Choisis selon ce que tu utilises :
- snippet seul (pas de clé d’API) :
TAKT_ENDPOINT=https://taktlytics.com/api/event; - S2S seul : garde le défaut
https://taktlytics.com; - les deux : garde l’URL complète pour le snippet et rebinde le client S2S sur l’origine, dans le
register()de tonAppServiceProvider:
use Vskstudio\Takt\Takt;
$this->app->scoped(Takt::class, function ($app) {
$takt = new Takt('https://taktlytics.com', config('takt.domain'), config('takt.api_key'));
$request = $app['request'] ?? null;
return $request === null ? $takt : $takt->withVisitor($request->ip(), $request->userAgent());
}); TAKT_SCRIPT_ORIGIN est l’origine first-party que tu proxifies vers Takt pour esquiver les bloqueurs. Elle est rendue en data-script-origin et sert le fichier du tracker en modes asset et sdk. Le tracker n’en dérive le point d’ingestion — l’origine suivie de /api/event — que si aucun endpoint n’est rendu, ce qui suppose TAKT_ENDPOINT=https://taktlytics.com/api/event. Avec toute autre valeur, data-endpoint est rendu et prime sur l’origine, qui ne sert alors qu’à charger le fichier.
Directive Blade @takt
Place @takt dans le <head> de ton layout pour rendre le snippet :
<head>
<meta charset="utf-8">
@takt
</head> La directive ne prend pas d’argument : elle compile un appel fixe à SnippetRenderer::render(), et toute expression écrite entre parenthèses est ignorée sans erreur. Le snippet est donc rendu à partir de la seule configuration.
Pour un rendu différent — typiquement un nonce CSP, propre à chaque requête alors que le SnippetRenderer est un singleton — rebinde le renderer avant le rendu de la vue, depuis un middleware :
use Illuminate\Support\Facades\App;
use Vskstudio\Takt\Options;
use Vskstudio\Takt\SnippetRenderer;
App::bind(SnippetRenderer::class, fn () => new SnippetRenderer(Options::fromArray(
['nonce' => $nonce, 'scriptOrigin' => config('takt.script_origin')] + config('takt')
))); Options::fromArray() lit les autres clés en snake_case, comme la config ; scriptOrigin est la seule attendue en camelCase.
Façade Takt (serveur-à-serveur)
use Vskstudio\Takt\Laravel\Facades\Takt;
use Vskstudio\Takt\Revenue;
Takt::event('Signup', ['plan' => 'pro']);
Takt::event('Purchase', ['plan' => 'pro'], new Revenue(amount: '29', currency: 'EUR'));
Takt::pageview('https://exemple.fr/merci'); event(string $name, array $props = [], ?Revenue $revenue = null, ?string $url = null, ?string $referrer = null): voidpageview(?string $url = null, ?string $referrer = null): void- Sans
$url, l’événement part avec une URL vide : il est comptabilisé, mais rattaché à aucune page. - Fire-and-forget : un
202vaut succès ; par défaut les erreurs de transport et les statuts non-202sont avalés, l’analytics ne devant jamais casser l’app. Aucune exception ne remonte — valide l’ingestion depuis le dashboard.Takt::strict()renvoie une instance qui lève sur non-202: réserve-la aux tests.
La façade résout le service Takt du conteneur, lié par requête. L’IP et l’User-Agent proviennent de la requête courante via $request->ip() et $request->userAgent().
App\Http\Middleware\TrustProxies en Laravel 10, trustProxies() dans bootstrap/app.php en Laravel 11 / 12) : sans cela, Takt reçoit l'IP du proxy et toute l'audience S2S est attribuée à une poignée d'adresses d'infrastructure. Hors requête HTTP — job en file, commande Artisan, webhook — il n'y a pas de visiteur à forwarder : passe l'IP et l'User-Agent réels toi-même avec withVisitor().