quiet-metrics/symfony-metrics

Bundle Symfony du SDK Quiet Metrics (La Boîte à Code) : pageviews serveur automatiques via kernel.terminate et configuration sémantique.

Maintainers

Package info

github.com/Quiet-Metrics/symfony-metrics

Homepage

Type:symfony-bundle

pkg:composer/quiet-metrics/symfony-metrics

Transparency log

Statistics

Installs: 2

Dependents: 0

Suggesters: 0

Stars: 0

Open Issues: 1

v0.3.0 2026-08-28 20:08 UTC

This package is auto-updated.

Last update: 2026-08-28 20:53:03 UTC


README

Quiet Metrics: Symfony bundle

🇫🇷 Version française

Symfony bundle (6.4 and 7.x) for the Quiet Metrics PHP SDK: audience measurement with no identification or tracking cookies, 100% server-side, unblockable by ad blockers. Page views are sent automatically on kernel.terminate, without JavaScript and without ever slowing the site down.

Installation

composer require quiet-metrics/symfony-metrics

With Symfony Flex, the bundle is registered automatically (symfony-bundle type). Without Flex, add it to config/bundles.php:

// config/bundles.php
return [
    // ...
    QuietMetrics\Symfony\QuietMetricsBundle::class => ['all' => true],
];

Before the Packagist release

symfony-metrics is not on Packagist yet, and its repository is private. Declare it (access required); the core package it depends on comes from Packagist:

{
    "repositories": [
        { "type": "vcs", "url": "https://github.com/Quiet-Metrics/symfony-metrics" }
    ]
}
composer require quiet-metrics/symfony-metrics:^0.3

Configuration

The configuration alias is quiet_metrics.

# config/packages/quiet_metrics.yaml
quiet_metrics:
    public_key: '%env(QUIET_METRICS_PUBLIC_KEY)%'   # site public key (required)
    secret_key: '%env(QUIET_METRICS_SECRET_KEY)%'   # essential server-side: signs every hit (HMAC)

    # endpoint: 'https://quietmetrics.dev/api/v1/collect'  # default: core SDK's Quiet Metrics SaaS endpoint
    # trust_proxy_headers: true   # application behind a reverse proxy (X-Forwarded-For / X-Forwarded-Proto)
    # auto_pageview: false        # disables the automatic pageview (manual events only)
# .env.local
QUIET_METRICS_PUBLIC_KEY=qm_pub_xxx
QUIET_METRICS_SECRET_KEY=qm_sec_xxx

Why the secret key matters. It enables signed mode, the only case where the visitor IP and User-Agent carried by your server are trusted. Without it, every hit is attributed to your server's IP: all your visitors would count as one.

Usage

Pageviews for successful HTML responses are sent on their own: nothing to do.

For custom events, inject the core SDK client (QuietMetrics\Client, wired by the bundle):

use QuietMetrics\Client;
use Symfony\Component\HttpFoundation\Response;

final class CheckoutController
{
    public function __construct(private readonly Client $quietMetrics) {}

    public function confirm(): Response
    {
        $this->quietMetrics->event('purchase', ['amount' => 49, 'plan' => 'pro']);
        // ...
    }
}

With auto_pageview: false, you keep control over page views:

// Context (URL, referrer, IP, User-Agent, language) inferred from the
// current request, overridable key by key:
$this->quietMetrics->pageview();
$this->quietMetrics->pageview(['url' => 'https://mysite.com/thank-you']);

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 OptOutListener takes care of it on the current request. It is registered whatever auto_pageview is set to: a refusal does not depend on a measurement option. Nothing to wire.

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. A dedicated VisitListener writes it on kernel.response, on the very requests whose pageview TrackRequestListener sends on kernel.terminate. Unlike OptOutListener, it is registered only when auto_pageview is on: a refusal does not depend on a measurement option, but a measurement cookie does.

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

  • Sending happens on kernel.terminate: the response has already reached the visitor, zero perceived latency. The core SDK client is itself non-blocking (write-and-forget socket, short-timeout cURL fallback, silent failures): analytics never breaks the host site.
  • The listener only counts real pages: GET requests, 2xx responses, HTML Content-Type, excluding AJAX requests.
  • The context is read from the Request object (never from superglobals): correct under RoadRunner and FrankenPHP, in tests, and aligned with the host application's trusted proxies.
  • With secret_key, every send is HMAC-SHA256 signed (X-QM-Timestamp and X-QM-Signature headers); the visitor IP and User-Agent carried by the SDK are then trusted on the collection side.

License

MIT. A La Boîte à Code product for Quiet Metrics.