webbingbrasil/filament-notification
A Filament plugin by WebbingBrasil for adding in-app notifications to Laravel admin panels, with database-backed alerts, a notification bell, and customizable toast messages for users.
Start by confirming the package actually fits your Filament version. This plugin is archived and was built for the Filament v2 era; the first thing to do is open composer.json in the repo and check its filament/filament constraint against your app. If you're on v3/v4, budget time to fork and port rather than expecting it to work out of the box.
Minimal setup on a v2 app:
composer require webbingbrasil/filament-notification
php artisan vendor:publish --provider="WebbingBrasil\FilamentNotification\FilamentNotificationServiceProvider"
php artisan migrate
Then register the plugin in your panel service provider (AdminPanelProvider or FilamentServiceProvider):
Filament::registerPlugins([
\WebbingBrasil\FilamentNotification\FilamentNotificationPlugin::make(),
]);
Where to look first, in this order:
config/filament-notification.php after publishing — polling interval, model class, table name, and whether the feed renders as a topbar dropdown or a page.src/ — the service provider and plugin class tell you exactly which Filament hooks are used (navigation items, render hooks, widgets), which is what you'll need to touch when porting or overriding.database/migrations/ — the package may ship its own notifications table or expect Laravel's default. Verify what actually got created.First real use case: replace Filament's transient toast-only notifications with a persistent, per-user feed. Your User model must already use Illuminate\Notifications\Notifiable, and you must have the standard notifications table (php artisan notifications:table && php artisan migrate) if the package doesn't ship one. Once a notification lands in the DB, the bell/dropdown should show an unread badge and let users mark items read.
Sending from anywhere in the app. The feed is just Laravel database notifications, so keep using the framework:
class InvoicePaid extends Notification
{
public function via($notifiable): array
{
return ['database'];
}
public function toDatabase($notifiable): array
{
return [
'title' => 'Invoice paid',
'body' => "Invoice #{$this->invoice->number} was paid.",
'url' => InvoiceResource::getUrl('edit', ['record' => $this->invoice]),
'icon' => 'heroicon-o-currency-dollar',
'color' => 'success',
];
}
}
$user->notify(new InvoicePaid($invoice));
// or fan out
Notification::send(User::role('admin')->get(), new InvoicePaid($invoice));
The url key is what makes this useful day-to-day — clicking a feed item deep-links into the relevant Filament resource.
Two-tier notifications. Use Filament::notify()->success(...) for the immediate "saved" toast, and a database notification for the audit trail that survives the page reload. Users get instant feedback and a history.
Scheduled digests. Because it's DB-backed, you can query unread notifications in a scheduled command and email a digest, while the in-app feed stays as the source of truth. Group with whereNull('read_at') and where('created_at', '>=', now()->subDay()).
Routing to the feed from a custom dashboard widget. Expose a count widget ($this->user->unreadNotifications()->count()) above the feed so the dashboard surfaces urgency without opening the dropdown.
Polling for near-real-time. The plugin typically polls on an interval from config. If your team needs true real-time, keep the plugin for rendering but trigger a refresh via a lightweight Livewire listener backed by broadcasting, rather than lowering the poll interval globally.
Customizing the render. If the package's Blade view doesn't match your design system, prefer overriding via ->view(...)/published views over editing vendor/. For anything structural (extra filters, bulk archive), subclass the plugin's Livewire component and re-register it — the archived state means upstream fixes aren't coming, so treat all changes as local.
composer.json ("webbingbrasil/filament-notification": "dev-main#<sha>") so a future composer update can't pull an incompatible state, and document the fork point in your README.via() must include database. A notification that only returns mail will never appear in the feed, and there is no error — just silence. This is the single most common "the feed is empty" cause.Notifiable on non-User models. If admins notify Teams, Tenants, or a custom Admin model, that model needs the trait and the package's queries need to respect it. Check whether the feed queries auth()->user() directly — if so, multi-guard or multi-panel setups will leak or show nothing.getEloquentQuery() in your subclass before exposing it.unreadNotifications()->count(). On tables with millions of rows, add an index on (notifiable_type, notifiable_id, read_at) — Laravel's default migration doesn't include one.markAsRead() on one user's copy doesn't affect others. That's correct Laravel behavior but surprises teams expecting a shared feed.created_at renders raw from the DB. If you display relative times ("2h ago"), ensure app.timezone matches what you expect or format explicitly with ->diffForHumans().ShouldQueue, the feed item appears only after the worker runs. During debugging, set QUEUE_CONNECTION=sync to rule out the queue as the culprit.php artisan config:clear after every config edit — the published config is cached in production like any other.vendor:publish without a tag first to see what's available (migrations, views, config); re-running with a tag after a fork will overwrite your edits.render() rather than patching vendor files — that way a future Laravel/Filament upgrade only breaks your one subclass.How can I help you explore Laravel packages today?