edwink/filament-user-activity
A Filament plugin that brings user activity tracking to your admin panel, letting you log, view, and filter user actions and events so you can audit changes and monitor who did what, when, and from where.
Install the package and publish its assets:
composer require edwink/filament-user-activity
php artisan vendor:publish --tag="filament-user-activity-config"
php artisan vendor:publish --tag="filament-user-activity-migrations"
php artisan migrate
Register the plugin on the panel(s) where you want activity tracked and surfaced:
public function panel(Panel $panel): Panel
{
return $panel
->plugin(FilamentUserActivityPlugin::make());
}
Where to look first: the published config/filament-user-activity.php. That file is the contract for everything else — the inactivity window (how many minutes ago a hit still counts as "online"), the table/connection used for storage, the auth guard being tracked, and any polling interval used by the widget. Read it before touching the widget or the middleware.
First use case: drop the active-users widget onto the dashboard so admins can see who is currently in the app. Register it in your panel's ->widgets([...]) array (or discover it via php artisan filament:widget), and you have a live "who's online" table in minutes. The natural second step is activity history — filtering the same data by user and time range to answer "what has this account been doing?"
Middleware-driven capture. The package records a visit per authenticated request, typically by stamping last_activity_at (and IP/user agent) on a row keyed by user. That means you don't call anything manually — the panel's web middleware group does the work. If you need tracking on non-Filament routes (an API, a public area), register the tracking middleware there too, and confirm it runs after auth so Auth::id() is populated.
Panel vs. global scope. In multi-panel apps (admin + app + vendor), decide whether activity is one shared pool or per-panel. Most teams want a single pool for "who's online" but a panel column/filter for "who's in the admin panel." If the package doesn't expose a panel column out of the box, add one via a small migration or a computed attribute rather than forking.
Tenant scoping. In a tenancy setup, "active users" is almost always "active users in this tenant." Wrap the widget's query in the tenant scope (->where('tenant_id', Filament::getTenant()->id)) and make sure the tracking middleware writes the tenant too — otherwise your widget leaks names across tenants, which is both a UX and a privacy problem.
Retention & pruning. Activity rows grow linearly with traffic. Add the package's model to your pruneable schedule ($schedule->command('model:prune')) or a bespoke activity:prune --days=30 command. Do this on day one, not after the table hits 50M rows.
Dashboard composition. Combine the active-users widget with Filament's chart widgets to show logins per day, per role, per panel. Same underlying table, different aggregation — cheapest way to make the data feel useful.
admin, staff), the plugin will silently show nothing until the config's guard is set to match the panel's authGuard(). This is the #1 "it's installed but empty" cause.bootstrap/app.php, put it in the web group, not the global stack.(user_id, last_activity_at), and consider caching the count for the header badge separately from the table.spatie/laravel-activitylog), don't duplicate storage. Point the config at the existing table if supported, or write a small adapter — two sources of truth for "last seen" will disagree within a week.Carbon::setTestNow() and assert on the inactivity boundary — off-by-one on the window is the most common subtle bug (is it >= or > five minutes?).How can I help you explore Laravel packages today?