tomatophp/filament-fcm-driver
Firebase Cloud Messaging driver for Filament that lets you send push notifications to mobile and web clients from your Laravel admin panel. Configure FCM credentials, target devices, and manage notification delivery directly within Filament.
This package wires Firebase Cloud Messaging (FCM) push notifications into a Filament panel, using tomatophp/filament-alerts as the notification layer and laravel-notification-channels/fcm as the transport. v5.0.0 is the Filament v5 / Laravel 12–13 line.
tomatophp/filament-alerts ^5.0, and laravel-notification-channels/fcm ^5.0 || ^6.0. If you're still on Filament v4, stay on the v4 branch — v5 is not a drop-in for v4 panels.composer require tomatophp/filament-fcm-driver, then run php artisan filament-fcm-driver:install. As of v5 this command also generates the browser service worker, so you don't need a separate publish step.storage/app/private/...) rather than a public path — no storage:link needed, but the web server user must be able to read/write it.filament-alerts.queue — e.g. php artisan queue:work --queue=filament-alerts.queue,default. Mobile notifications are queued on this named queue again in v5, so a default-only worker will silently send nothing.Where to look first: config/filament-fcm-driver.php for the disk, queue name, and credential path; the panel settings page for the uploaded key; and the generated service worker in public/ to confirm its scope.
First use case: from the panel, send a test push to yourself. Once that lands, move to a real notification class (see below) and wire it into whatever domain event you actually care about — a new alert, an assigned task, an approval request.
Notification class + FCM channel. The day-to-day shape is a standard Laravel notification that returns an FCM message from toFcm(). Keep the payload small — title, body, and a data array for deep-link routing into the panel. Rich formatting belongs in the panel, not the push.
Routing to devices. Implement routeNotificationForFcm() on your notifiable so the channel can resolve one or more tokens. If you support multiple devices per user, back this with a device_tokens table (user_id, token, platform, last_seen_at) rather than a single column — you'll thank yourself when pruning.
Token lifecycle is the real work. Tokens rotate and expire. Refresh the token on login and on the SDK's token-refresh callback, persist it, and delete rows when FCM reports messaging/registration-token-not-registered or invalid-registration-token. Pruning is not optional at any real user count.
Public/broadcast notifications. v5 routes public notifications to every user holding an FCM token. That's convenient for announcements but dangerous as a default — chunk it (Bus::batch or a chunked job) so a 50k-user announcement doesn't become one giant job or a timeout. Treat "public" as an explicit, deliberate send.
Queue discipline. Anything sent to mobile lands on filament-alerts.queue. Give it its own supervisor process or at least include it in your worker's --queue list. If push volume is high, isolate it so a slow FCM round-trip can't starve your default queue.
Panel actions. The natural integration point is a Filament action or bulk action ("Send push", "Notify assignees"). Because actions work again on Filament v5, you can hang a push off the resource table directly instead of building a custom page.
Notifications as a side effect, not the primary path. Fire the push from a domain event/listener rather than inline in a controller action, so a failed push never blocks the user's request.
tomatophp/filament-fcm-driver to ^5.0 for Filament v5 and ^4.0 for v4. Mixing them produces confusing plugin-registration or view errors rather than a clean composer failure.lcobucci/jwt lock is fixed — but only at the constraint. v5 allows laravel-notification-channels/fcm ^5.0 || ^6.0, so installs no longer fail when something else pins lcobucci/jwt 4.x. If you were previously held on an old driver version for this reason, this is the release to upgrade for.filament-fcm-driver:install. After upgrading, re-run the command and hard-refresh: browsers cache service workers aggressively, and a stale worker is the #1 cause of "push worked yesterday, not today." If behaviour is still odd, unregister the old worker in DevTools → Application → Service Workers./js/ won't intercept /admin/.storage/app/private must be writable by PHP and readable by the queue worker. In containerised setups where the queue runs as a different user, this is a common silent failure.filament-alerts.queue → no push; user has no token row → no push; token stale → FCM accepts the request but drops the message. Check failed_jobs, then storage/logs/laravel.log, then the token table.config:cache after config edits. Changing the disk or queue name in the config file does nothing until you re-cache in environments that cache config.messagingSenderId/VAPID config used by the browser SDK, and confirm the token was issued by that Firebase project. Cross-project tokens fail without an obvious error at send time.How can I help you explore Laravel packages today?