laravel-notification-channels/webpush
Laravel notification channel for sending Web Push notifications. Supports VAPID keys, major browsers, rich payload options (title, actions, data, TTL), and easy subscription management on models with automatic cleanup of expired endpoints.
Installation:
composer require laravel-notification-channels/webpush
Add Trait to Model:
Attach HasPushSubscriptions to your User (or any notifiable) model:
use NotificationChannels\WebPush\HasPushSubscriptions;
class User extends Model
{
use HasPushSubscriptions;
}
Publish Assets: Run migrations and config:
php artisan vendor:publish --provider="NotificationChannels\WebPush\WebPushServiceProvider" --tag="migrations"
php artisan vendor:publish --provider="NotificationChannels\WebPush\WebPushServiceProvider" --tag="config"
php artisan migrate
Generate VAPID Keys:
php artisan webpush:vapid
(Add VAPID_SUBJECT for Safari/iOS support, e.g., https://yourdomain.com)
First Notification: Create a notification class:
use NotificationChannels\WebPush\WebPushMessage;
use NotificationChannels\WebPush\WebPushChannel;
class AccountApproved extends Notification
{
public function via($notifiable) { return [WebPushChannel::class]; }
public function toWebPush($notifiable, $notification) {
return (new WebPushMessage)
->title('Approved!')
->body('Your account was approved!');
}
}
config/webpush.php for customization (e.g., automatic_padding, default_encoding).NotificationSent/NotificationFailed for debugging.Frontend (Browser):
PushManager.subscribe().endpoint, keys.p256dh, keys.auth) to Laravel via API.Laravel Backend:
$user->updatePushSubscription($endpoint, $key, $token);
Notification facade:
$user->notify(new AccountApproved());
Notification Handling:
WebPushMessage for classic push or DeclarativeWebPushMessage for modern declarative syntax.->icon('/icon.png')->action('View', 'action_id').Polymorphic Models:
Use HasPushSubscriptions on any model (e.g., Team, Device) by configuring morph_map in config/webpush.php:
'morph_map' => [
'users' => \App\Models\User::class,
'teams' => \App\Models\Team::class,
],
Batch Sending: Send to multiple users:
Notification::send($users, new AccountApproved());
Dynamic Data: Pass custom data to the frontend:
->data(['order_id' => 123, 'status' => 'shipped'])
Declarative Messages:
Use DeclarativeWebPushMessage for silent notifications or navigation:
->navigate('https://app.com/dashboard')
->silent()
Fallbacks:
Combine with email/SMS in via():
public function via($notifiable) {
return [WebPushChannel::class, MailChannel::class];
}
Testing: Mock subscriptions in tests:
$user->updatePushSubscription('test_endpoint', 'test_key', 'test_token');
VAPID Keys:
VAPID_SUBJECT causes BadJwtToken errors. Use a valid domain (e.g., https://yourdomain.com).Subscription Expiry:
$user->pushSubscriptions()->where('endpoint', $endpoint)->exists();
Browser Support:
VAPID_SUBJECT and may have limited features.Payload Size:
Service Worker:
push events and displays notifications:
self.addEventListener('push', (event) => {
event.waitUntil(
self.registration.showNotification(event.data.json().title, {
body: event.data.json().body,
icon: event.data.json().icon,
})
);
});
Failed Notifications:
Listen for NotificationFailed events:
event(new NotificationFailed($user, $notification, $exception));
Check exception->getMessage() for errors (e.g., InvalidVapidSignature).
Log Reports:
Enable debug mode in config/webpush.php:
'debug' => env('APP_DEBUG', false),
WebPush-PHP Logs:
Set WP_LOG_LEVEL in .env:
WP_LOG_LEVEL=debug
Custom Report Handler:
Extend ReportHandler to log failed sends:
use NotificationChannels\WebPush\ReportHandler;
class CustomReportHandler extends ReportHandler
{
public function handle($report) {
Log::error('Push failed', ['report' => $report]);
parent::handle($report);
}
}
Register in config/webpush.php:
'report_handler' => \App\Handlers\CustomReportHandler::class,
Custom Message Class:
Extend WebPushMessage for reusable templates:
class AlertMessage extends WebPushMessage
{
public function __construct() {
$this->icon('/alert-icon.png')
->vibrate([200, 100, 200]);
}
}
Dynamic VAPID Keys:
Override getVapidKeys() in a custom service provider:
public function register() {
$this->app->bind('webpush.vapid', function () {
return [
'publicKey' => config('services.vapid.public_key'),
'privateKey' => config('services.vapid.private_key'),
'subject' => config('services.vapid.subject'),
];
});
}
Migration Customization:
Modify the migration table name/columns in config/webpush.php:
'table' => 'push_subscriptions',
'connection' => 'pgsql',
Environment-Specific Keys:
Use .env overrides for staging/production:
VAPID_PUBLIC_KEY=staging_public_key
VAPID_PRIVATE_KEY=staging_private_key
Rate Limiting: Throttle push sends to avoid browser throttling (e.g., 1 push/second per user).
A/B Testing:
Use DeclarativeWebPushMessage for A/B testing notification styles without frontend changes.
Analytics:
Track push open rates by including a campaign_id in data() and logging clicks via your service worker.
Fallback Icons:
Provide multiple icon sizes in config/webpush.php:
'default_icon' => [
'192x192' => '/icons/icon192.png',
'512x512' => '/icons/icon512.png',
],
How can I help you explore Laravel packages today?