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

Push Notification Laravel Package

edujugon/push-notification

A Laravel package for sending push notifications through Firebase Cloud Messaging (FCM). Deliver messages to Android and iOS devices—individually, by topic, or in groups—via a simple, expressive API with support for custom data payloads.

View on GitHub
Deep Wiki
Context7

Getting Started

Install the package and let Laravel auto-discover the service provider:

composer require edujugon/push-notification
php artisan vendor:publish --provider="Edujugon\PushNotification\PushNotificationServiceProvider"

Version 5.5.0 adds Laravel 12 support, so the same install works on Laravel 11 and 12 without a composer.json constraint workaround; check that your PHP version satisfies the release's floor (Laravel 12 requires PHP 8.2+) before bumping. Note that "Laravel 12 support" is a framework-compatibility change only — the transport APIs (setService, setMessage, setDevicesToken, send) are unchanged, so nothing in your existing call sites needs rewriting.

This publishes config/pushnotification.php. That file is the first place to look — it defines one array per transport (gcm, fcm, apn) containing the API key / certificate, endpoint URL, and (for APN) the topic. Wire the secrets through .env immediately rather than editing the config directly:

// config/pushnotification.php
'fcm' => [
    'apiKey' => env('FCM_API_KEY'),
    'url'    => 'https://fcm.googleapis.com/fcm/send',
],
'apn' => [
    'certificate' => env('APN_CERT_PATH'),
    'passPhrase'  => env('APN_PASS_PHRASE'),
    'url'         => env('APN_URL', 'https://api.push.apple.com'),
    'topic'       => env('APN_TOPIC'),
],

Your first use case — send a notification to a single device — is three calls behind the facade:

use Edujugon\PushNotification\Facades\PushNotification;

$result = PushNotification::setService('fcm')
    ->setMessage([
        'notification' => ['title' => 'Hello', 'body' => 'World'],
        'data'         => ['order_id' => 42],
    ])
    ->setDevicesToken([$deviceToken])
    ->send();

$result is an array with success (bool) and feedback (the raw provider response). Once that works end to end, the natural second step is sendByTopic() for the FCM/APN topic path, and reading src/Services/ to see exactly how each transport builds its payload — that directory is the ground truth when the README is ambiguous.

Implementation Patterns

Wrap the facade in a single application service. Don't sprinkle PushNotification::setService(...) through controllers. Create an App\Services\PushSender that owns payload shaping, token selection, and response normalization. This gives you one place to swap in a newer API version later and keeps the package's array-based API out of your domain code.

Queue everything. Every send() is a synchronous HTTP call to Google/Apple. A controller that pushes to 5,000 tokens will time out. The idiomatic shape is a job per batch:

class SendPushBatch implements ShouldQueue
{
    use InteractsWithQueue, Queueable;

    public function __construct(public array $tokens, public array $payload) {}

    public function handle(PushSender $sender): void
    {
        foreach (array_chunk($this->tokens, 1000) as $chunk) {
            $sender->sendToDevices('fcm', $chunk, $this->payload);
        }
    }
}

Chunk by provider limit. FCM accepts up to 1,000 registration tokens per request; APN expects one token per request (the package will loop, but that loop is serial and slow). For APN-heavy apps, dispatch one job per token and let the queue workers fan out.

Model device tokens as first-class rows. Store user_id, token, platform, app_version, last_seen_at. Prune on last_seen_at rather than on errors — you'll get stale-token errors as a side effect, not as the primary signal.

Use data-only payloads when you need app logic to run. On FCM, ['data' => [...]] alone delivers silently and your app decides what to render; including notification lets the OS render it when the app is backgrounded. Mixing both causes duplicate notifications on Android — a very common production bug.

Override config per call with setConfig([]) when you need a second Firebase project (e.g. tenant isolation) without redeploying:

PushNotification::setService('fcm')
    ->setConfig(['apiKey' => $tenantKey])
    ->setMessage($payload)
    ->setDevicesToken($tokens)
    ->send();

Feature-test with a fake transport. The package has no built-in fake. Bind your PushSender interface in the container to a recording double in tests, and assert on the payload arrays rather than on network calls. On Laravel 11/12 the container binding in TestCase::setUp() behaves the same as before, so existing fakes port over cleanly.

Gotchas and Tips

  • Check which FCM API your installed version targets. The legacy https://fcm.googleapis.com/fcm/send server-key endpoint was shut down by Google; v5.5.0 is a Laravel-12 compatibility release only, so it does not by itself move you to HTTP v1 with OAuth. Inspect src/Services/Fcm/ before committing — if it's still legacy, you'll hit 404s in production and need the v1 path or a different package.
  • Don't read "Laravel 12 support" as a transport upgrade. The release notes mention nothing about payload shape, auth, or endpoints. Treat v5.5.0 as a drop-in framework bump: run your feature tests against the recording double, and smoke-test one real send per transport in staging before rolling out.
  • APN certificates vs. tokens. The config expects a .pem certificate plus passphrase. Token-based (.p8) auth is generally preferable and, if unsupported, forces you to rotate certificates annually. Confirm which your version supports.
  • Sandbox vs. production APN endpoint. https://api.push.apple.com vs https://api.sandbox.push.apple.com. Sending a dev build's token to production silently returns BadDeviceToken. Split via an env variable scoped per environment.
  • 4 KB payload ceiling. Both FCM and APN reject oversized payloads with a non-obvious error. Validate payload size in PushSender before dispatch; trimming data at the last moment is much better than debugging a 400.
  • The response shape is inconsistent across providers. Always branch on $result['success'] and log $result['feedback'] in full. Providers embed per-token error codes (NotRegistered, Unregistered, BadDeviceToken) inside the feedback; you need those to prune tokens.
  • No retry or backoff is built in. Wrap send() in your own retry policy (e.g. ->retry(3, 1000)) and treat 5xx / 429 as retryable, 4xx-per-token as terminal.
  • config:cache will freeze your .env values. Standard Laravel behavior, but easy to forget when rotating a Firebase key — always php artisan config:clear after deploy. This bites hardest on the Laravel 11/12 upgrade path, where cached config from the old app version is still on disk.
  • Facade state can leak across calls in long-running workers (Octane, queue workers). Re-call setService() and setDevicesToken() every time rather than assuming defaults persist.
  • Debugging checklist: (1) log the exact payload, (2) hit the provider directly with curl using the same key/cert, (3) verify token freshness by round-tripping a token from the device to your DB. Nine times in ten the package is fine and the token is stale.
  • Extension point: subclass or decorate the service classes to add logging, metrics, or v1 API support without forking the vendor tree — composer.json already declares PSR-4 autoloading, so a custom PushSender binding is the cleanest seam.
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.
socialdept/tenant-domains
tautvydasr/blade-class-names
socialdept/color-scales
maherelgamil/controller
coleus/widgets
coleus/table
coleus/users
coleus/music
coleus/health
coleus/calendar
coleus/notes
coleus/support
coleus/settings
coleus/apps
seampact/laravel
emmyconceptng/laravel-ng-postcode
jjsquady/round-robin
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route