haruncpi/laravel-user-activity
Laravel User Activity is a lightweight package for monitoring and logging user actions in Laravel apps. It tracks logins, logouts, page visits, and other activity in a database-backed log, with simple setup and an easy way to review recent user behavior.
Install and wire it up in about five minutes:
composer require haruncpi/laravel-user-activity
php artisan vendor:publish # pick the Haruncpi\LaravelUserActivity provider entry
php artisan migrate
Publishing drops two things you care about: config/user-activity.php and a migration for the activity table. Read the config file before doing anything else — it is the single source of truth for how much noise this package makes. The knobs that matter on day one are the middleware stack it assumes, the list of excluded URIs, and the user model reference.
Then register the package middleware in app/Http/Kernel.php under the web group (or, better, a dedicated route group — see below):
protected $middlewareGroups = [
'web' => [
// ...
\Haruncpi\LaravelUserActivity\Middleware\UserActivity::class,
],
];
First use case: hit a few pages while authenticated, then query the activity table directly (UserActivity::latest()->take(20)->get() in tinker) to see exactly what gets captured per request — URL, method, IP, user agent, user id, and any Eloquent model events. Do this before you build anything on top of it; the payload shape tells you whether the package is a request logger, an audit trail, or both in your version.
If the package exposes its dashboard route, visit it while logged in and confirm it renders — it is usually the fastest way to sanity-check the integration.
Scope the middleware, don't globalize it. Adding it to the whole web group logs every asset request, health check, Horizon/Telescope poll, and Livewire ping. Prefer a route group:
Route::middleware(['web', 'auth', UserActivity::class])->group(function () {
Route::get('/dashboard', ...);
});
and keep the config's except array populated with _debugbar/*, horizon/*, telescope/*, user-activity*, livewire/*.
Pair it with auth, not around it. The middleware resolves the current user from the auth guard at the time it runs. If it sits before auth, guests get logged with a null user_id and you cannot tell "anonymous hit" from "misconfigured middleware order."
Use the Eloquent event side for audit trails. If your version logs created/updated/deleted on models, that is the real value: you get a free change history for the models you nominate in config. Keep that list tight — logging every model in a large app multiplies write volume and turns the table into an unreadable firehose.
Log domain events explicitly. For anything that matters and isn't a CRUD write — "exported invoice", "impersonated user", "changed plan" — write a row yourself with the package model (or a thin wrapper service) rather than trying to infer intent from route names. Consistency between auto-logged and manual rows makes the reporting queries trivial.
Reporting layer. Treat the activity table as append-only and query it with your own scopes: per-user timelines, per-route hit counts, "who touched this record." A small ActivityReport service keeps raw queries out of controllers and lets you swap in caching once the table grows.
Retention. Most versions ship no pruning. Add a scheduled command:
UserActivity::where('created_at', '<', now()->subDays(90))->delete();
and make sure user_id + created_at are indexed before the table hits a few million rows.
Testing. Set the package to disabled (or point it at a null/sqlite in-memory connection) in phpunit.xml so feature tests don't burn time on inserts that aren't under test.
DB::afterCommit).DB::table() and mass updates bypass everything. Query-builder deletes, update() on a builder, and raw SQL are invisible to model-event logging. Don't sell this as a compliance audit trail without that caveat.config/user-activity.php, run php artisan config:clear. A stale cached config is the #1 cause of "the exclusion isn't working."/user-activity) may clash with something you already own. Rename it or disable the package routes and build your own view off the model.auth (and ideally an admin gate) in your setup. An activity log that lists every user's URLs and IPs is itself a privacy surface.user_activities table already exists from a previous attempt, the migration will fail silently-ish. Drop or rename before re-running.spatie/laravel-activitylog (or owen-it/laravel-auditing for field-level diffs) is the safer long-term bet. This package's edge is the batteries-included request log + dashboard for small-to-medium apps — use it for that, don't stretch it into an enterprise audit system.How can I help you explore Laravel packages today?