Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

vjupix's avatar

Laravel Reverb: Bidirectional communcation?

Hi,

I was very excited about the first release of Laravel Reverb. I really appreciate the effort to have a first party Laravel package for websocket communcation.

Right from https://reverb.laravel.com it says:

Reverb is a first-party WebSocket server for Laravel applications, bringing real-time communication between client and server directly to your fingertips.

I am not sure if I get the wording/idea right, but I think Laravel Reverb is "just" a first party websocket server written in PHP. All known functionality from Laravel Broadcasting should work with Reverb. But from that statement above I really was hoping that Reverb adds client TO server communcation to Laravel's features as well. But I think that's not true (for now)?

Currently I am working on a project where real-time communcation between a "Laravel Client" and a "Laravel Server" would be beneficial over just using HTTPS. You can imagine the project as a device management application. So there is a central server application that handles many devices in the field (like edge devices). As soon as a device turns on and has a working internet connection it connects to the central server. Because the devices may be in networks behind firewalls or even using cellular connections the communcation needs to be established from the device-side.

After the connection is established the devices should constantly push their diagnostics (like network connectivity, cpu/gpu usage etc..). For this a real-time communcation FROM the device TO the server would be very nice. But if I get it right Larvel Reverb also "just" enables server to client communcation over websockets. So it is like a replacement for Laravel Websockets or Soketi. The mechanisms (pusher, websockets, redis..) are still the same. As well as the communication FROM server TO client.

Or am I missing something here?

Please don't get me wrong: I really like the idea of having a PHP first party package for this and I appreciate all the efforts to create such a package. Also Reverb seems to have "scalability in mind" which is also great. But I still miss bidirectional real-time communcation capabilities in Laravel. This would also be a nice feature to enable real-time communcation between two separate Laravel Apps (microservices!).

1 like
24 replies
giantpopples's avatar

I was also interested in this functionality as I currently use a custom nodejs server with socket.io to have bidirectional communication for a web based game and the documentation does not mention this use case.

I therefore looked at the github repo and I have found some routing services with a Reverb Router and Route classes with static methods for GET/POST/PUT/PATCH/DELETE so I suppose you could register routes in the Laravel Application using the Reverb Route class Laravel\Reverb\Servers\Reverb\Http\Route and thus respond to client side event.

When I have the time I will try to test that, if it works it would be absolutely great 😃 and set Reverb apart from simple server side push events as other services or applications can already do that (I think of Mercure which is meant for server side events with native javascript support and no dependency on pusher protocol)

1 like
giantpopples's avatar

After toying around a little with a fresh laravel 11 install, I have found that you can register a listener that will listen to the Laravel\Reverb\Events\MessageReceived event that has the connection and the json encoded message sent from Echo.

When subscribing to a channel with Echo (via the Echo.channel method) it will return a connection object, you can use connection.pusher.send_event(event, data) method to send something to the laravel application.

There is probably a better solution, and so far I did not look into private channel or authorization, also with this listener you reveive all events, even the ping message that are automatically sent by Echo.

It is promising, but I find it weird to not have documentation about client side event to the server and not between clients as it is one of the key features of websocket since server side events can be implemented without it.

4 likes
vjupix's avatar

Hey @giantpopples interesting findings. This looks promising for extending Reverb for such a functionality. I was not thinking about Laravel Echo for client to server communcation for the first place, but that feature could be useful, too.

Currently I am investigating about communicate between multiple Laravel Backends where one backend acts as some kind of centralized server ("control server"). This would require something like a "Laravel Echo PHP Client". I already managed this functionality using SSE (where one backend just offers a basic HTTP-based SSE endpoint and the "client" Laravel app is listening on those events). But using full-duplex communication would have benefits over SSE when data needs to be exchanged bidirectional in real-time. Let's imagine a central dashboard and all connected client apps constantly push their diagnostic data to a centralized Laravel app.

1 like
giantpopples's avatar

I have just watched Joe Dixon's Laracon EU presentation of Reverb (https://www.youtube.com/watch?v=yrL5eCMpqtc) and he demonstrates client side events to the Reverb server and indeed the mechanism used is the one I described, use the client Echo library to push the event through websocket and listen to the MessageReceived event available through Reverb 😀

Server side communication for backends is more tricky as native php is not a long living process, and a client needs to always be running to listen to events. I don't know if a websocket client exists in PHP but for backend communication I would look into Redis pubsub system and see if there is a long living PHP package that could subscribe to Redis channels as websocket is a web technology made for client/server communication.

2 likes
vjupix's avatar

@giantpopples Thanks for the hint!

Maybe it needs some time for a more integrated way of doing client to server communication but it's good to know that it's already possible using Reverb.

There are websocket clients for PHP like https://amphp.org/websocket-client. Already did some research on using Server Sent Events (SSE) instead. I was able to use a long running artisan command on the "client backend" that listens to SSE Endpoints from another Laravel app. This works but is only unidrectional.

So it would be very nice to integrate some PHP websocket client like mentioned above to work with Reverb. This way a true bidirectional communcation would be possible. Maybe even fully integrated with Laravel's event and broadcasting features.

1 like
nmkd's avatar

@vjupix hi,

I use the same listener as Joe Dixon showed in his presentation. In my console when debugging reverb I receive MessageReceived event but it doesnt even trigger my listener. Maybe I am missing something? Logic is pretty much the same as in presentation

nmkd's avatar

@vjupix There was something wrong in my Echo configuration. I figured it out and now it works. Thanks for response.

1 like
vjupix's avatar

I started on integrating the amphp websocket client with reverb but I have troubles figuring out the reverb websocket endpoints. If I just call laravel using websockets on ws://localhost:8080 (laravel reverb default listening port) I get a 404 and "no http update response found" error from the underlying websocket implementation of amphp.

I think I will try to install laravel Echo next and reverse engineer the requests it makes.

usman350's avatar

Hello, after reviewing the code in the Laravel Reverb repository, I discovered a solution that worked for me. I created a listener named BroadcastMessage, as shown in the example code below:


namespace App\Listeners;

use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Queue\InteractsWithQueue;
use Laravel\Reverb\Events\MessageReceived;

class BroadcastMessage
{
    /**
     * Create the event listener.
     */
    public function __construct()
    {
        //
    }

    /**
     * Handle the event.
     */
    public function handle(MessageReceived $event): void
    {
        $message = json_decode($event->message);
        $data = $message->data;

        if(!$message->event || !$message->event !== 'SendMessage'){
            return ;
        }

        $data = json_decode($data);
    }
}

Ensure that you use the MessageReceived Laravel Reverb event and listen to it in EventServiceProvider.php:

MessageReceived::class => [
    BroadcastMessage::class
], 

Here's an example of sending an event using Laravel Echo with Pusher from the client side:

Echo.connector.pusher.send_event(
      'SendMessage',   // Event Name
       JSON.stringify({message : "Hello from client"}),  // data
       `analytics-project-channel`,  // channel
    );
8 likes
vjupix's avatar

@usman350 Thank you for sharing! After all listening to events on the server side and sending them through pusher.send_event on the JavaScript-side seems to be no big deal. I am still investigating on integrating a backend to backend websocket communication using Laravel Reverb and a PHP websocket client.

1 like
lararara's avatar

@usman350 If you use Laravel 11, there's no more EventServiceProvider by default, instead put it in the AppServiceProvider

public function boot() {
	...
	Event::listen(
            BroadcastMessage::class,
    );
}

To verify it's all working fine, run php artisan event:listen and find

  Laravel\Reverb\Events\MessageReceived ............................................................................................................  
  ⇂ Closure at: /vendor/laravel/pulse/src/Pulse.php:124  
  ⇂ App\Listeners\BroadcastMessage@handle  
voina026's avatar

I've implemented the listener and that works great but now I'm trying to broadcast back again but the job is hanging on an curl request for which I have no clue where or why it is making a curl request. When I broadcast the same event in a command it works fine. Does anyone have a idea?

"local.ERROR: Pusher error: cURL error 28: Operation timed out after 30007 milliseconds with 0 bytes received (see http*://curl.haxx.se/libcurl/c/libcurl-errors.html) for http*://127.0.0.1:6002/apps/215917/events?auth_key=e3exyyljv36cpdoddapb&auth_timestamp=1712242863&auth_version=1.0&body_md5=39cf4da138ab7f442751ec965ad9943c&auth_signature=e445d98a829e55fe188ea4b36bde15218cd56c8968764c3a118d105fb900f2b8."

NJZ's avatar

@voina026 Change your queue connection to database / redis then run artisan queue. Sync queue connection doesn't work with Event listeners

1 like
NJZ's avatar

MessageReceived doesn't seem to work if the running instance of reverb server is a different laravel project from the event listener. I created an Event Listener with reverb's MessageReceived on one laravel project and another Laravel project to run reverb Server. The event listener doesn't trigger reverb's MessageReceived

1 like
NJZ's avatar

@vjupix Thanks. I didn't see that scaling part on the docs.

marciliojunior's avatar

First of all, please forgive me for my limited English... I currently have a Laravel project that uses the Laravel Websockets library (beyond code) precisely because it offers the Custom Handler feature. I need this level of control because, in addition to web clients in this project, there are also .Net clients that connect to the Laravel server through websockets (more precisely, Windows services developed in C#). In short, I am very interested in using Laravel Reverb. I would like to count on you experts to suggest a way to reproduce this concept of "custom Handlers" from the BeyondCode library in Laravel Reverb.

1 like
lararara's avatar

We really need this to be implemented on a first class citizen level. Right now, although we can listen for the messages client side, then handle them via an event listener server side. It's missing a lot of the niceness that the inverse, server to clientside has.

Such as proper authentication, csrf protections etc.

1 like
weelion's avatar

I have successfully retrieved the message from Laravel\Reverb\Events\MessageReceived. Here is the way to register a listener in Laravel 10.x. For Laravel 11.x, please refer to the reply above.

class EventServiceProvider extends ServiceProvider
{
    /**
     * The event listener mappings for the application.
     *
     * @var array<class-string, array<int, class-string>>
     */
    protected $listen = [
        \Laravel\Reverb\Events\MessageReceived::class => [
            \App\Listeners\HandleMessageReceived::class,
        ],
    ];

\App\Listeners\HandleMessageReceived.php

Then clear the cache:

php artisan config:clear
php artisan cache:clear
php artisan event:clear

Restart Reverb and queue:

php artisan reverb:start
php artisan queue:work

You will see the following in laravel.log:

[2025-01-19 21:41:30] local.INFO: {"connection":{},"message":"{\"event\":\"pusher:subscribe\",\"data\":{\"auth\":\"xxx:xxxx\",\"channel\":\"private-user.1\"}}"} 
1 like
marciliojunior's avatar

@weelion Amazing progress. I believe the last peace of the puzzle is get information about the user connection Id that sent the message. Or already has this information on the $event object?

vjupix's avatar
Level 2

Hey all, @lararara If you use private channels and the client is sending a message over that channel and you use Reverb's event listener to handle that incoming message there is no need for CSRF/authentication. On a private channel a user is already authenticated. So if you listen for an incoming message you can get the channel out of the message's json string (channel-property). And CSRF protection should not be an issue, because this is a websocket connection not http(s).

@marciliojunior The mssage contains all information you need. If the user sent a message on a private channel you get the channel-name from the event-payload (channel-property). If you want to "talk back" to the user - just use Laravel`s default Broadcasting and dispatch an event with Broadcasting enabled on the same channel.

I also had some progress on implementing a PHP "Echo Client" that is able to make a websocket connection to a remote Laravel application that serves Reverb.

I got this working:

  1. Websocket connection (initialization)
  2. Private channel subscription using Laravel Sanctum API tokens for authentication
  3. Receiving messages on the "client" application
  4. Sending messages from the "client" application to the remote server (running reverb)
  5. Sending/receiving messages on the remote server using the Reverb Event Listener and Broadcast Events

With this setup it is possible to have a persistent duplex connection between two (or more) Laravel applications. A bit like a pub/sub broker like redis but with authentication and authorization already included.

This is how I do it on the "client" application:

It is not ideal (I "misuse" the cache to check for new messages to be send every two seconds) but it works.

2 likes

Please or to participate in this conversation.