PHPackages                             syriable/filament-activitylog - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Utility &amp; Helpers](/categories/utility)
4. /
5. syriable/filament-activitylog

ActiveLibrary[Utility &amp; Helpers](/categories/utility)

syriable/filament-activitylog
=============================

A package to integrate Spatie Activitylog with Filament.

0.1.1(2d ago)02↑2900%MITPHPPHP ^8.4CI passing

Since Jun 7Pushed 2d agoCompare

[ Source](https://github.com/syriable/filament-activitylog)[ Packagist](https://packagist.org/packages/syriable/filament-activitylog)[ Docs](https://github.com/syriable/filament-activitylog)[ RSS](/packages/syriable-filament-activitylog/feed)WikiDiscussions main Synced 2d ago

READMEChangelog (2)Dependencies (13)Versions (3)Used By (0)

Filament Activitylog
====================

[](#filament-activitylog)

Easily add beautiful timelines to your Filament apps — inside panels or stand-alone. Integrates with [Spatie Activitylog](https://github.com/spatie/laravel-activitylog).

[![Latest Version on Packagist](https://camo.githubusercontent.com/fdd65be18a504d4d493e3e45cda5dfa89912de2a7f6fc7fe8cadef2d4845e4e2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7379726961626c652f66696c616d656e742d61637469766974796c6f672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/syriable/filament-activitylog)[![Software License](https://camo.githubusercontent.com/55c0218c8f8009f06ad4ddae837ddd05301481fcf0dff8e0ed9dadda8780713e/68747470733a2f2f696d672e736869656c64732e696f2f62616467652f6c6963656e73652d4d49542d627269676874677265656e2e7376673f7374796c653d666c61742d737175617265)](https://opensource.org/licenses/MIT)[![Total Downloads](https://camo.githubusercontent.com/0130a4150ac05e0139d0d76ae11dd74133c74bf1fd5135cab5b5eb2c5feacac5/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7379726961626c652f66696c616d656e742d61637469766974796c6f672e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/syriable/filament-activitylog)

**Dark mode ready** · **Multilingual support** · **Filament v4 &amp; v5**

---

Table of contents
-----------------

[](#table-of-contents)

- [Features](#features)
- [Requirements](#requirements)
- [Installation](#installation)
- [Usage](#usage)
    - [Logging model events](#logging-model-events)
    - [Custom events](#custom-events)
    - [Timeline](#timeline)
    - [Timeline action](#timeline-action)
- [Translations](#translations)
- [Troubleshooting](#troubleshooting)
- [Testing](#testing)
- [Changelog](#changelog)
- [License](#license)

Features
--------

[](#features)

- Infolist **timeline** component with many configuration options
- Searchable, compact, collapsible, and scrollable timelines
- Custom **actions** inside timeline items
- `ActivitylogTimelineAction` for pages and tables (slide-over modal)
- Activity **group** support with nested or inline display via Spatie v5 `group` properties
- Activities from **relations and related models**, with auto-linking to resources
- Global configuration of icons, colors, actions, descriptions, and more via `ActivitylogTimeline::configureUsing()`
- Beautiful design integrated with Filament
- Works **outside** the admin panel in infolists and Livewire components
- Dark mode support
- Fully translatable (English, French, Italian, Dutch included)
- Works out-of-the-box with Spatie model events

Requirements
------------

[](#requirements)

- PHP 8.4+
- Laravel 12 or 13
- Filament 4.10+ or 5.5+
- [Spatie Laravel Activitylog](https://spatie.be/docs/laravel-activitylog/v5/introduction) 5.x

You should already have Spatie Activitylog installed and configured before using this package. If you have existing activity data, it will work immediately.

Installation
------------

[](#installation)

Install via Composer:

```
composer require syriable/filament-activitylog
```

The service provider registers automatically via Laravel package discovery.

### Custom theme (required)

[](#custom-theme-required)

For each Filament panel that uses the timeline, create a [custom theme](https://filamentphp.com/docs/4.x/styling/overview#creating-a-custom-theme) and add the following line to your `theme.css`:

```
@source '../../../../vendor/syriable/filament-activitylog/resources/**/*.blade.php';
```

If you use the timeline outside a panel, include the same `@source` line in the CSS file used by the Livewire components where the timeline is rendered.

### Register the plugin

[](#register-the-plugin)

Register the plugin on each panel where you use the timeline:

```
use Syriable\Filament\Plugins\Activitylog\Activitylog;

$panel
    ->plugin(Activitylog::make());
```

### Publish translations (optional)

[](#publish-translations-optional)

```
php artisan vendor:publish --tag="filament-activitylog-translations"
```

Usage
-----

[](#usage)

Spatie Activitylog supports two main use cases:

1. Automatically **log model events** on Eloquent models.
2. Log **custom events** and associate them with Eloquent models.

### Logging model events

[](#logging-model-events)

See the [Spatie documentation on logging model events](https://spatie.be/docs/laravel-activitylog/v5/advanced-usage/logging-model-events). Enable model event logging first, then use the timeline to display them.

### Custom events

[](#custom-events)

#### Terminology

[](#terminology)

Each activity has four main properties:

1. **Subject** — the Eloquent model the event was logged on.
2. **Causer** — the model (usually a user) that caused the event, or `null`.
3. **Event** — the programmatic event name (`created`, `updated`, `deleted`, `restored`, or custom events like `published`).
4. **Description** — usually the same as the event name, but can be a custom human-readable string.

#### Logging custom events

[](#logging-custom-events)

Always include an event name. For example, logging a `published` event on a `Post`:

```
$post = Post::find(1);
$johnDoe = User::firstWhere('email', 'johndoe@example.com');

$post->touch('published_at');

activity()
    ->performedOn($post)
    ->causedBy($johnDoe)
    ->event('published')
    ->log('published');
```

By default, the timeline displays:

> John Doe published the post.

#### Displaying the causer name

[](#displaying-the-causer-name)

The causer name is inferred automatically:

1. If the causer implements `Filament\Models\Contracts\HasName`, `getFilamentName()` is used.
2. Otherwise, the `name` attribute is used.
3. Otherwise, `first_name` and/or `last_name` are used.
4. Otherwise, no causer name is included ("The post was published.").

Override with `causerName()` or `causerNames()`:

```
use Syriable\Filament\Plugins\Activitylog\Filament\Infolists\Components\ActivitylogTimeline;

ActivitylogTimeline::make()
    ->causerName(User::class, fn (User $causer) => $causer->full_name)
    ->causerNames([
        User::class => fn (User $causer) => $causer->full_name,
    ])
```

**Fallback causer name** when `causer_type` / `causer_id` are `null`:

```
ActivitylogTimeline::make()
    ->causerName(null, 'System')
```

**Causer URL:**

```
ActivitylogTimeline::make()
    ->causerUrl(function (User $causer) {
        return UserResource::getUrl('edit', ['record' => $causer]);
    })
```

#### Custom descriptions

[](#custom-descriptions)

If the description passed to `->log()` differs from the event name, it is stored as-is (not translatable). For translatable custom descriptions, use `eventDescription()` on the timeline component instead.

You can use inline markdown for bold or italic formatting in stored descriptions.

#### Grouping related activities

[](#grouping-related-activities)

Spatie Activitylog v5 removed `LogBatch` and `Activity::forBatch()`. Use the package `ActivityBatch` helper to group related activities under a shared `group` property:

```
use Syriable\Filament\Plugins\Activitylog\Support\ActivityBatch;
use Spatie\Activitylog\Models\Activity;

ActivityBatch::withinBatch(function () use ($post) {
    activity()
        ->performedOn($post)
        ->event('published')
        ->log('published');

    $post->tweet()->create(['content' => 'Check out my new blog post']);

    activity()
        ->performedOn($post)
        ->event('tweeted')
        ->log('tweeted');
});

$groupId = ActivityBatch::getBatchUuid(Activity::query()->latest('id')->first());

ActivityBatch::scopeForBatch(Activity::query(), $groupId)->get();
```

You can also assign the property manually with `->withProperty(ActivityBatch::PROPERTY_KEY, $groupId)` when logging.

See the [Spatie v5 upgrading guide](https://github.com/spatie/laravel-activitylog/blob/main/UPGRADING.md#batch-system-removed) for details.

### Timeline

[](#timeline)

Use the timeline infolist entry in forms and infolists. In Filament v4+, infolist components can be used inside forms.

```
use Syriable\Filament\Plugins\Activitylog\Filament\Infolists\Components\ActivitylogTimeline;

ActivitylogTimeline::make()
    ->label('History')
```

By default, the timeline hides itself on `create` pages (no record yet). Pass `->visible(true)` to override.

When empty, a customizable empty state is shown.

#### Relation support

[](#relation-support)

Include activities from related models with `withRelations()`:

```
use Filament\Support\Icons\Heroicon;

ActivitylogTimeline::make()
    ->withRelations(['addresses'])
    ->itemIcon('*', Heroicon::OutlinedHomeModern, [Address::class])
```

Related model activities produce descriptions like "John Doe added related address **Main St. 123, NYC**."

> If a related model is no longer linked to the current record, its historical activities disappear from that record's timeline.

**Record title attribute:**

```
ActivitylogTimeline::make()
    ->recordTitleAttribute(Post::class, 'id')
    ->recordTitleAttributes([
        Post::class => 'id',
        Address::class => 'display_summary',
    ])
    ->getRecordTitleUsing(Post::class, fn (Post $post) => (string) $post->id)
    ->getRecordTitleUsing(Address::class, fn (Address $address) => "{$address->city}, {$address->state}")
```

**Record URL:**

```
ActivitylogTimeline::make()
    ->recordUrl(Post::class, fn (Post $post) => route('frontend.posts.show', ['post' => $post]))

// Disable linking:
ActivitylogTimeline::make()
    ->recordUrl(Post::class, fn (Post $post) => null)
```

**Limit related results:**

```
ActivitylogTimeline::make()
    ->withRelations([
        'addresses' => function (HasMany $relation) {
            return $relation->where('type', AddressType::Shipping);
        },
    ])
```

#### Customizing timeline items

[](#customizing-timeline-items)

**Icons and colors:**

```
use Filament\Support\Icons\Heroicon;
use Spatie\Activitylog\Models\Activity;

ActivitylogTimeline::make()
    ->itemIcon('created', Heroicon::OutlinedPlusCircle)
    ->itemIcon('deleted', Heroicon::OutlinedTrash)
    ->itemIcons([
        'created' => fn (Activity $activity) => Heroicon::OutlinedPlus,
        'deleted' => Heroicon::OutlinedTrash,
    ])
    ->itemIconColor('created', 'info')
    ->itemIconColor('deleted', 'danger')
    ->itemIconColors([
        'created' => 'info',
        'deleted' => 'danger',
    ])
```

Scope to specific models:

```
ActivitylogTimeline::make()
    ->itemIcon('created', Heroicon::OutlinedPlusCircle, [Post::class])
    ->itemIconColor('created', 'success', Post::class)
```

**Badges:**

```
use Filament\Support\Colors\Color;

ActivitylogTimeline::make()
    ->itemBadge('email_sent', fn (Activity $activity) => Status::tryFrom($activity->getProperty('status'))?->getLabel())
    ->itemBadgeColor('email_sent', fn (Activity $activity) => match (Status::tryFrom($activity->getProperty('status'))) {
        Status::Bounce => 'danger',
        Status::Delivery => 'success',
        default => 'gray',
    })
```

**Time format and timezone:**

```
ActivitylogTimeline::make()
    ->itemDateTimeFormat('Y-m-d H:i')
    ->itemDateTimeTimezone(fn () => auth()->user()->timezone)
```

**Item actions:**

```
use Filament\Actions;
use Filament\Forms;
use Filament\Support\Icons\Heroicon;

ActivitylogTimeline::make()
    ->itemActions('published', [
        Actions\Action::make('view_url_in_search_console')
            ->label('Open Google Search Console')
            ->icon(Heroicon::MagnifyingGlass)
            ->url(fn (Post $post) => 'https://search.google.com/...'),
        Actions\Action::make('create_tweet')
            ->label('Send Tweet')
            ->icon(Heroicon::Megaphone)
            ->form([
                Forms\Components\Textarea::make('content')
                    ->maxLength(280)
                    ->required(),
            ])
            ->action(function (Post $post, array $data) {
                // ...
            }),
    ])
```

Access the underlying activity via `$arguments['activity_id']` when needed.

**Global defaults:**

```
use Filament\Support\Icons\Heroicon;

ActivitylogTimeline::configureUsing(function (ActivitylogTimeline $timeline) {
    return $timeline
        ->itemIcons([
            'created' => Heroicon::OutlinedPlusCircle,
            'deleted' => Heroicon::OutlinedTrash,
        ])
        ->itemIcon('created', Heroicon::OutlinedPencil, [Post::class])
        ->itemIconColors([
            'created' => 'info',
            'deleted' => 'danger',
        ])
        ->itemActions(
            event: 'published',
            actions: [/* ... */],
            subjectScopes: [Post::class],
        );
});
```

Per-timeline configuration overrides global defaults.

#### Descriptions

[](#descriptions)

Override generated descriptions per event:

```
ActivitylogTimeline::make()
    ->eventDescription('published', 'Post is now shared with the world 🌎', [Post::class])
    ->eventDescriptions(
        descriptions: [
            'created' => fn (Activity $activity) => "{$activity->causer->full_name} started a draft post",
            'published' => 'Post is now shared with the world 🌎',
        ],
        subjectScopes: [Post::class],
    )
    ->modifyEventDescriptionUsing(function (string $eventDescription, Activity $activity, string $recordTitle, ?string $causerName, ?string $changesSummary) {
        return "{$eventDescription} for {$recordTitle}";
    })
```

#### Formatting attribute values

[](#formatting-attribute-values)

For `updated` events, changed attributes appear in the description automatically. Strings, booleans, arrays, enums, and dates are formatted for readability.

**Custom casts** — add casted attributes to `useAttributeRawValues()` in `getActivitylogOptions()`:

```
public function getActivitylogOptions(): LogOptions
{
    return LogOptions::defaults()
        ->useAttributeRawValues(['amount'])
        ->logAll();
}
```

**Format by attribute:**

```
ActivitylogTimeline::make()
    ->attributeLabel('amount', 'purchase amount')
    ->attributeValue('amount', fn (?Money $value) => $value?->formatWithoutZeroes())
    ->attributeValues([
        'amount' => fn (?Money $value) => $value?->formatWithoutZeroes(),
    ])
```

**Format by cast class:**

```
ActivitylogTimeline::make()
    ->attributeCast(MoneyCast::class, fn (?Money $value) => $value?->formatWithoutZeroes())
```

**Hide old attribute values:**

```
ActivitylogTimeline::make()
    ->changesSummaryOldAttributeValues(false)
```

**Hide attribute values:**

```
ActivitylogTimeline::make()
    ->changesSummaryAttributeValues(false)
```

**Attribute labels:**

```
ActivitylogTimeline::make()
    ->attributeLabel('some_date', 'published at')
    ->attributeLabels([
        'some_boolean' => 'is hidden from SEO',
    ])
```

Labels are also resolved from form/infolist components on the same page when available.

**Model labels:**

```
ActivitylogTimeline::make()
    ->modelLabel(User::class, 'Benutzer')
    ->modelLabels([
        Post::class => 'Beitrag',
    ])
```

#### Activity groups

[](#activity-groups)

Activities that share the same `group` property (via `ActivityBatch`) display as a nested sub-timeline by default. Display group items inline with the main timeline:

```
ActivitylogTimeline::make()
    ->inlineGroups()
```

**Customize the group query:**

```
ActivitylogTimeline::make()
    ->modifyGroupActivitiesQueryUsing(function (Builder $query, Activity $activity, string $groupKey) {
        return $query->whereIn('event', ['deleted', 'restored']);
    })
```

**Override the group query entirely:**

```
use Syriable\Filament\Plugins\Activitylog\Support\ActivityBatch;

ActivitylogTimeline::make()
    ->getGroupActivitiesUsing(function (Activity $activity, string $groupKey) {
        return ActivityBatch::scopeForBatch(Activity::query(), $groupKey)
            ->where('id', '!=', $activity->id)
            ->get();
    })
```

#### Empty state

[](#empty-state)

```
use Filament\Support\Icons\Heroicon;

ActivitylogTimeline::make()
    ->emptyStateHeading('No history')
    ->emptyStateDescription('Nothing has happened to this model yet.')
    ->emptyStateIcon(Heroicon::OutlinedBarsArrowDown)
```

#### Compact timeline

[](#compact-timeline)

```
ActivitylogTimeline::make()
    ->compact()
```

Globally:

```
ActivitylogTimeline::configureUsing(fn (ActivitylogTimeline $timeline) => $timeline->compact());
```

On compact timelines, outline heroicons are automatically converted to mini variants (and vice versa). Disable with:

```
ActivitylogTimeline::make()
    ->convertHeroicons(false)
```

#### Searchable timelines

[](#searchable-timelines)

```
ActivitylogTimeline::make()
    ->searchable()
```

Search runs in the browser against activity descriptions.

#### Collapsible timelines

[](#collapsible-timelines)

Show only the most recent activities by default, with a toggle to reveal the rest:

```
ActivitylogTimeline::make()
    ->collapsible()
    ->collapsedVisibleCount(5)
```

#### Maximum height

[](#maximum-height)

```
ActivitylogTimeline::make()
    ->maxHeight()      // default 500px
    ->maxHeight(800)
    ->maxHeight('50vh')
```

#### Sort order

[](#sort-order)

```
ActivitylogTimeline::make()
    ->sortActivitiesDescending(false) // oldest first
```

#### Custom activities query

[](#custom-activities-query)

```
ActivitylogTimeline::make()
    ->modifyActivitiesQueryUsing(function (Builder $query) {
        return $query->where('log_name', 'notifications');
    })
```

Override entirely:

```
ActivitylogTimeline::make()
    ->getActivitiesUsing(function () {
        return Activity::query()->get();
    })
```

Prefer `modifyActivitiesQueryUsing()` when possible.

#### Activities limit

[](#activities-limit)

For models with long histories, cap how many activities are loaded into the timeline:

```
ActivitylogTimeline::make()
    ->activitiesLimit(50)
```

The limit is applied after sorting and group deduplication. Combine with `modifyActivitiesQueryUsing()` for database-level filtering when possible.

#### Hiding the label

[](#hiding-the-label)

```
ActivitylogTimeline::make()
    ->hiddenLabel()
```

### Timeline action

[](#timeline-action)

Use `ActivitylogTimelineAction` on pages and in tables to open the timeline in a slide-over:

```
use Syriable\Filament\Plugins\Activitylog\Filament\Actions\ActivitylogTimelineAction;

class EditPost extends EditRecord
{
    protected function getHeaderActions(): array
    {
        return [
            ActivitylogTimelineAction::make(),
        ];
    }
}
```

```
$table
    ->recordActions([
        ActivitylogTimelineAction::make(),
    ]);
```

Customize the embedded timeline:

```
ActivitylogTimelineAction::make()
    ->modifyActivitylogTimelineUsing(function (ActivitylogTimeline $timeline) {
        return $timeline->compact()->searchable();
    })
```

Translations
------------

[](#translations)

Built-in languages: English, French, Italian, Dutch.

Publish and customize:

```
php artisan vendor:publish --tag="filament-activitylog-translations"
```

Troubleshooting
---------------

[](#troubleshooting)

### Timeline styles are missing

[](#timeline-styles-are-missing)

Add the package `@source` line to your Filament custom theme CSS (see [Custom theme](#custom-theme-required)).

### No activities appear

[](#no-activities-appear)

Confirm Spatie Activitylog is installed, the model uses the `LogsActivity` trait, and activities exist for the record. Use `modifyActivitiesQueryUsing()` to debug the underlying query.

### Grouped activities do not collapse

[](#grouped-activities-do-not-collapse)

Spatie v5 uses a `group` property on activities, not a `batch_uuid` column. Use `ActivityBatch::withinBatch()` or set the `group` property manually when logging.

### Performance on large histories

[](#performance-on-large-histories)

Use `activitiesLimit()` or `modifyActivitiesQueryUsing()` to avoid loading thousands of rows into memory.

Testing
-------

[](#testing)

```
composer test
```

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

License
-------

[](#license)

This package is open-sourced software licensed under the [MIT license](https://opensource.org/licenses/MIT).

###  Health Score

39

—

LowBetter than 84% of packages

Maintenance99

Actively maintained with recent releases

Popularity3

Limited adoption so far

Community8

Small or concentrated contributor base

Maturity42

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 54.5% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~0 days

Total

2

Last Release

2d ago

### Community

Maintainers

![](https://avatars.githubusercontent.com/u/286110444?v=4)[syriable](/maintainers/syriable)[@syriable](https://github.com/syriable)

---

Top Contributors

[![alkhatibsy](https://avatars.githubusercontent.com/u/23545455?v=4)](https://github.com/alkhatibsy "alkhatibsy (6 commits)")[![claude](https://avatars.githubusercontent.com/u/81847?v=4)](https://github.com/claude "claude (5 commits)")

---

Tags

laravelfilament-activitylogsyriable

###  Code Quality

TestsPest

Static AnalysisPHPStan

Code StyleLaravel Pint

Type Coverage Yes

### Embed Badge

![Health badge](/badges/syriable-filament-activitylog/health.svg)

```
[![Health](https://phpackages.com/badges/syriable-filament-activitylog/health.svg)](https://phpackages.com/packages/syriable-filament-activitylog)
```

###  Alternatives

[codewithdennis/filament-select-tree

The multi-level select field enables you to make single selections from a predefined list of options that are organized into multiple levels or depths.

327482.0k25](/packages/codewithdennis-filament-select-tree)[rawilk/profile-filament-plugin

Profile &amp; MFA starter kit for filament.

3913.7k](/packages/rawilk-profile-filament-plugin)[mradder/filament-logger

Audit logging, activity tracking, exports, alerts, and dashboards for Filament admin panels.

2210.5k](/packages/mradder-filament-logger)[dotswan/filament-map-picker

Easily pick and retrieve geo-coordinates using a map-based interface in your Filament applications.

127173.7k3](/packages/dotswan-filament-map-picker)[stephenjude/filament-jetstream

A Laravel starter kit built with Filament inspired by Jetstream.

17758.9k2](/packages/stephenjude-filament-jetstream)[stephenjude/filament-debugger

About

103150.5k2](/packages/stephenjude-filament-debugger)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
