andreshg112/pusher-api-notifications
Laravel notification channel for sending push notifications through Pusher's API. Integrate a Pusher driver with Laravel's notification system, configure credentials, and target devices or interests using simple, queueable notification classes.
This is a small, single-purpose Laravel notification channel that wraps Pusher's HTTP API. Before you write a line of code, confirm two things: (1) which Pusher product it targets — Channels (/apps/{id}/events publish) or Beams (push to devices via interests/tokens) — by reading the channel class in src/, and (2) the Laravel/PHP constraints in composer.json. The last release was September 2023 and the repo is archived, so expect illuminate/* constraints that stop at Laravel 10.
Install and configure (expected shape):
composer require andreshg112/pusher-api-notifications
php artisan vendor:publish --tag=pusher-api-notifications
Then populate the published config (almost certainly config/pusher-api-notifications.php) with your Pusher app credentials — app_id, key, secret, cluster, useTLS — and mirror those in .env (PUSHER_APP_ID, PUSHER_APP_KEY, PUSHER_APP_SECRET, PUSHER_APP_CLUSTER). These are the standard pusher/pusher-php-server constructor arguments, so the env names will look familiar and will likely collide conceptually with config/broadcasting.php.
Where to look first, in order:
composer.json — Laravel/PHP version floors. This is the make-or-break file for a 2023 archive.src/ — this is the entire package. It will be small; read it fully.README.md — installation and a single usage example, usually.First use case: a queued notification fired on a domain event, delivered to a user's private channel so a Laravel Echo listener picks it up.
class OrderShipped extends Notification implements ShouldQueue
{
public function via($notifiable): array
{
return [PusherApiChannel::class];
}
public function toPusherApi($notifiable)
{
return PusherApiMessage::create()
->channel("private-user.{$notifiable->id}")
->event('order.shipped')
->data(['order_id' => $this->order->id]);
}
}
If that compiles and fires, you've validated the whole package. If it doesn't, you've spent an hour learning to use the official SDK directly instead — which is the more likely correct outcome.
Notification-as-event-bus. The best fit for this package is not "push notifications" but "realtime domain events" — order shipped, invoice paid, deploy finished, import complete. Define one message class per event so the payload contract lives in a single typed place, and let the notification class handle routing (who gets it).
On-demand notifiers. For events with no user model (system alerts, tenant-wide broadcasts), use the anonymous notifier route rather than inventing a fake notifiable:
Notification::route('pusher-api', 'private-ops')
->notify(new DeployFinished($release));
This requires the channel to implement toPusherApi on an anonymous notifiable; verify it reads the route value rather than a model property.
Queue everything. The channel performs a synchronous HTTP call to Pusher. Always implement ShouldQueue on the notification and, if you're fanning out to many recipients, use Notification::send() with a queue connection tuned for it. Without this, a Pusher timeout becomes a user-facing 500.
Compose with other channels. The package earns its keep as one channel among several:
public function via($notifiable): array
{
return ['mail', 'database', PusherApiChannel::class];
}
Realtime + email + database gives you the UI toast, the permanent record, and the inbox — with Pusher only responsible for the ephemeral one.
Testing pattern. Use Notification::fake() and assert on the notification class rather than on Pusher:
Notification::fake();
$this->post('/orders')->assertOk();
Notification::assertSentTo($user, OrderShipped::class);
For channel-level tests, bind a fake or swap the underlying Pusher client with a mock and assert the publish call arguments — but note the package may instantiate Pusher\Pusher internally with new, which makes that hard. If it does, that's another reason to prefer a hand-rolled channel where the SDK client is injected.
Frontend integration. With Pusher Channels, pair this with Laravel Echo (pusher or pusher-js + laravel-echo) subscribing to the same channel name the message targets. Private and presence channels still authenticate through Laravel's /broadcasting/auth route and your routes/channels.php — this package publishes, it does not authorize subscribers. Getting the channel naming convention aligned between the message class and channels.php is the integration step that bites most often.
Migration path if you outgrow it. A drop-in replacement is roughly fifty lines: a notification channel class that type-hints Pusher\Pusher, plus a fluent message DTO. The official pusher/pusher-php-server package does the actual work either way; this package is a thin convenience wrapper. If you need options the DTO doesn't expose — socket_id to exclude the originating client, multi-channel publish via triggerBatch, Beams apns/fcm payload blocks — you will end up calling the SDK directly regardless.
The archive status is the headline gotcha. Eighteen stars, zero dependents, no release since September 2023, no maintainer. There will be no Laravel 11/12 compatibility patch and no security response. Treat every install as a fork: either vendor the one class you need into app/Notifications/Channels/ (MIT license permits it, keep the attribution) or budget for replacing it. For a package this thin, copying is cheaper than depending.
Credential duplication. You will almost certainly end up with Pusher credentials in both config/broadcasting.php and this package's config. Drift here produces the maddening failure mode where broadcasting works but notifications silently fail, or vice versa. Source both from the same env vars and never hardcode. Better: check whether the channel can read config('broadcasting.connections.pusher') directly.
Laravel version constraints will block the install. The 2023 release predates Laravel 11. If composer require fails on illuminate/support, don't fight it with --ignore-platform-reqs in production — that's how you get a package calling removed framework APIs at runtime.
Publish ≠ authorize. The channel pushes an event to a channel name. It does not register the authorization callback, does not know about routes/channels.php, and will happily publish to private-user.5 for a user who can never subscribe. Subscription failures are Pusher-side (AuthError in the browser console), not package-side — debug them in the Pusher debug console and the Echo client, not in Laravel logs.
Payload limits are real. Pusher Channels caps event payloads at ~10KB and caps message rate by plan tier. A notification that serializes an entire Eloquent model (or a collection of them) will fail intermittently under load rather than immediately. Send IDs and fetch on the client, or send a minimal projection.
Errors are thrown, not swallowed. The underlying SDK throws Pusher\ApiErrorException / Pusher\PusherException. In a queued notification that means retries and then a failed_jobs entry — which is correct behavior, but make sure your failed() handler doesn't re-trigger the same notification. In a synchronous path, wrap in try/catch so a Pusher outage doesn't fail the whole request.
Debugging. Enable the SDK's logging or the Pusher debug console. Locally, the fastest signal is whether the HTTP call leaves the app at all — Http::fake() or a network trace will tell you whether the problem is credentials (401), channel config (403), or subscription auth (the client side).
Extension points are the DTO and the container binding. Nearly all customization happens in the message class. If you need behavior the package doesn't offer, don't subclass the channel — register your own via Notification::extend() or bind a replacement implementation, keeping the package's message API stable so a later swap is a one-line change in via().
Verdict for day-to-day use: this is not a package to build on. If you're greenfield, use Laravel's built-in broadcast notification channel with the Pusher broadcaster — same Pusher API, zero extra dependencies, maintained by the framework, and it handles broadcastAs(), broadcastWith(), and broadcastOn() cleanly. Reach for this package only if you're already on it and migrating is more expensive than wrapping it.
How can I help you explore Laravel packages today?