quiet-metrics / laravel-metrics
Pont Laravel du SDK Quiet Metrics (quiet-metrics/php-metrics) : pageviews serveur automatiques (middleware), facade et configuration.
Requires
- php: >=8.1
- illuminate/support: ^10.0 || ^11.0 || ^12.0 || ^13.0
- quiet-metrics/php-metrics: ^0.3
Requires (Dev)
- orchestra/testbench: ^10.0 || ^11.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Laravel bridge for Quiet Metrics (La Boîte à Code): automatic server-side pageviews via middleware, a facade for events, publishable configuration. Tracking is 100% server-side and JS-free, with no identification or tracking cookies, invisible to ad blockers. Built on the core PHP package (quiet-metrics/php-metrics).
Compatible with Laravel 10 to 13 (illuminate/support ^10 || ^11 || ^12 || ^13), PHP >= 8.1.
Installation
composer require quiet-metrics/laravel-metrics
The service provider and the facade alias are registered automatically (package discovery).
Configuration
Publish the configuration file (optional; environment variables are enough in most cases):
php artisan vendor:publish --tag=quiet-metrics-config
Environment variables:
# Site keys, from the "Installation" panel of the Quiet Metrics dashboard. QUIET_METRICS_PUBLIC_KEY=qm_pub_xxxx # ESSENTIAL for server-side sending: enables signed mode (HMAC), the only # case where the visitor IP/UA carried by your server are trusted. Without # it, every hit would carry your server's IP: a single visitor counted. QUIET_METRICS_SECRET_KEY=qm_sec_xxxx # Optional: QUIET_METRICS_ENDPOINT=https://quietmetrics.dev/api/v1/collect QUIET_METRICS_TRUST_PROXY=false # true if the app sits behind a reverse proxy / CDN
Usage
Middleware: automatic pageviews
The middleware is registered under the quiet-metrics alias. Per route or per group:
Route::middleware('quiet-metrics')->group(function () { // ... your web routes });
Globally on the whole web group, Laravel 11+ (bootstrap/app.php):
use QuietMetrics\Laravel\Middleware\TrackPageview; ->withMiddleware(function (Middleware $middleware) { $middleware->web(append: TrackPageview::class); })
Laravel 10 (app/Http/Kernel.php):
protected $middlewareGroups = [ 'web' => [ // ... \QuietMetrics\Laravel\Middleware\TrackPageview::class, ], ];
The middleware only counts successful HTML GETs: non-GET requests, non-2xx responses and AJAX/JSON requests are ignored.
Facade: custom events
use QuietMetrics\Laravel\Facades\QuietMetrics; // Event with properties (scalar values, 30 keys max). QuietMetrics::event('signup', ['plan' => 'pro']); // Manual pageview, overridable context (useful outside HTTP requests: // jobs, artisan commands; `url` is then required). QuietMetrics::pageview(['url' => 'https://mysite.com/pricing']);
You can also inject QuietMetrics\Client directly (registered as a singleton) instead of going through the facade.
Opting out of measurement
A visitor can ask to stop being counted, with no account and without writing to anyone: they visit a page of your site with ?qm_ignore=1, and ?qm_ignore=0 puts them back into measurement.
https://mysite.com/?qm_ignore=1 stop being counted
https://mysite.com/?qm_ignore=0 be counted again
The marker is a first-party cookie of your own site, named qm_ignore with the value 1 (path=/, samesite=lax, secure over https, five years). A dedicated HandleOptOut middleware takes care of it, registered globally by the service provider: the marker can therefore be set from any URL, not only from the routes you track. Nothing to wire. To handle it yourself, set quiet-metrics.register_opt_out_middleware to false; the quiet-metrics-optout alias stays available.
It holds no identifier (its value is the same for everyone), it is never transmitted to Quiet Metrics, and it exists only to stop measurement: it is an opt-out marker, not a tracker. The JS tracker additionally writes the same value to localStorage, but a server-side SDK only ever reads the cookie: one visit therefore covers both tracking modes.
Visit continuity
When the visitor fingerprint changes mid-visit (4G, then wifi), the same person would otherwise be counted as two unique visitors on the same day. A second first-party cookie of your own site closes that gap: qm_visit, value 1 (path=/, samesite=lax, secure over https), on a sliding ten-minute window pushed back by every measured hit. Each hit reports whether it was already there as the c key of the payload.
Its value is a constant, the same for everyone, so it identifies nobody: it only says that a visit is already under way in this browser. It is never written to someone who has set the opt-out marker, and never written when nothing is measured: the quiet-metrics middleware writes it during the response phase, on the very requests whose pageview it sends in terminate(). Like the opt-out marker, it is exempt from Laravel cookie encryption, since the JS tracker of the same site has to read the same window.
Note for cached sites: a measured response now carries a Set-Cookie header, which some reverse proxies and CDNs treat as a reason not to store the response.
How it works
The provider builds a Client singleton (core package) from the quiet-metrics config. The middleware sends the pageview in terminate(), after the response has been sent to the visitor: no impact on perceived latency. The context (URL, referrer, IP, User-Agent, language) comes from the Request object, never from superglobals: correct under Octane and persistent workers, in tests, and aligned with the host application's trusted proxies. On the core side, sending is non-blocking (fire-and-forget socket, short cURL fallback) and every failure is silent: analytics never breaks the site.
Tests
composer update && composer test
Orchestra Testbench suite against the core package's HTTP capture server: signed middleware pageview (HMAC verified), exclusions (JSON, POST, errors), event facade, configured singleton.
License
MIT. A La Boîte à Code product for Quiet Metrics.
