atm-code/laravel-umami
Laravel integration for Umami, the privacy-friendly, cookieless analytics platform. Add tracking snippets to your Blade views, query stats through a fluent API client, and keep visitor data self-hosted and GDPR-friendly without cookies.
still-code/laravel-umami is a thin integration layer that injects the Umami analytics tracker into your Laravel app and exposes a small API for server-side event tracking. Release 5.0.3 is maintenance-only — Dependabot bumps plus Laravel 12 support (PR #39) — so there are no migrations or breaking changes, but it unblocks installs on Laravel 12 projects.
composer require still-code/laravel-umami — on Laravel 12 you now need ^5.0.3; earlier 5.x tags will fail dependency resolution against laravel/framework ^12.0.php artisan vendor:publish --tag="umami-config" and open config/umami.php first — it is the source of truth for every option discussed below..env: UMAMI_ENABLED=true, UMAMI_WEBSITE_ID=<uuid-from-umami-dashboard>, and UMAMI_HOST=https://cloud.umami.is (or your self-hosted instance, e.g. https://analytics.example.com). There is no trailing slash on the host.@umami / <x-umami::script /> (check the config/README of the installed version for which is registered) just before </head>.UMAMI_ENABLED off in config/umami.php for local/testing so your dev traffic doesn't pollute dashboards; keep it driven by env so staging can be toggled independently.Layout-level injection. The intended path is one include in resources/views/layouts/app.blade.php. Everything else — script URL, data-website-id, data-domains, data-auto-track, data-do-not-track — flows from config, so you never edit Blade when the marketing team moves from cloud to self-hosted.
Env-driven multi-environment setup. Standard pattern:
UMAMI_ENABLED=true
UMAMI_WEBSITE_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
UMAMI_HOST=https://analytics.example.com
UMAMI_TRACK_LOCALHOST=false
Keep UMAMI_ENABLED=false in phpunit.xml and .env.testing. Because the flag is read at boot, config:cache in deploy pipelines will freeze the value — ensure the deploy env is set before artisan config:cache runs.
Server-side events (the reason to use the package over a raw <script>). When the config exposes the Umami /api/send endpoint, use it for conversions you can only trust server-side: registration completed, subscription upgraded, webhook-driven outcomes. Fire it from a listener or job, not the controller, and wrap in try/catch — analytics failures must never fail a checkout flow. Pass a stable, low-cardinality event name and keep data/payload keys consistent across releases so Umami's dashboard aggregations hold.
Multi-tenant / multi-site apps. If one Laravel instance serves several brands, publish the config but resolve website ID at runtime (per-tenant setting, or a config override in a middleware) rather than reading the env value directly in the Blade partial. Guard against a null ID — an injected script with an empty data-website-id silently collects nothing, which is worse than a visible error.
Livewire / Inertia / SPA navigation. Umami auto-tracks history changes, but only if your router actually pushes state. For Inertia this generally works; for Livewire wire:navigate verify pageviews land in the dashboard before assuming it's handled, and otherwise call umami.track() manually on navigation events.
CSP and consent. If you run a strict Content-Security-Policy, add UMAMI_HOST to script-src and connect-src. For GDPR-sensitive projects, gate rendering behind your consent manager (an Alpine/JS check or a Blade @if(cookie('consent'))) rather than enabling DNT handling and hoping.
https://example.com/stats) — the package appends /script.js, so a missing subpath yields a 404 that's only visible in DevTools.config:cache staleness. If the tracker stops rendering after a deploy, php artisan config:clear locally and check your CI deploy order before touching package code.<script> tag is present or absent per env with a simple assertSee('data-website-id'). Because the flag is config-driven, config(['umami.enabled' => true]) in the test is more reliable than env manipulation.How can I help you explore Laravel packages today?