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 Ably Broadcaster Laravel Package

springboardvr/laravel-ably-broadcaster

An Ably broadcaster driver for Laravel that plugs Ably’s realtime messaging into Laravel’s broadcasting system, enabling events to be sent to public, private, and presence channels with minimal configuration. Add scalable realtime features to your PHP app quickly and reliably.

View on GitHub
Deep Wiki
Context7

Getting Started

  1. Install and pin. The repo is archived and the last tag is 1.2.0 (Sep 2020, Laravel 8 support only), so pin rather than float:

    composer require springboardvr/laravel-ably-broadcaster:^1.2
    composer why springboardvr/laravel-ably-broadcaster   # confirm what resolved
    

    If auto-discovery is enabled, the service provider registers the ably driver with BroadcastManager. Check composer.json → extra.laravel.providers and confirm the class appears in bootstrap/cache/packages.php after php artisan package:discover.

  2. Add a connection in config/broadcasting.php — this is the only config the package needs:

    'connections' => [
        'ably' => [
            'driver' => 'ably',
            'key'    => env('ABLY_KEY'),  // server-side API key, never VITE_/EXPO_PUBLIC_
        ],
        // ...existing pusher/redis/log entries
    ],
    
  3. Switch the default. On a Laravel 8-era app this is BROADCAST_DRIVER=ably in .env; if you have since moved to Laravel 10.17+/11 this key is BROADCAST_CONNECTION. Then php artisan config:clear.

  4. Look first at your existing ShouldBroadcast events, not at this package. The driver is drop-in — nothing in your event classes, controllers, or broadcastOn() / broadcastWith() methods changes. Inventory what you already broadcast (grep -r ShouldBroadcast app/) and pick the least critical one.

  5. First use case: take one existing private-channel event (e.g. OrderShipped on PrivateChannel('orders.'.$order->id)), flip BROADCAST_DRIVER=ably, fire it from php artisan tinker (broadcast(new OrderShipped($order))), and watch the Ably Dev Console. You should see a message land on the channel with the event name from broadcastAs(). That single round-trip validates Composer resolution, provider discovery, config caching, outbound HTTPS to Ably's REST endpoint, and channel naming — in that order of likely failure.

Implementation Patterns

Reuse the events you already have. Nothing about the driver changes the Laravel side. Keep writing what you already write:

class OrderShipped implements ShouldBroadcast
{
    public function __construct(public Order $order) {}

    public function broadcastOn(): array
    {
        return [new PrivateChannel('orders.'.$this->order->id)];
    }

    public function broadcastAs(): string
    {
        return 'order.shipped';      // short name — much easier to match client-side
    }

    public function broadcastWith(): array
    {
        return ['id' => $this->order->id, 'status' => $this->order->status]; // small payload
    }
}

Always set broadcastAs(). The default event name is the FQCN (App\Events\OrderShipped), which is awkward to subscribe to from Ably's own JS client and easy to get wrong through Echo's namespace mangling. A short dotted name (order.shipped) removes an entire class of silent-mismatch bugs.

Choose ShouldBroadcastNow deliberately. Plain ShouldBroadcast is queued — a broken Ably key or unreachable network surfaces as a failed job minutes later, not a 500. For UI-critical events (auth handshakes, toOthers() notifications) use ShouldBroadcastNow; for high-volume feeds stay queued and monitor failed jobs.

Private/presence auth runs through /broadcasting/auth. Keep your routes/channels.php callbacks untouched:

Broadcast::channel('orders.{orderId}', fn (User $u, int $orderId) =>
    $u->id === Order::find($orderId)?->user_id
);

Verify BroadcastServiceProvider (or your equivalent) is registered so the /broadcasting/auth route exists. The client hits that endpoint exactly as it did for Pusher.

Echo on the client. Laravel Echo has no native Ably adapter; the standard pattern is Echo's Pusher driver pointed at Ably's Pusher-compatible endpoint, with authEndpoint unchanged:

window.Echo = new Echo({
  broadcaster: 'pusher',
  key: import.meta.env.VITE_ABLY_KEY,      // Ably *public* key or token-request key
  wsHost: 'realtime-pusher.ably.io',
  wsPort: 443,
  forceTLS: true,
  encrypted: true,
  disableStats: true,
  authEndpoint: '/broadcasting/auth',
  // namespace: false,   // <-- see Gotchas
});

Echo.private(`orders.${orderId}`).listen('.order.shipped', handler);

If you use Ably's native JS client instead, skip Echo entirely and subscribe with the exact channel + event names the driver emits (channel.subscribe('order.shipped', cb)), obtaining an Ably token from the same /broadcasting/auth flow.

Hide the driver behind one class. Even though it's drop-in, put a thin adapter between your domain and broadcast():

final class RealtimePublisher
{
    public function orderShipped(Order $o): void { broadcast(new OrderShipped($o)); }
    public function orderShippedNow(Order $o): void { broadcast_now(new OrderShipped($o)); }
}

When you fork the archived package or swap to ably/ably-php behind a custom Broadcast::extend('ably', ...) driver (very likely within a year given the archive status), one class changes.

Notifications use the same driver. Notification::send() with the broadcast channel routes through BROADCAST_DRIVER; nothing extra to wire. Just ensure each notification's toBroadcast() payload stays small.

Gotchas and Tips

  • Archived ≠ broken, but plan the exit. No Laravel 9/10/11 support is advertised. Before committing, run your suite against the exact target version; if you're on Laravel 11, assume you'll need a custom driver. The auth contract for broadcasters (auth() / validAuthenticationResponse()) is the most likely breakage point. Write the adapter class now so the replacement is a one-file change.
  • Channel-name round-tripping is the #1 silent failure. Laravel private channels land on the wire with a private- prefix in Echo/Pusher semantics; verify what the driver actually sends to Ably (subscribe in the Dev Console and compare) and subscribe client-side with the exact same string. Mismatch produces no error — just no message. Presence channels have the same trap with presence-.
  • Echo's default namespace is App.Events and silently prefixes listened event names. Combined with a dotted broadcastAs() name and Echo's leading-dot alias (.order.shipped = "don't prefix"), this is a recipe for missed events. Either set namespace: false or always use the leading dot.
  • Ably messages are size-capped (default ~16 KiB realtime). broadcastWith() returning an Eloquent model with relations will blow this quickly. Always return IDs + scalars; let the client re-fetch via your API. A too-large payload fails on the Ably side and, for queued events, only shows up as a failed job.
  • toOthers() is unreliable across Pusher-compat bridges because it requires a socket ID the driver may not receive from Ably. Test it explicitly; if it's broken, fall back to putting the sender's ID in the payload and filtering client-side.
  • Queued events only fail in the queue. After switching drivers, tail storage/logs/laravel.log and the failed-jobs table for 24h — a bad key doesn't fail the HTTP request for ShouldBroadcast.
  • Outbound firewall: the server needs 443 to Ably's REST host, not just the client WS host. A request-path ShouldBroadcastNow with a blocked egress is a hard 500; that's actually a good canary for day one.
  • Config caching bites twice. After editing config/broadcasting.php or .env: php artisan config:clear locally, then php artisan config:cache in staging/prod. A stale broadcasting.php cache is the most common "it worked on my machine" report.
  • Testing: Event::fake() asserts the event dispatched, never that Ably received anything — it won't catch driver regressions. For that, bind a fake Broadcaster ($app->instance(BroadcastManager::class, $fake)) or mock AblyBroadcaster::broadcast(), and keep one opt-in integration test hitting a sandbox Ably app.
  • Debugging checklist, in order: provider in bootstrap/cache/packages.php → php artisan about shows the connection → config not cached → broadcast(new TestEvent) from tinker succeeds → message visible in Ably Dev Console → client subscribed to the exact channel/event string. Stop at the first failing step; don't re-check later ones.
  • Extension point to use, not vendor/ edits: Broadcast::extend('ably', fn ($app, $config) => ...) in your own AppServiceProvider lets you override or replace the driver without forking — do this before the package's own registration if you need to shadow it. Avoid subclassing the package's broadcaster class; its internals are the least stable surface and won't survive a fork.
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