Configuration reference
Every key, its environment variable and the value shipped in the package. This page — not
your published config/matomo-analytics.php — is the authoritative list, because a key
your file does not contain still has its default. See
configuration for why.
A key with an environment variable can be set either way. A key without one is a structure, and is edited in the file.
Connection and master switch
| Key | Env | Default | Meaning |
|---|---|---|---|
enabled | MATOMO_ENABLED | false | Master switch. Installing the package tracks nobody until you set this to true. |
host | MATOMO_HOST | — | Base URL of your Matomo. Everything else is derived from it. |
site_id | MATOMO_SITE_ID | — | The Matomo site id. |
site_id_resolver | — | null | fn(): ?int — an invokable class-string or closure that may name the site for the hit being built. null, or anything that is not a positive int, falls back to site_id. For multi-tenant applications; see below. |
require_tls | MATOMO_REQUIRE_TLS | false | Refuse to track over a plaintext host. With it on, an http:// host counts as unconfigured and nothing is tracked — the same no-op a missing host takes, never an exception. Off by default because Matomo on a private network without TLS is a legitimate deployment. What it protects: token_auth travels in the request body on every server-side hit. |
token | MATOMO_TOKEN | — | token_auth, server-side only. Needed for the real client IP, exact hit time, and the read side. |
tracker_path | MATOMO_TRACKER_PATH | matomo.php | Path to the tracking endpoint, relative to host. |
js_path | MATOMO_JS_PATH | matomo.js | Path to the JavaScript tracker. |
timeout | MATOMO_TIMEOUT | 5 | Request timeout in seconds for tracking calls. |
Tracking is a no-op while host or site_id is missing. See
installation.
One site id per request
site_id_resolver is the seam for an application that tracks each tenant into its own Matomo
site. It is called while the hit's payload is built, so it decides per hit rather than per
process:
'site_id_resolver' => fn (): ?int => Tenant::current()?->matomo_site_id,
It takes no arguments on purpose — the tenant is a property of your own request context, which the callback already has.
A buffered batch may therefore carry hits for several sites, and that is fine. Each buffered
hit holds its own idsite, and Matomo's Bulk endpoint accepts a mixed batch. This is why the
seam is a resolver rather than a per-request connection: rebuilding the connection would not fix
the buffer, and this does.
Anything other than a positive int falls back to site_id — null, a string, a negative,
and a resolver that throws. Tracking never breaks the caller, and that has to include an
extension point the package cannot see.
These seven values are read once and then held for the life of the process. In an ordinary
request that is invisible, because the process ends with the response. In a long-lived one — a
queue:work or matomo:work worker, or Octane — the values the process resolved first are the
values it keeps, and changing the configuration underneath it does nothing until it restarts.
It matters in one shape: an application that repoints this package per request or per tenant, so that each tenant tracks into its own Matomo site. There the worker sends every tenant's hits to whichever site it saw first. The way to do it is a tracking gate plus custom dimensions, which read live configuration on every hit — not by swapping the connection under a running worker, which does not work for the reason the Octane guide sets out.
Transmission
| Key | Env | Default | Meaning |
|---|---|---|---|
mode | MATOMO_MODE | queue | queue, sync or batch. |
schedule.run_in_background | MATOMO_SCHEDULE_BACKGROUND | true | Runs both scheduled commands off your scheduler, so a slow Matomo never delays another task. Costs you the failure report: Laravel raises a scheduled command's non-zero exit only in the foreground, so a background one reaches neither ScheduledTaskFailed nor your exception handler. Set it to false when that report matters more than the wait. |
queue.connection | MATOMO_QUEUE_CONNECTION | null | Queue connection; null uses the default. |
queue.queue | MATOMO_QUEUE | matomo | Queue name. Your worker must serve it. |
queue.tries | — | 5 | Delivery attempts before the batch is dead-lettered. |
queue.backoff | — | [30, 120, 300, 900] | Seconds between retries, escalating. |
queue.retry_until_minutes | — | 1440 | Outer bound on retrying. queue.tries normally ends the loop first. |
See transmission modes.
Batch buffer
| Key | Env | Default | Meaning |
|---|---|---|---|
batch.driver | MATOMO_BATCH_DRIVER | database | Buffer store: database, redis, file or array. |
batch.size | MATOMO_BATCH_SIZE | 200 | Hits per Bulk request, and therefore how many requests a backlog costs — 2000 hits against a Matomo answering in 20ms take 1021ms at 50, 276ms at 200 and 125ms at 500. It is also the memory knob: a claimed batch is held at roughly 2.3 KB per hit. |
batch.flush_interval | MATOMO_BATCH_INTERVAL | 60 | Seconds between passes of the matomo:work daemon. |
batch.max_per_flush | — | 2000 | Cap on hits moved by a single flush pass. |
batch.stale_after_minutes | — | 15 | Reclaim a claimed-but-unacknowledged batch after this long. Floored at one minute: at zero every claim expires the moment it is made, and at-least-once delivery becomes guaranteed double delivery. |
batch.redis_connection | MATOMO_BATCH_REDIS | default | Redis connection for the redis driver. |
batch.table | — | matomo_tracking_buffer | Table for the database driver. |
batch.path | MATOMO_BATCH_PATH | null | Spool directory for the file driver; unset means storage/app/matomo-analytics. |
batch.max_attempts | MATOMO_BATCH_MAX_ATTEMPTS | 25 | Consecutive failed flushes before a stuck batch is dead-lettered. |
batch.dead_letter.enabled | — | true | Move undeliverable batches to the dead-letter store. |
batch.dead_letter.retention_days | MATOMO_DEAD_LETTER_RETENTION_DAYS | 30 | Days a dead letter is kept before the daily prune deletes it. 0 keeps them forever. |
batch.dead_letter.table | — | matomo_dead_letters | Dead-letter table. |
The max_attempts counter lives in the cache and therefore needs a persistent cache
store — see reliability.
Resilience and alerting
| Key | Env | Default | Meaning |
|---|---|---|---|
resilience.never_throw | — | true | Tracking errors never bubble into the application. |
resilience.connect_timeout | — | 2 | Connection timeout in seconds. |
resilience.reporting.report_after_attempts | — | 3 | Report only after this many failures. |
resilience.reporting.channel | MATOMO_REPORT_CHANNEL | report | report (exception handler plus log), log, or silent. |
resilience.reporting.level | — | warning | Log level for a reported failure. |
resilience.reporting.transient_level | — | null | Log level for each retry; null logs none. |
resilience.reporting.throttle_minutes | — | 15 | Throttle window per error signature. 0 disables throttling. |
Reporting (read side)
| Key | Env | Default | Meaning |
|---|---|---|---|
reporting.path | MATOMO_REPORTING_PATH | index.php | Path to the Reporting API. |
reporting.timeout | MATOMO_REPORTING_TIMEOUT | 10 | Request timeout in seconds for report calls. |
reporting.default_period | MATOMO_REPORTING_PERIOD | day | Period used when a call omits one. |
reporting.default_date | MATOMO_REPORTING_DATE | today | Date used when a call omits one. |
reporting.segments | — | [] | Named-segment registry: key to Matomo segment definition. |
reporting.cache.enabled | — | true | Cache report responses. |
reporting.cache.store | MATOMO_REPORTING_CACHE_STORE | null | Cache store; null uses the default. |
reporting.cache.prefix | — | matomo-analytics:report | Cache key prefix. |
reporting.cache.ttl.live | — | 60 | Seconds for realtime counters. |
reporting.cache.ttl.today | — | 300 | Seconds for periods covering today. |
reporting.cache.ttl.recent | — | 900 | Seconds for yesterday and recent ranges. |
reporting.cache.ttl.historical | — | 3600 | Seconds for fully archived past periods. |
See reporting and queries and segments.
Visitor identity
| Key | Env | Default | Meaning |
|---|---|---|---|
visitor.rotate | — | daily | Cookieless salt rotation: daily, weekly or never. |
visitor.user_id | — | null | auth attaches the authenticated user id as the Matomo User ID; null attaches none. |
anonymize_ip | — | true | Truncate the client IP before sending it. |
ip_header | MATOMO_IP_HEADER | null | Forwarding header carrying the real client IP; the first address in the chain is used. Trusted without verification — read the warning. |
Tracking gate
| Key | Env | Default | Meaning |
|---|---|---|---|
tracking.environments | — | null | Restrict tracking to these environments; null or [] means all. |
tracking.track_authenticated | — | true | Track logged-in users. |
tracking.except_abilities | — | [] | Skip users who pass any of these Gate abilities. |
tracking.except_ips | — | [] | Skip these client IPs or CIDR ranges. |
tracking.except_routes | — | ['horizon*', 'telescope*', 'nova*', 'up', 'health*', 'livewire/*'] | Skip these request-path patterns. |
tracking.gate | — | null | Invokable class-string or closure for full control. |
See the tracking gate.
Privacy
| Key | Env | Default | Meaning |
|---|---|---|---|
privacy.honor_dnt | — | true | Skip tracking on DNT: 1 or Sec-GPC: 1. |
privacy.cookieless | — | true | Push disableCookies in the client snippet. |
privacy.consent | — | none | Client consent posture: none, cookie or full. |
privacy.opt_out.respect | — | true | Honor the first-party opt-out cookie. |
privacy.opt_out.cookie | — | matomo_opt_out | Name of that cookie. |
privacy.redact.enabled | — | true | Strip secrets and PII from tracked URLs. |
privacy.redact.replacement | — | REDACTED | Value a redacted parameter is replaced with. |
privacy.redact.query_params | — | A list of token, password, secret, signature and session parameter names | Parameters whose value is replaced; the key is kept. Matched case-insensitively. |
privacy.redact.patterns | — | [] | Regular expressions applied to the URL. |
privacy.redact.keys | — | ['url', 'urlref', 'link', 'download'] | Which payload fields are redacted. |
See consent and redaction for the full shipped parameter list and how to extend it.
Bots
| Key | Env | Default | Meaning |
|---|---|---|---|
bots.track | — | false | Record bots and crawlers instead of excluding them. |
bots.detect_ai_crawlers | — | true | Use the maintained AI/LLM crawler token list. |
bots.detect_generic | — | true | Use the generic crawler signals. |
bots.allow | — | [] | User-Agent tokens always treated as human. Overrides every other layer. |
bots.deny | — | [] | User-Agent tokens always treated as bots. |
bots.detector | — | null | Extra invokable class-string or closure, consulted last. |
See bots and AI crawlers.
AI chatbot telemetry
| Key | Env | Default | Meaning |
|---|---|---|---|
ai_chatbots.track | — | false | Master switch for AI-chatbot telemetry. |
ai_chatbots.auto | — | false | Auto-register the matomo.chatbots middleware on the web group. |
ai_chatbots.rec_mode | — | 1 | 1 records bots only (Matomo discards non-bots); 2 lets Matomo decide. |
ai_chatbots.source | — | Laravel | Label identifying this collector. |
ai_chatbots.user_agents | — | null | Recognized fetchers; null uses the built-in on-demand list. |
See AI assistants.
Page-view middleware
| Key | Env | Default | Meaning |
|---|---|---|---|
middleware.auto | — | false | Auto-register the page-view middleware on the web group. |
middleware.only_get | — | true | Track GET requests only. |
middleware.only_successful | — | true | Track delivered pages only: 2xx and 304. |
middleware.skip_livewire | — | true | Skip Livewire update requests. |
middleware.strip_query | — | false | Drop the query string from the tracked URL. |
middleware.performance | — | false | Stamp the server generation time onto the page view. |
See server-side tracking.
Client-side snippet
| Key | Env | Default | Meaning |
|---|---|---|---|
js.enabled | MATOMO_JS_ENABLED | true | Render the client snippet at all. Governs both @matomoScript and the <noscript> pixel. |
js.host | MATOMO_JS_HOST | null | Separate asset host for the tracker script; tracking stays on host. |
js.tag_manager | — | null | Full Tag Manager container URL. When set, the container renders instead of the tracker. |
js.enable_link_tracking | — | true | Track outbound links and downloads. |
js.performance | — | true | false pushes disablePerformanceTracking. |
js.custom_dimensions | — | [] | Map of dimension id to value, set on every page view. |
js.content_tracking | — | false | false, 'all' or 'visible'. |
js.heartbeat | — | 15 | Heartbeat timer in seconds; 0 disables it. |
js.noscript | — | true | Render a <noscript> tracking pixel. |
js.dns_prefetch | — | true | Emit a dns-prefetch hint for the Matomo origin. |
See client-side tracking.
SPA
| Key | Env | Default | Meaning |
|---|---|---|---|
spa.enabled | MATOMO_SPA | false | Record a virtual page view on each soft navigation. |
spa.adapters | — | ['livewire', 'inertia'] | Which adapters to attach: livewire, inertia, generic. |
spa.performance | — | true | Forward an app-provided timing object per virtual page view. |
Web Vitals
| Key | Env | Default | Meaning |
|---|---|---|---|
web_vitals.enabled | — | false | Enable the ingest route and the directive. |
web_vitals.path | — | matomo-analytics/web-vitals | Route path for the beacon endpoint. |
web_vitals.category | — | Web Vitals | Matomo event category the samples are recorded under. |
web_vitals.metrics | — | ['LCP', 'CLS', 'INP', 'FCP', 'TTFB'] | Accepted metrics. Also the allowlist the route validates against. |
web_vitals.throttle | — | 60,1 | Route throttle, "requests,minutes". null disables it; an absent key falls back to the shipped value rather than to no limit. |
web_vitals.middleware | — | [] | Extra middleware for the ingest route. Empty by default, because the browser beacons it with sendBeacon() and that carries no CSRF token — which also means no session is started there, so tracking.track_authenticated and tracking.except_abilities see a guest on this path. Add ['web'] if you need them to apply, and exempt this one route from CSRF on your side. |
web_vitals.library | — | null | Script URL for the web-vitals library; null means your app provides it. |
See Web Vitals.
Annotations
| Key | Env | Default | Meaning |
|---|---|---|---|
annotations.release | MATOMO_ANNOTATE_RELEASES | false | Enable matomo:annotate --release. |
annotations.starred | — | false | Star release annotations. |
annotations.release_prefix | — | Deployed | Release note is the prefix followed by the version. |
See release annotations.
Events
| Key | Env | Default | Meaning |
|---|---|---|---|
events | — | true | Fire the package's Laravel events. |
See events.
Keys your published config may still carry
These keys are gone from the shipped config file. If you published the config in an earlier version, your copy still has them — and they do nothing. Deleting the lines changes nothing:
resilience.durability(and itsMATOMO_DURABILITYvariable) — never read by any code path; removed from the shipped config in 0.19.0bots.record_ai_dimension— removed earlier
They are listed here rather than quietly dropped, because a reference that omits a key
you can see in your own file is worse than one that explains it. Publishing the config
again with --force gives you the current set, but overwrites your edits.
Every environment variable
MATOMO_ENABLED=true
MATOMO_HOST=
MATOMO_SITE_ID=
MATOMO_TOKEN=
MATOMO_TRACKER_PATH=matomo.php
MATOMO_JS_PATH=matomo.js
MATOMO_TIMEOUT=5
MATOMO_MODE=queue
MATOMO_REQUIRE_TLS=false
MATOMO_QUEUE_CONNECTION=
MATOMO_QUEUE=matomo
MATOMO_BATCH_DRIVER=database
MATOMO_BATCH_SIZE=200
MATOMO_BATCH_INTERVAL=60
MATOMO_BATCH_REDIS=default
MATOMO_BATCH_PATH=
MATOMO_BATCH_MAX_ATTEMPTS=25
MATOMO_DEAD_LETTER_RETENTION_DAYS=30
MATOMO_SCHEDULE_BACKGROUND=true
MATOMO_REPORT_CHANNEL=report
MATOMO_REPORTING_PATH=index.php
MATOMO_REPORTING_TIMEOUT=10
MATOMO_REPORTING_PERIOD=day
MATOMO_REPORTING_DATE=today
MATOMO_REPORTING_CACHE_STORE=
MATOMO_IP_HEADER=
MATOMO_JS_ENABLED=true
MATOMO_JS_HOST=
MATOMO_SPA=false
MATOMO_ANNOTATE_RELEASES=false
Only MATOMO_HOST and MATOMO_SITE_ID have no usable default — everything else can
be left unset. MATOMO_ENABLED has a default, but it is false, so it is the one you
must set to start tracking.
MATOMO_URL is not read. It was accepted as an alias until 0.16.0, which meant an
application configuring its own, separate Matomo integration through that key was
activating this package as well.