Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Nova Activitylog Laravel Package

sashalenz/nova-activitylog

Nova Activity Log integrates spatie/laravel-activitylog with Laravel Nova, adding a resource to browse, filter, and inspect recorded model events and user actions from your admin panel. Quickly trace who changed what and when.

View on GitHub
Deep Wiki
Context7

Getting Started

Nova Activity Log is a Nova tool that surfaces the rows written by spatie/laravel-activitylog as a browsable, filterable audit trail inside your Nova admin panel. It is a viewer, not a logger — the logging itself is spatie's package.

composer require sashalenz/nova-activitylog

Order of installation matters:

  1. Install and configure spatie/laravel-activitylog first (publish + run its migration).
  2. Publish the tool's config/migrations if it ships any, then php artisan migrate.
  3. Register the tool in app/Providers/NovaServiceProvider.php:
public function tools()
{
    return [
        new \Sashalenz\NovaActivitylog\NovaActivitylog(),
    ];
}
  1. Ensure the frontend assets exist — if the entry is missing from the sidebar, run php artisan nova:publish and, in the package directory, npm install && npm run prod.

Look first at: the tool's config/ file (log names, per-page, visible columns), the spatie config/activitylog.php (default_log_name, delete_records_older_than_days), and the tool's Vue components if you need to add a column.

First use case — give a model an audit trail and confirm it renders:

use Spatie\Activitylog\Traits\LogsActivity;
use Spatie\Activitylog\LogOptions;

class Invoice extends Model
{
    use LogsActivity;

    public function getActivitylogOptions(): LogOptions
    {
        return LogOptions::defaults()
            ->logOnly(['status', 'total', 'paid_at'])
            ->logOnlyDirty()
            ->dontSubmitEmptyLogs();
    }
}

Update an Invoice in Nova, then open the Activity Log tool from the sidebar — you should see the entry with causer, subject, event, and the old/attributes diff.

Implementation Patterns

Scope the tool per audience. Gate the whole tool with canSee, and give non-admins a pre-filtered view rather than a raw table dump:

(new NovaActivitylog())->canSee(fn ($request) => $request->user()->hasRole('admin')),

Per-resource history panel. Attaching the tool as a resource tool (rather than only in the sidebar) is the highest-value integration — it puts the audit trail on the detail page of the record it describes. Pass the resource name and ID, and have the tool constrain on subject_type + subject_id.

Log names as a taxonomy. Spatie's log_name is the cheapest way to partition the table (billing, auth, import). Set it per model via ->useLogName('billing') and mirror it as a filter in the tool. Keep the list of log names in config so filters, policies, and activitylog:clean all agree.

Bulk-operation correlation. When a job mutates hundreds of records, wrap it in activity()->withBatchUuid()-style grouping or set batch_uuid yourself so the tool can show one row per operation group. This is the pattern that makes the tool useful for incident review rather than just single-record diffs.

Causer discipline. In HTTP contexts spatie resolves the causer from the guard. In queued jobs and console commands it will be null unless you set it explicitly:

activity()->causedBy($user)->performedOn($invoice)->log('refunded');

If your app runs most writes through jobs, set a CauserResolver or pass the actor ID into the job payload — otherwise your audit trail is anonymous where it matters most.

Retention as a scheduled job. Register activitylog:clean in Kernel::schedule() and set delete_records_older_than_days. Audit tables grow monotonically and the Nova tool's filters will get slow before anything actually breaks.

Multi-tenancy. There is no tenant column by default. Either add one via a migration and extend the base Activity model (then point config('activitylog.activity_model') at yours), or constrain the tool's index query. Do this before the table is large.

Pair with a dashboard card. A small Nova metric/card showing activity volume per day or per log name turns the tool from an archive into something people actually open.

Gotchas and Tips

2.0.0 is a major bump with no published migration notes. The changelog for this release is a bare compare link, so treat it as "assume breaking." Before upgrading, read the tool's composer.json constraints and confirm which major of spatie/laravel-activitylog and which Nova major it now requires. The v3 → v4 activitylog jump is the classic trap: the schema gained event and batch_uuid, morph columns became nullable, and getActivitylogOptions() replaced the static $logAttributes/$recordEvents properties. A tool built for one major will show blank columns or throw on the other.

Pin both packages together. sashalenz/nova-activitylog and spatie/laravel-activitylog move in lockstep. Lock them in composer.json with explicit major constraints rather than ^ on both and hoping.

Renamed methods bite silently. With activitylog v4, logOnly()/logExcept()/logOnlyDirty() live on the LogOptions object. If you upgraded the package but left the old static properties on your models, you will get no log entries and no error — the trait just logs everything or nothing depending on defaults.

Assets are the most common "it's broken" report. A blank tool route or an unstyled table in Nova 4/5 is almost always uncompiled Vite assets in the vendor directory. Check the browser console and nova:publish output before debugging PHP.

properties is a JSON blob, not a schema. Old/new values only appear when logOnlyDirty() is on and the model actually changed. Manual activity()->withProperties([...])->log() calls don't follow the same shape, so the tool's diff view may render an empty cell — normalize your manual calls to ['old' => [...], 'attributes' => [...]] if you want the diff UI to work.

Causer is null more often than you think. Queue workers, scheduled commands, seeders, and impersonation sessions all produce rows the tool will label "System." Add a default_causer or an explicit causedBy() and log it as a known limitation in your runbook — auditors ask about this.

Index the table yourself. At minimum (subject_type, subject_id), (log_name, created_at), and created_at. The tool paginates, but the filters and the "history for this record" panel both scan; without indexes they degrade badly past a few hundred thousand rows.

Swapping the Activity model is a one-way door. Pointing activity_model at a subclass is fine if it extends the base model and the tool resolves through config rather than a hardcoded class. Verify by grepping the tool's source for Spatie\Activitylog\Models\Activity — a hardcoded reference means your subclass's extra columns never render.

Verify authorization after upgrading. canSee closures and Nova policies changed shape across Nova majors. After the 2.0.0 bump, log in as a non-admin and confirm the sidebar entry is genuinely hidden, not just visually disabled.

Debugging checklist: php artisan nova:check, php artisan config:clear (tool config is cached), php artisan route:list | grep activity, and confirm rows exist with Activity::latest()->first() in tinker. If rows exist but the tool is empty, it's a filter/scope or subject_type morph-map issue (morph maps must be registered in Relation::enforceMorphMap() if you use them).

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
middlewares/firewall
qubiqx/montapacking
nyoncode/laravel-package-console
pnscripts/filament-broadquill-lite
pnscripts/laravel-sentfold-lite
vleap/mx-sdk-laravel-internal
twidpay/utils
htetmyathlaing/scout-elasticsearch-driver
artisan-toolbox/front-awesome
ls/client-assistant
users-au/laravel-client
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect