Skip to content
Developers · 8 min read

Laravel browser push notifications (no Firebase)

Laravel’s notification system already knows how to send mail and Slack messages. With the community WebPush channel, browser push becomes one more channel — using standard VAPID, no Firebase.

Updated By the Pusharoo team
In short
  • Install laravel-notification-channels/webpush and run its migration.
  • php artisan webpush:vapid writes VAPID keys into your .env.
  • Add HasPushSubscriptions to your User model and save subscriptions from the browser.
  • Return WebPushChannel from via() and build a WebPushMessage in toWebPush().

Install the channel

composer require laravel-notification-channels/webpush php artisan vendor:publish --provider="NotificationChannels\WebPush\WebPushServiceProvider" --tag="migrations" php artisan migrate php artisan webpush:vapid # adds VAPID_PUBLIC_KEY / VAPID_PRIVATE_KEY to .env

Keep the private key out of version control like any other secret (why).

Store subscriptions on users

use NotificationChannels\WebPush\HasPushSubscriptions; class User extends Authenticatable { use Notifiable, HasPushSubscriptions; } // routes/web.php (inside your auth middleware group) Route::post('/push/subscriptions', function (Request $request) { $data = $request->validate([ 'endpoint' => 'required|url', 'keys.p256dh' => 'required|string', 'keys.auth' => 'required|string', ]); $request->user()->updatePushSubscription($data['endpoint'], $data['keys']['p256dh'], $data['keys']['auth']); return response()->noContent(201); });

The browser code that creates the subscription is in the Push API example; pass your VAPID_PUBLIC_KEY to it.

A WebPush notification

use NotificationChannels\WebPush\WebPushChannel; use NotificationChannels\WebPush\WebPushMessage; class OrderShipped extends Notification { public function __construct(public Order $order) {} public function via($notifiable) { return [WebPushChannel::class]; } public function toWebPush($notifiable, $notification) { return (new WebPushMessage) ->title('Your order has shipped 📦') ->body('Arriving ' . $this->order->eta->format('l') . '. Tap to track it.') ->icon('/icon-192.png') ->data(['url' => route('orders.show', $this->order)]); } } $user->notify(new OrderShipped($order));

The service worker

Your public/sw.js needs push and notificationclick handlers that read the payload and open data.url. A complete version is in service worker push events. Make sure your web server and any CDN don’t cache it for long.

Queue it

Implement ShouldQueue on notifications so sending happens in a queue worker, not during the request. The channel removes subscriptions that the push service reports as expired.

The front-end subscribe call

// resources/js/push.js — call from a button click const reg = await navigator.serviceWorker.register('/sw.js'); if (await Notification.requestPermission() === 'granted') { const sub = await reg.pushManager.subscribe({ userVisibleOnly: true, applicationServerKey: urlBase64ToUint8Array(window.VAPID_PUBLIC_KEY) // from config('webpush.vapid.public_key') }); await fetch('/push/subscriptions', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name=csrf-token]').content }, body: JSON.stringify(sub) }); }

Include the CSRF token because the route sits in the web middleware group. The urlBase64ToUint8Array helper is in the Push API example.

Unsubscribing and cleanup

When a user turns notifications off in your settings page, call subscription.unsubscribe() in the browser and $user->deletePushSubscription($endpoint) on the server. Expired endpoints (404/410 from the push service) should also be removed so your sends stay fast; check the package’s events and configuration for the version you install.

For marketing pushes, use a dashboard

The channel is perfect for per-user, transactional notifications. For marketing campaigns to anonymous visitors — segments, schedules, welcome automations — add Pusharoo’s snippet to your Blade layout instead; it’s free and needs no backend code (setup). Many apps use both.

Questions

Does Laravel have built-in browser push?

Not in the core framework. The community laravel-notification-channels/webpush package adds a WebPush channel using the standard protocol.

Can I send Laravel push notifications without Firebase?

Yes. The WebPush channel uses VAPID and the browsers’ own push services; no Firebase project is required.

Can guests (not logged in) receive Laravel push notifications?

The package stores subscriptions on a notifiable model, usually User. For anonymous visitors, store subscriptions on a guest model or use a hosted tool.

More in Developers: The Web Push protocol, explained · Web push notifications with Node.js · Web push notifications in React and Next.js · Declarative Web Push, explained · Firebase web push vs. standard web push · All guides

Free for life. No limits.

Unlimited subscribers, campaigns and automations. No badges. About five minutes to install.