Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Laravel Webpush Notifications Laravel Package

xcoorp/laravel-webpush-notifications

A Laravel package for sending Web Push notifications to browsers. It integrates with Laravel’s notification system, manages push subscriptions and VAPID keys, and lets you deliver messages even when users aren’t actively on your site.

View on GitHub
Deep Wiki
Context7

Getting Started

This package gives you browser Web Push (the notifications that appear via the service worker, even when the tab is closed) backed by a push_subscriptions table and a Laravel notification channel. It is not FCM/APNs — there is no Google/Apple account involved; you own the VAPID key pair.

First steps:

  1. composer require xcoorp/laravel-webpush-notifications — note that v1.0.3 bumps the dependency constraints to allow Laravel 13. Nothing in the public API changed in this release; the changelog is entirely dependency bumps and lockfile maintenance, so an upgrade from v1.0.2 is a composer update with no code changes. If you are pinned below that, you can still upgrade confidently.
  2. Publish and run migrations: php artisan vendor:publish --tag="webpush-migrations" then php artisan migrate. The table stores an endpoint, a public_key/auth_token pair, and a morph to your user model.
  3. Publish the config and generate keys: php artisan vendor:publish --tag="webpush-config" and php artisan webpush:vapid (or generate externally and set WEBPUSH_VAPID_PUBLIC_KEY, WEBPUSH_VAPID_PRIVATE_KEY, WEBPUSH_VAPID_SUBJECT). Commit the public key to your frontend build; keep the private key in the environment only, and never in a committed .env.example with a real value.
  4. Add the trait to your User model — typically HasPushSubscriptions, exposing a pushSubscriptions() morph-many relation.

Your first useful use case is the simplest one: on page load, register the service worker, call PushManager.subscribe() with the VAPID public key, and POST the resulting subscription JSON to an endpoint that does $request->user()->updatePushSubscription(...). Then send a Notification with the web push channel and watch it land. Get that loop working for one hardcoded user before wiring it into real product events.

Implementation Patterns

Notification channel is the idiomatic path. Define a notification class, add the package's channel to via(), and implement the message builder to return a WebPushMessage (title, body, icon, badge, action buttons, deep-link URL). This keeps web push sitting alongside mail and database in the same class, which is what you want for anything user-facing — one notification, several transports, consistent preferences handling.

Store subscriptions per device, not per user. The morph relation naturally allows many rows per user. Treat each row as a device/browser install and delete on 410 Gone / 404 responses, which the package surfaces. Plan a cleanup job from day one: push endpoints expire constantly, and a table full of dead endpoints slows every broadcast.

Fan-out patterns. For single-user sends, $user->notify(new ...) is fine. For anything bulk (a campaign, a “your report is ready” blast to a segment), use Notification::send() with a chunked cursor query and queue the notification. Web push is fast per-request but you are making one outbound HTTPS call per subscription — 50k subscribers in a request cycle will time out.

Trigger from domain events, not controllers. The pattern that ages best: a listener on OrderShipped or ReportReady dispatches the notification, and the notification decides its own channels. You then add email later without touching the event.

Service worker placement. The service worker file must be served from the site root scope you want to control. Keep the push and notificationclick handlers minimal — display the payload, and on click, focus an existing client or open the deep link. Business logic belongs in the payload, not in the SW.

Local development. Push requires HTTPS (or localhost). Test against a real browser with a real key pair; the Symfony/web-push failure modes are opaque and you will waste an hour if you stub the transport and assume it works.

Gotchas and Tips

  • Silent delivery failures. A push that returns 201 from the push service can still never render — permission revoked, OS-level Do Not Disturb, or the subscription bound to a different browser profile. Do not treat “sent” as “seen” in analytics; rely on the notificationclick handler pinging your own endpoint if you need real engagement data.
  • VAPID key mismatch is the single most common setup bug. Changing keys invalidates every existing subscription — users must re-subscribe. Rotate deliberately, and keep old keys valid during a transition window.
  • iOS Safari requires the site be added to the Home Screen (installed PWA) for web push to work at all, and only on recent iOS. Feature-detect and hide your “enable notifications” prompt rather than showing a button that does nothing.
  • Permission prompts. Never call Notification.requestPermission() on page load. Browsers penalise this, and once a user blocks, you cannot re-prompt programmatically — only they can undo it in site settings. Ask behind a user gesture and an explained benefit.
  • Queue the send. The channel makes outbound HTTP calls; wrap your notifications in ShouldQueue. Set a sensible timeout so one dead endpoint does not stall a worker.
  • Payload size is capped at roughly 4 KB encrypted. Long bodies get truncated — keep titles short and put detail behind the deep link.
  • Config caching. WEBPUSH_* values read at boot via config() are baked into the cached config. If you rotate keys in production, php artisan config:cache must be re-run.
  • Extension points: the published config and the notification channel class are the seams. If you need per-user quiet hours, opt-out flags, or topic-based routing, override the channel (or wrap notify() behind a NotificationPreference service) rather than forking the package — nothing in the v1.0.3 release changes those seams, so customisations against v1.0.2 remain valid.
  • Version pinning: given this release is pure maintenance, pin ^1.0 and let dependency bumps flow in via your normal scheduled composer update. There is no migration or config diff to chase here.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
robertmarney/lara-hierarchial-collections
simonschaufi/rule-doc-generator
emissaoja/emissaoja
blackbricksoftware/gravityforms-civicrm-form-processor
al-rahabi/fancy-crud
jinas/dhivatar-component
mltstephane/laravel-quality
bernskiold/laravel-talentlms
bernskioldmedia/laravel-form-architect
youbar/easy-crud
c-point-labs/laravel-hostyourai
dbravoan/dbcms-admin-theme-dbcms
dbravoan/dbcms-theme-db-cyber
dbravoan/dbcms-blocks-basic
dbravoan/dbcms-module-content-audit
dbravoan/dbcms-module-ai-assistant
paygate-to/paygate-php
padosoft/askmydocs-connector-base
defstudio/supercharged-carbon
bernskioldmedia/laravel-matomo