Configuration
Configuration lives in one file, config/matomo-analytics.php, published by
matomo:install. This page explains how that file behaves and what each block is
for. For the exhaustive key-by-key table, see the
configuration reference.
You do not have to publish it
The package merges its own configuration underneath yours, and every value is read through a small typed accessor that carries an explicit default. Two consequences worth knowing:
- No published file is needed. Set
MATOMO_HOSTandMATOMO_SITE_IDand the package works on its shipped defaults. - A key missing from your published file does not become
null. It falls back to the default the code reads it with, which is the value shipped in the package's own config file.
That second point is what makes an upgrade safe: a release that adds a new setting does not require you to re-publish the config file before your application boots again.
What the merge does and does not do
Since 0.19.0 the merge recurses into nested sections. A block you published is
no longer a ceiling: a key you never mentioned arrives with its shipped default,
while every value you did set still wins. Before that release the merge was
Laravel's flat one, so a published block replaced the shipped block whole and a
subkey added by a later version was simply absent — privacy.redact.query_params
answering [] is URL redaction quietly doing nothing.
Lists are deliberately not merged. A map is a namespace and gets merged key by key; a list is a value and is taken exactly as you wrote it, including when you emptied it. That is the whole point: merging lists by index would hand back entries you deleted on purpose, and for a privacy or bot list that means switching a setting back on behind your back.
One situation is still outside all of this, and it is worth stating plainly:
php artisan config:cachefreezes the resolved configuration, and the framework skips merging for a cached config by design. Rebuilding the cache (php artisan config:cache) after an upgrade re-runs the merge and picks up everything added since — that rebuild is the fix, not re-publishing the file. Until then the only values that exist are the ones frozen in the cache, so the published file is not a complete picture of the effective configuration. The configuration reference is.
Environment variables or the file?
A setting with an environment variable can be set either way. A setting without one is a structure — a list, a map, a class-string — and belongs in the file.
Keep in .env: the connection (MATOMO_HOST, MATOMO_SITE_ID, MATOMO_TOKEN),
the transmission mode (MATOMO_MODE) and its driver, and the per-environment
switches (MATOMO_ENABLED, MATOMO_SPA).
Keep in the file: tracking.except_routes, tracking.except_ips,
tracking.except_abilities, privacy.redact.query_params,
privacy.redact.patterns, reporting.segments, js.custom_dimensions,
bots.allow, bots.deny and every callable extension point.
Callables must be class-strings if you cache config
Two settings accept your own logic: tracking.gate and bots.detector. Both take
either a closure or an invokable class-string. A closure in a config file cannot be
serialized, so config:cache fails on it — prefer an invokable class-string:
'tracking' => [
'gate' => \App\Analytics\OnlyPayingCustomers::class,
],
The package resolves a class-string through the container, so the class can take constructor dependencies.
The blocks
| Block | Covers | Page |
|---|---|---|
enabled, host, site_id, token, timeout | The master switch and the connection. | Installation |
mode, queue, batch | How hits leave your application. | Transmission modes |
resilience | Retry, alerting and throttling behavior. | Reliability |
reporting | The read-side client, its cache and named segments. | Reporting |
visitor, anonymize_ip, ip_header | How a visitor is identified and which IP is used. | Server-side tracking |
tracking | Who gets tracked at all. | The tracking gate |
privacy | Consent posture, opt-out cookie, URL redaction. | Consent and redaction |
bots | Bot and AI-crawler detection. | Bots and AI crawlers |
ai_chatbots | Server-side AI-assistant fetch telemetry. | AI assistants |
middleware | The automatic page-view middleware. | Server-side tracking |
js | The client-side snippet. | Client-side tracking |
spa | Virtual page views on soft navigation. | SPA and soft navigation |
web_vitals | The Core Web Vitals ingest route. | Web Vitals |
annotations | Deploy markers on the reports timeline. | Release annotations |
events | Whether the package fires Laravel events. | Events |
The master switch
'enabled' => env('MATOMO_ENABLED', false),
It ships off. Installing the package tracks nobody until you set
MATOMO_ENABLED=true — dormancy is the shipped state, not a side effect of an unset
host. Once it is on, tracking.environments is the finer instrument, because it keeps
the package live in production and inert elsewhere without a per-environment variable:
'tracking' => [
'environments' => ['production'], // null = every environment
],
Missing connection settings are a second belt: an environment without MATOMO_HOST
is inert whatever the switch says.