Installation
Requirements
- PHP 8.4+
- Laravel 12 or 13
Any release of either major. The constraints floor at ^12.0 and ^13.0 rather
than at a later minor, so an application still on Laravel 12.0 installs the
package as readily as one on the newest 13.x.
The package requires focused illuminate/* components rather than
laravel/framework, so it adds no framework weight to an application that only
uses part of Laravel.
The curl extension is optional. With it, a flush sends every request over one reused connection; without it, hits go out over PHP streams, one connection each.
Install
composer require pushery/matomo-analytics-for-laravel
php artisan matomo:install
The service provider is discovered automatically — there is nothing to register.
matomo:install publishes config/matomo-analytics.php (every option is
documented inline in that file) and prints the environment variables to set.
Publishing the config file is optional. The package merges its own defaults, and
every setting is read with an explicit fallback, so the package is fully
functional with no published file at all. Publish it when you want to change
something that has no environment variable, such as tracking.except_routes or
reporting.segments.
Point it at your instance
MATOMO_HOST=https://your-instance.matomo.cloud # or https://analytics.example.com
MATOMO_SITE_ID=1
MATOMO_TOKEN= # optional; see below
# MATOMO_MODE=batch # switch single -> batch transmission
MATOMO_HOST is the base URL of your Matomo — everything else is derived from it:
the tracking endpoint, the Reporting API, the JavaScript tracker, the opt-out
script and the no-script pixel. Only MATOMO_HOST is read — MATOMO_URL is not an
alias for it.
Nothing is tracked until you set MATOMO_ENABLED=true. Installing the package
does not start tracking anyone: dormancy is the shipped state, not a side effect of
an unset host. Tracking additionally stays a no-op while MATOMO_HOST or
MATOMO_SITE_ID is missing, so the package remains inert in local development and
CI without any extra guard in your code, and no call site needs to know whether
analytics is configured.
Should you set a token?
MATOMO_TOKEN is a token_auth and is used server-side only. Matomo honors the
real visitor IP (cip), and the geolocation derived from it, only when a token is
sent. Without a token, hits are attributed to your application server's IP.
The hit time (cdt) is sent with every hit, and Matomo takes it without a token
while it is less than a day old. In the default queue mode and in batch mode a
hit usually reaches Matomo within minutes, so its time holds. A hit that waited
longer, after a long retry or a dead-letter replay, keeps its time only with a
token; without one it is recorded when it arrives. Set a token if you want
server-side hits attributed correctly. Use a dedicated tracking token rather than
your personal one.
A token is also what the read side needs: see Reporting (view access) and GDPR requests (admin access).
Verify
php artisan matomo:test
matomo:test sends one real hit to the configured tracking endpoint and reports
the HTTP status, so a misconfigured host, a firewall, a wrong site id or a token Matomo
does not accept surfaces immediately instead of as missing data a week later. It fails
with a clear message when the package is not configured at all.
To confirm the read side as well:
php artisan matomo:report VisitsSummary.get
Database tables
Two tables back batch mode: the hit buffer and
the dead-letter queue. The package registers its migrations automatically, so
php artisan migrate creates them.
The buffer table is only touched in batch mode. The dead-letter table is written from
queue mode too, so an application on the shipped default does use one of them. You can
still opt out of the automatic registration — call this from a service provider's
register() method — but switch batch.dead_letter.enabled off along with it, or the
delivery path is left with nowhere to park an exhausted batch:
use MatomoAnalytics\MatomoAnalyticsServiceProvider;
MatomoAnalyticsServiceProvider::ignoreMigrations();
To manage the migrations in your own application instead, publish them and edit the copies.
Publishing is only half of it — call ignoreMigrations() as well, or migrate breaks
permanently. vendor:publish rewrites the 0001_01_01_00000N_ prefix to the publish date,
and the migrator keys on the file name — so the copies are five different migrations, not
replacements. Measured on both engines: ten migrations found instead of five, the bundled ones
run, the published create then dies with a duplicate-table error, and every later migrate
dies the same way.
// in a service provider's register()
MatomoAnalyticsServiceProvider::ignoreMigrations();
php artisan vendor:publish --tag=matomo-analytics-migrations
php artisan migrate
See Database tables for the schema of each table.
What else can be published
| Tag | Publishes |
|---|---|
matomo-analytics-config | config/matomo-analytics.php — what matomo:install publishes. |
matomo-analytics-migrations | The batch-buffer and dead-letter migrations. |
matomo-analytics-views | The privacy-policy partial, into resources/views/vendor/matomo-analytics. |
matomo-analytics-lang | The package translation files, into lang/vendor/matomo-analytics. |
Next steps
- Track from your code with the
Matomofacade, or attach the middleware and track page views with no per-route code. - Render the JavaScript tracker in your layout.
- Count page views on one side. The JavaScript tracker records a page view on every page it is on, and the middleware records one for the same request, so with both on the same pages every view counts twice. Choose the middleware for a site that tracks server-side only, and the tracker otherwise.
- Decide who gets tracked — the defaults already
exclude bots and honor
Do-Not-Track. - Pick a transmission mode once volume grows.