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.
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
iframe 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 only honors
three things when a token is sent: the real visitor IP (cip), the exact hit time
(cdt) and geolocation derived from that IP. Without a token, hits are attributed
to your application server's IP and timed at the moment Matomo receives them.
That second point matters more than it looks. In the default queue mode — and
much more so in batch mode, after a retry, or after a dead-letter replay — a hit
can reach Matomo minutes or hours after the event happened. Set a token if you
want server-side hits attributed and timed 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 or a wrong site id 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.
- Decide who gets tracked — the defaults already
exclude bots and honor
Do-Not-Track. - Pick a transmission mode once volume grows.