Summer sale! Save 50% on access to our entire library of courses.Join here →

Setting up Realtime Broadcasting with Laravel and Reverb

July 3rd, 2024

This article covers getting set up with broadcasting real-time events in Laravel from scratch. Once we're done, you'll be able to broadcast events from anywhere in your Laravel application and pick up the data from the client side.

If you prefer to watch, we have a free course covering everything here (and more).

For this article, I'll create a project with the Breeze starter kit (available via laravel new) and demonstrate using Laravel Echo with Alpine.js. However, every step will work regardless of how you've set up your project.

Let's get started!

If you're new to Laravel, the common terminology we'll use in this article is as follows:

  • Broadcasting. This refers to broadcasting events from our backend
  • Events. We broadcast these classes in Laravel. They specify the channel we want to broadcast to and any data we want to broadcast.
  • Channels. The channels we define and listen to. This is where we sent event data.
  • Reverb. This is a WebSocket server built by Laravel. We run this server to receive broadcasted event data.
  • Echo. This client-side JavaScript package connects to our WebSocket server (Reverb) on a channel and listens for events.

Hopefully that's cleared things up. Let's get broadcasting installed.

By default, Laravel doesn't include broadcasting functionality. To install this, run the following command:

php artisan install:broadcasting

Once this command runs, it'll create the broadcasting.php config file and a routes/channels.php file.

You'll also be prompted to install Laravel Reverb. Choose yes.

INFO  Published 'broadcasting' configuration file.
INFO  Published 'channels' route file.

 Would you like to install Laravel Reverb? ───────────────────┐
  Yes /  No                                                 
└──────────────────────────────────────────────────────────────┘

You'll also be prompted to install the Node dependancies. Again, choose yes.

INFO  Reverb installed successfully.

 Would you like to install and build the Node dependencies required for broadcasting? 
  Yes /  No                                                                         
└──────────────────────────────────────────────────────────────────────────────────────┘

Broadcasting is now installed, along with Laravel Reverb and Echo.

On a local machine, we don't need to configure Reverb, but take a look at your .env file anyway.

The first change is that BROADCAST_CONNECTION has been changed to reverb.

BROADCAST_CONNECTION=reverb

This instructs any events you broadcast to be sent to the Reverb connection. These settings are also defined in your .env file.

REVERB_APP_ID=955910
REVERB_APP_KEY=cpcjylkqykmpqjnhuj4s
REVERB_APP_SECRET=stixgunvgag7naamrv0x
REVERB_HOST="localhost"
REVERB_PORT=8080
REVERB_SCHEME=http

VITE_REVERB_APP_KEY="${REVERB_APP_KEY}"
VITE_REVERB_HOST="${REVERB_HOST}"
VITE_REVERB_PORT="${REVERB_PORT}"
VITE_REVERB_SCHEME="${REVERB_SCHEME}"

On a local development environment, it's highly unlikely you'll need to change anything here.

Note the VITE_ prefixed env keys. These expose the Reverb server information to Vite so js/echo.js can read them. Open up this file and take a look.

window.Echo = new Echo({
    broadcaster: 'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    wsPort: import.meta.env.VITE_REVERB_PORT ?? 80,
    wssPort: import.meta.env.VITE_REVERB_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_REVERB_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
})

As we learned earlier, Laravel Echo is the JavaScript package that allows us to connect to our Reverb server so we're able to listen for events. We'll use this later on.

Open up a terminal tab, it's time to run Reverb! You'll need to leave this running.

php artisan reverb:start

You'll see something like this.

INFO  Starting server on 0.0.0.0:8080 (localhost).

If you need to debug anything, you can also start Reverb with the --debug option. This logs out any connection events and any data being sent to the Reverb server. This is fine for local development, but running this in production isn't advised due to the amount of data that'll be logged out.

php artisan reverb:start --debug

Ok, our Reverb server is running. Now, it's (almost) time to broadcast an event.

We'll start by defining the most basic channel type, a public channel. Anyone can connect to this, and there are no authorization rules around it. If you'd like to learn more about private and presence channels, we have a course covering those in detail.

Open up routes/channels.php and define a new channel like this:

Broadcast::channel('chat', function () {
    //
});

(You'll also notice a App.Models.User.{id} channel defined in here. That's a private channel).

To be honest, that's it! You've just created a channel that we can now broadcast to.

Events in Laravel don't specifically relate to real-time broadcasting, but they can be used to do this too.

If you're new to events in Laravel, these are classes that we can dispatch anywhere in our application and listen to. For example, when a user registers, we might dispatch a UserRegistered event and have a listener defined to send them an email.

Let's focus on real-time, though. Create your event like this:

php artisan make:event Example

Open up the Example event. Here's roughly what it'll look like:

class Example
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    /**
     * Create a new event instance.
     */
    public function __construct()
    {
        //
    }

    public function broadcastOn(): array
    {
        return [
            new PrivateChannel('channel-name'),
        ];
    }
}

The broadcastOn method returns the channels we want to broadcast to. Luckily for us, we've already defined a channel, so update it to use a standard public Channel while updating the name:

public function broadcastOn(): array
{
    return [
        new Channel('chat'),
    ];
}

Next, and really importantly, we need to instruct this event to be broadcastable by implementing the ShouldBroadcastNow interface. Add this to the event:

use Illuminate\Contracts\Broadcasting\ShouldBroadcastNow;

class Example implements ShouldBroadcastNow
{
    //...
}

You'll need to import the namespace at the top, since it's not available by default in the generated event.

You may have noticed a ShouldBroadcast interface namespace in the event. If you implement this interface, your event will be queued before being broadcast. Right now, we're just focused on directly broadcasting to our Reverb server without queueing, so that's why we're using ShouldBroadcastNow.

Where you broadcast events is totally up to you, and depends on what you're building. For the purpose of this article, let's create a web route.

Route::get('/broadcast', function () {
    broadcast(new Example());
});

We use the broadcast function, passing in the Example event to broadcast this.

Feel free to head over to /broadcast in your browser. Nothing will happen yet, and if you don't see an error, you know you're on track, and your event is successfully being broadcast to your Reverb server!

If you see a cURL error here, check your Reverb server is running.

We're successfully broadcasting an event to our WebSocket server, but we need to listen in and pick up the event now. Let's connect to our channel.

Once again, I'm using the Breeze starter kit, which gives us access to Alpine.js. We'll use this to work with Echo, but you're welcome to do this with Livewire, Inertia or any other solution you're using.

Register an account with your application, open up dashboard.blade.php and add the following code anywhere on the page:

<div
    x-init="
        Echo.channel('chat')
    "
>

</div>

Because Laravel Echo is bound to the window object, we're able to access it anywhere.

Reload the page and check your console for any errors. You can also check the network tab in your developer tools, filter by WS (WebSocket) and check you have a 101 status code. If so, this means you're now connected to your Reverb server!

If you're not seeing anything, also make sure you're running npm run dev to compile assets.

Now, we can listen to the Example event we're broadcasting from the backend. Update Echo to listen to the event like this:

<div
    x-init="
        Echo.channel('chat')
            .listen('Example', (event) => {
                console.log(event)
            })
    "
>

Here, we're using the listen method to listen to the class name we gave our event. The callback takes the event data and, in this case, dumps it to the console.

Keeping the dashboard opem, head over to the /broadcast URL in your browser, then return to the dashboard.

You should see an empty array dumped to your console.

[]

Hopefully, your event will roll in, but it's a little empty now. Let's add some data to our event. After all, there's not much point in sending event data to connected clients if there's no data to do anything with.

Open up your Example event class again, and set an example public property.

class Example implements ShouldBroadcastNow
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public $message = 'Hello';

    //...
}

Any public properties you set in your broadcastable events will be sent to your server and thus delivered to all clients.

Head back to /broadcast in your browser and recheck your console for the new event. You should now see an object with the message we just added:

{message: 'Hello'}

Any data you now add to your event will be available to the client. For example, you could pass in an entire model:

Route::get('/broadcast', function () {
    broadcast(new Example(User::find(1)));
});

And in your event:

class Example implements ShouldBroadcastNow
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(public User $user)
    {
        //
    }

    //...
}

Now, when you broadcast this, you'll see the JSON-encoded data from the user:

{
    "user": {
        "id": 1,
        "name": "Alex",
        "email": "alex@codecourse.com",
        "email_verified_at": null,
        "created_at": "2024-07-03T20:50:10.000000Z",
        "updated_at": "2024-07-03T20:50:10.000000Z"
    }
}

One of the most important parts of broadcasting data is not including too much. Firstly, because you're revealing a lot about your model data, and secondly, you may send more data than you need.

To customize what data gets sent with your events, use the broadcastWith method on your event.

class Example implements ShouldBroadcastNow
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

    public function __construct(protected User $user)
    {
        //
    }

    public function broadcastWith(): array
    {
        return [
            'user' => [
                'id' => $this->user->id,
            ]
        ];
    }

Here, I've changed the User we're passing in to protected (since it doesn't need to be a public property anymore), and we're now only revealing the user ID. This is just an example, so customize broadcastWith to output the data you need.

Nice, you're now broadcasting real-time events in Laravel. This is just the start, though, and there's more to learn.

We have some courses on real-time broadcasting with some practical applications that'll put everything nicely into context, like Build a Multi-room Realtime Chat with Livewire and Reverb.

Happy broadcasting!

Thanks for reading! If you found this article helpful, you might enjoy our practical screencasts too.
Author
Alex Garrett-Smith
Share :

Comments

No comments, yet. Be the first to leave a comment.