Consent and redaction
The default posture is the private one: no cookies, Do-Not-Track and Sec-GPC
honored, URLs scrubbed before they leave your application, and bots excluded. You opt
into more identification, never out of it.
'privacy' => [
'honor_dnt' => true, // skip on DNT:1 / Sec-GPC:1
'cookieless' => true, // JS: disableCookies before trackPageView
'consent' => 'none', // none|cookie|full
],
Cookieless by default
privacy.cookieless pushes disableCookies before the page view, so the client-side
tracker sets none. Server-side identification is cookieless by construction — see
how a visitor is identified.
With no cookies and a rotating, salted identifier, there is nothing stored on the visitor's device and no cross-site identifier — which is what makes a consent banner unnecessary in the default configuration. Whether that holds for your jurisdiction and your configuration is a question for your own legal advice, not for this page; what the package guarantees is the technical posture.
Do-Not-Track
honor_dnt covers both signals — the legacy DNT: 1 header and Sec-GPC: 1, the
Global Privacy Control. It is checked server-side, in the
tracking gate, before anything about identity is evaluated. The
client-side tracker is told about it too, via setDoNotTrack.
Honoring it server-side is the part that matters: a DNT header cannot be respected
by JavaScript that has already run.
Consent postures
'consent' => 'none', // none | cookie | full
| Value | The snippet emits | Use when |
|---|---|---|
none | No consent call | The cookieless default — nothing to consent to |
cookie | requireCookieConsent | You track with cookies and gate only the cookies on consent |
full | requireConsent | You gate all tracking on consent |
With cookie or full, Matomo holds hits back until your consent manager calls
setCookieConsentGiven or setConsentGiven. Wiring that call is your consent
manager's job — the package emits the requirement, not the grant.
Note that these are client-side postures. Server-side tracking is governed by the gate and by the opt-out cookie below.
A publishable privacy-policy partial
php artisan vendor:publish --tag=matomo-analytics-views
That publishes a small partial describing the cookieless Matomo setup, which you can include in your privacy policy and edit freely:
@include('matomo-analytics::privacy-policy')
@include('matomo-analytics::privacy-policy', ['heading' => 'Analytics'])
Read it before you publish it. It describes the package's default configuration, so if you changed the defaults — enabled cookies, stopped anonymizing — the text needs changing too.
URL redaction
On by default. Secrets and PII are stripped out of tracked URLs before they reach Matomo:
?token=abc123&page=2 -> ?token=REDACTED&page=2
'privacy' => [
'redact' => [
'enabled' => true,
'replacement' => 'REDACTED',
'query_params' => [
'token', 'api_key', 'apikey', 'api-key', 'access_token', 'auth',
'auth_token', 'password', 'passwd', 'pwd', 'secret', 'client_secret',
'signature', 'sig', '_token', 'session', 'session_id', 'sessionid',
],
'patterns' => [],
'keys' => ['url', 'urlref', 'link', 'download'],
],
],
Three things worth understanding about it.
The key survives, the value does not. A redacted parameter keeps its name and loses its value, so a report still tells you "a password-reset link was opened" without the token being in your analytics, your Matomo access logs, or a dashboard someone shares in a meeting. Parameter matching is case-insensitive.
patterns handles what a parameter list cannot. Any regular expression here is
applied to the URL. This is how you scrub an identifier that lives in a path segment
rather than a query parameter:
'patterns' => [
'/\b[\w.+-]+@[\w-]+\.[\w.-]+\b/', // email addresses anywhere in the URL
'#/invoices/\d+#', // numeric invoice ids in the path
],
keys decides which payload fields are scrubbed. By default the page URL, the
referrer, and link and download targets. The referrer is included, and that is worth
knowing in both directions: the parameters of an incoming URL are scrubbed, while its
host is left intact — which is what keeps referrer reports, and the
AI Assistants acquisition channel, working.
Redaction is not a substitute for not putting secrets in URLs. It is the safety net for the ones that are already there — a password-reset link, a signed download URL, an OAuth callback.
Server-side opt-out
Matomo's own opt-out widget sets a cookie on the Matomo domain, which your server-side tracker cannot see. So an application that tracks server-side needs a first-party cookie, and the gate honors one:
use MatomoAnalytics\Privacy\OptOut;
return back()->withCookie(OptOut::enable()); // stop tracking this browser
return back()->withCookie(OptOut::disable()); // opt back in
'opt_out' => [
'respect' => true,
'cookie' => 'matomo_opt_out',
],
enable() returns a permanent cookie; disable() returns the forget-cookie that
clears it. Attach either to a response from your own opt-out control.
Set it server-side. These are Laravel cookies, so they pass through the
EncryptCookiesmiddleware. A plaintext cookie of the same name written by client-side JavaScript is dropped as invalid and will not opt anyone out. If you want a JavaScript control, have it hit a small endpoint that returnsOptOut::enable().
Pair it with @matomoOptOut if you
track on both sides: the iframe covers the client-side tracker, the cookie covers the
server.