pushery/matomo-analytics-for-laravel
A Laravel wrapper for Matomo Analytics that lets you track page views, events, and goals server-side through a clean, configurable API. Keep tracking code out of your views and respect visitor consent.
composer require <vendor>/laravel-matomo-analytics
php artisan vendor:publish --tag=matomo-analytics-config
php artisan vendor:publish --tag=matomo-analytics-migrations
php artisan migrate
config/matomo-analytics.php. It is the contract for everything below — queue settings under queue.*, batching under batch.*, dead-letter handling under its own keys. The config reference (shipped in the package docs) is authoritative; the code is a fallback..env:
MATOMO_QUEUE_TRIES=5
MATOMO_QUEUE_RETRY_UNTIL_MINUTES=120
MATOMO_BATCH_STALE_AFTER_MINUTES=30
MATOMO_DEAD_LETTER_RETENTION_DAYS=30
Non-integer or < 1 values for the first three silently keep the shipped default — so verify effective config, don't assume it took.php artisan queue:work) in the same environment you configured. A worker started before an .env change keeps the old values — restart it.Tune retries per environment, not per deploy. MATOMO_QUEUE_TRIES and MATOMO_QUEUE_RETRY_UNTIL_MINUTES map straight onto queue.tries and queue.retry_until_minutes, so staging can retry aggressively while production stays conservative. Set both together: a high try count with a short retry window just burns attempts fast, and a long window with tries=1 never uses it.
Use the retry window as your "outage tolerance". If Matomo is briefly unreachable, the retry window is how long tracking keeps being retried. Size it against your acceptable data loss, and make sure the worker's --timeout / --max-time settings don't kill jobs before the window elapses.
Watch batch.stale_after_minutes alongside your cron cadence. Stale batches are reclaimed after this window, so if you flush or prune batches on a schedule, keep the reclaim window comfortably larger than the interval between runs. Two overlapping reclaimers on the same batch is the classic double-send source; keep the flush job non-overlapping (withoutOverlapping()).
Treat dead letters as a bounded audit log. MATOMO_DEAD_LETTER_RETENTION_DAYS=0 means keep forever and the daily prune is off. Any positive value prunes after that many days; negatives now fall back to the shipped 30 rather than disabling pruning. Decide explicitly which of 0 or 30 you want — the difference between an unbounded table and a rolling window is easy to discover a year later.
Wrap tracking calls behind the package's API, not behind raw config reads. Since migrations now depend only on public API (Support\TableLookup), your application config and your migrations are both reasonable extension points; direct coupling to internal classes is not.
Publish migrations once and own them. After publishing, the file lives in your database/migrations and runs in your namespace. That's the intended model — but it also means package upgrades will not patch it for you. If the package's migration changes upstream, diff the published copy against the shipped one deliberately.
MATOMO_QUEUE_TRIES=4.5, =0, or =abc doesn't error — it keeps the shipped default. Dump config('matomo-analytics.queue.tries') in php artisan tinker after any change rather than trusting the .env file.php artisan config:cache in deploy means .env edits are invisible until you re-cache. Add config:clear / config:cache to the deploy script, and restart queue workers so they pick up the new config.MATOMO_DEAD_LETTER_RETENTION_DAYS=-1 to disable pruning, that silently changes behaviour in this release — you'll start losing dead letters after 30 days. Switch to 0 if unlimited retention is genuinely intended.Support\TableLookup now public API, the "call into internal class" warnings from your analyser on published migrations should disappear. If they persist, you're on a stale published migration — re-publish or check the analyser's cached results.retry_until_minutes lands in dead letters; a batch reclaimed as stale before its jobs finish can be re-sent. When tuning, change one value at a time and watch both the failed-jobs table and the batch table.How can I help you explore Laravel packages today?