Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Umami Laravel Package

still-code/laravel-umami

Laravel Umami is a lightweight integration for the privacy-friendly Umami analytics platform. Easily add analytics to your Laravel application, track page views and custom events with Blade directives, middleware, and simple configuration—no cookies or complex setup required.

View on GitHub
Deep Wiki
Context7

Getting Started

Requires: Laravel 10/11/12, PHP 8.1+. Version 5.0.3 is the first line with explicit Laravel 12 support (added in PR #39); the rest of the release is Dependabot housekeeping, so there are no breaking changes to plan around.

Minimal setup (about 5 minutes):

composer require still-code/laravel-umami
php artisan vendor:publish --tag="umami-config"

Set the two values you actually need in .env:

UMAMI_ENABLED=true
UMAMI_HOST=https://analytics.example.com
UMAMI_WEBSITE_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx

Drop the tracking snippet into your layout's <head> (typically resources/views/layouts/app.blade.php):

<x-umami::script />

Where to look first: the published config/umami.php. It is the whole package in one file — enable/disable switch, self-hosted host, website ID. If something is not behaving, that file is the first and usually last place you need to check. After config, the README's Blade snippet section is the second.

First use case: pageview tracking on a marketing site or app. Add the component to the layout, deploy, and confirm in the Umami dashboard that pageviews appear within a minute or two. Do this in staging first with a separate Umami website entry so you don't pollute production stats.

Implementation Patterns

Layout-level pageview tracking. The default and by far the most common pattern: one component in the base layout, and every full page load is tracked automatically. Do not sprinkle the component across partials or individual views — that leads to duplicate beacons on pages that include multiple layouts.

Consent gating. Because the component is just a Blade render, wrap it in your consent check:

@if (Cookie::get('analytics_consent') === 'granted')
    <x-umami::script />
@endif

This keeps the GDPR/ePrivacy story simple and auditable: no script tag in the HTML at all until consent is recorded. The trade-off is that consent must be resolved server-side; if you use a client-side consent banner, gate on the client instead (render the component but have your banner block it) or accept a reload after consent.

Server-side events for the things the browser misses. Pageviews are only half the story. For signups, form submissions, checkout completions, and other actions worth measuring, fire an event from the controller or an event listener:

use StillCode\LaravelUmami\Facades\Umami;

Umami::track('signup', ['plan' => $user->plan]);

Do this in a queued listener when the request path is latency-sensitive — the package makes an outbound HTTP call to your Umami instance, and you do not want that inline on a checkout response.

SPAs, Livewire, and Inertia. The script is injected once per full document load. Client-side route changes will not produce additional pageviews unless you call the Umami browser API yourself (umami.track(...)) from your router's navigation hook. For Livewire, wire it into Livewire.hook('morph.updated') or a navigate callback. Treat the Blade component as "load the library" and everything else as manual instrumentation.

Per-tenant or multi-site setups. If you host several brands from one codebase, override the config at runtime before the layout renders — for example in a tenancy middleware:

config([
    'umami.website_id' => $tenant->umami_website_id,
    'umami.host'       => $tenant->umami_host,
]);

Because the component reads config at render time, this works without touching the package. Keep the shared .env values as a fallback so local development does not blow up when no tenant is bound.

Environment separation. Keep UMAMI_ENABLED=false in .env.testing and .env.local. There is no reason for a test suite or a developer machine to hit your analytics host, and it removes a whole class of flaky outbound-HTTP failures from CI. If you need to assert tracking in a feature test, bind a fake or use Http::fake([...]) and assert against the recorded request rather than the real endpoint.

Gotchas and Tips

  • UMAMI_WEBSITE_ID is the website UUID, not the domain. This is the single most common misconfiguration. Copy the ID from Umami's Settings → Websites panel. A wrong ID means successful HTTP 200s with no data.
  • No trailing slash on UMAMI_HOST. Use https://analytics.example.com, not https://analytics.example.com/. A double slash in the script URL resolves on most servers but breaks on some reverse proxies and CDNs.
  • Config caching is the classic "it works locally" trap. After changing .env values run php artisan config:cache on deploy and php artisan config:clear locally. If the script disappears in staging but not on your machine, this is almost always why.
  • Ad blockers and privacy extensions block analytics scripts broadly, including self-hosted Umami. Expect 10–20% undercounting in consumer-facing audiences. This is not a package bug and there is no fix worth pursuing — server-side events (fired from your backend, not the browser) are the workaround for critical conversion events.
  • Content Security Policy. If you ship a CSP (Spatie's laravel-csp or a hand-rolled header), you need the Umami host in both script-src and connect-src. Forgetting connect-src produces a silent failure: the script loads, the beacon is blocked, and nothing appears in the dashboard.
  • Disabling in one place only. UMAMI_ENABLED=false stops the Blade component, but if you call the facade directly in a controller it will still make the HTTP call unless the package honours the flag there too — verify this for your version, and consider wrapping your own calls in if (config('umami.enabled')).
  • Server-side tracking failures should never break the user's request. Wrap facade calls in a try/catch or push them onto a queue with retry. An analytics outage taking down your signup flow is an avoidable incident.
  • Extension points are deliberately thin. There is no event system, no custom driver, no middleware pipeline. If you need retries, batching, or a queue, build a small wrapper service around the facade rather than expecting the package to grow those features — it is intentionally a small binding to Umami, not an analytics abstraction layer.
  • Upgrading to 5.0.3 is low-risk: it adds Laravel 12 compatibility and bumps CI actions only. The main thing to confirm is that your composer.json constraint allows it and that you are not pinning an older transitive dependency. Run the suite after upgrading, but do not expect behaviour changes.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
diephp/sequences
users-au/socialite-provider
twidpay/twid-logger
mrnewport/laravel-plaid
mrnewport/laravel-repo
mrnewport/laravel-docsign
mrnewport/laravel-stow
mrnewport/laravel-flow
mrnewport/laravel-priceable
mrnewport/laravel-nestedterms
fredmeng/laravel-apidoc-generator
itstructure/laravel-multilingual-tools
pdustdar/elasticsearch
markupai/php-sdk
rlacerda83/lumem-microservice-shipment
uni-method/symfony-lib
tacticmedia/scim-server-bundle
neika-ai/symfony-bundle
mattleads/agent-publishing-bundle
glavweb/framework-bundle