Skip to main content
Create your own
Lesson illustration

Broadcasting to Channels

Hello! Welcome back.

In our last lesson, we laid all the essential groundwork by configuring your Laravel application, the Reverb WebSocket server, and the Laravel Echo client. You now have a live, persistent communication pipeline between your backend and the browser, and you know how to verify that it's working.

Today, we'll put that pipeline to work. This lesson focuses on the core of broadcasting: sending events to specific channels. We'll explore the critical difference between public channels, which are open to anyone, and private channels, which are secure and require authorization. Mastering this distinction is fundamental to building robust, real-time features.

By the end of this 60-minute lesson, you will be able to broadcast events to public and private channels, controlling who receives your real-time updates.


1. Understanding Broadcast Channels

Before we write any code, let's solidify the concept of channels. Think of your WebSocket server as a radio tower. A channel is like a specific frequency. When you broadcast a message (an event) on a frequency, only the clients tuned into that same frequency will receive it.

Laravel provides three types of channels, each serving a different purpose.

Laravel Reverb: A Comprehensive Guide to Real-Time Broadcasting

This article from the Twilio blog gives a concise and clear explanation of the three channel types. It's a great way to build a mental model before we dive into the implementation.

Read the sub-section titled 'Broadcasting Channels' and the three channel types it describes: Public, Private, and Presence. Focus on the analogy and the use case for each.

To summarize:

  • Public Channels: Open to all. Perfect for broadcasting information that isn't sensitive, like a public announcement or a live score update on a sports site.
  • Private Channels: Require authorization. Only authenticated users who pass a specific check can listen. This is essential for user-specific notifications, private messages, or updates to a user's own data.
  • Presence Channels: A special type of private channel that is "presence-aware." They not only require authorization but also keep track of who is currently subscribed to the channel. Ideal for chat rooms or "who's online" lists.

Let's see how to implement the two most common types: public and private.


2. Broadcasting to Public Channels

Public channels are the simplest to implement because they don't require any authorization. Let's create an event and broadcast it to a public channel.

Step 1: Define the Broadcast Event

First, generate an event class using Artisan. Let's imagine an event for when a new blog post is published.

php artisan make:event BlogPostPublished

Now, open app/Events/BlogPostPublished.php and make two crucial changes:

  1. Implement the Illuminate\Contracts\Broadcasting\ShouldBroadcast interface. This tells Laravel that this event should be broadcast.
  2. Define the broadcastOn() method. This method must return the channel(s) the event will be sent to.

Here's what the modified class will look like. We'll pass the post's data through the constructor.

<?php

namespace App\Events;

use App\Models\Post; // Assuming you have a Post model
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class BlogPostPublished implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

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

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        return [
            new Channel('posts'),
        ];
    }
}

The key line is new Channel('posts'). We are telling Laravel to broadcast this event on a public channel named posts. Any public properties on the event class (like our $post property) will be automatically serialized and sent as the event's data payload.

Step 2: Dispatch the Event

Now, whenever you create a new post in your application (e.g., in your PostController), you can dispatch the event:

use App\Events\BlogPostPublished;

// ... inside a controller method after a post is saved
$post = Post::create([...]);

BlogPostPublished::dispatch($post);

That's it for the backend! Because you implemented ShouldBroadcast, Laravel's event dispatcher automatically sends this to your queue to be broadcast on the posts channel via Reverb.

On the frontend, you would then use Echo.channel('posts').listen(...) to receive it. We'll cover that in detail in the next lesson.


3. Broadcasting to Private Channels

Private channels are where the real power lies for personalized, real-time experiences. They introduce a critical step: Authorization.

Imagine you have an Order and you want to send status updates. Only the user who owns that order should receive those updates.

Laravel Event Broadcasting with Ably and Private Channels
This diagram shows the flow for a private channel. The Laravel backend dispatches an event, which goes to the WebSocket server (e.g., Reverb). Before a client can listen, it must be authenticated and authorized by Laravel. Only authorized clients receive the message.

Let's walk through the implementation.

Step 1: Define the Private Channel in the Event

First, let's create an OrderStatusUpdated event.

php artisan make:event OrderStatusUpdated

Inside app/Events/OrderStatusUpdated.php, we'll again implement ShouldBroadcast. However, in the broadcastOn() method, we'll instantiate a PrivateChannel instead of a Channel.

<?php

namespace App\Events;

use App\Models\Order;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PrivateChannel; // Use PrivateChannel
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

class OrderStatusUpdated implements ShouldBroadcast
{
    use Dispatchable, InteractsWithSockets, SerializesModels;

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

    /**
     * Get the channels the event should broadcast on.
     *
     * @return array<int, \Illuminate\Broadcasting\Channel>
     */
    public function broadcastOn(): array
    {
        // Note the dynamic {id} parameter in the channel name
        return [
            new PrivateChannel('orders.'.$this->order->id),
        ];
    }
}

Notice the channel name: 'orders.'.$this->order->id. We are creating a unique, private channel for each specific order. This is a common and powerful pattern.

Step 2: Authorize the Channel

When your frontend tries to listen to orders.123, Laravel Echo will first make an HTTP request to your application to ask: "Is the currently logged-in user allowed to listen to this channel?"

You define the logic for this answer in routes/channels.php.

Broadcasting - Authorizing Channels

The official Laravel documentation provides the definitive guide to authorizing channels. Pay close attention to the Broadcast::channel method and its callback.

Read the section titled 'Authorizing Channels'. This section explains how to use the routes/channels.php file to define your authorization logic. Focus on the structure of the Broadcast::channel method, its arguments (the user and the wildcard parameters), and the boolean it must return.

Let's add our authorization rule to routes/channels.php:

<?php

use App\Models\Order;
use App\Models\User;
use Illuminate\Support\Facades\Broadcast;

// The wildcard {orderId} matches the number from the channel name 'orders.123'
Broadcast::channel('orders.{orderId}', function (User $user, int $orderId) {
    // Find the order from the database
    $order = Order::find($orderId);

    // Return true if the authenticated user's ID matches the order's user_id
    // Otherwise, return false
    return $user->id === $order->user_id;
});

This callback is the gatekeeper.

  1. Laravel automatically provides the currently authenticated $user. If the visitor is not logged in, the request is automatically rejected with a 403 Forbidden status before this callback is even run.
  2. The {orderId} from the channel name is passed as the second argument.
  3. You return true or false based on your application's logic.

Step 3: See it in Action

This video from the official Laravel channel provides a clear, practical demonstration of setting up a private channel and its authorization.

10 - Broadcasting Events

Watch this demonstration to see how the event, the private channel definition, and the authorization callback all work together.

Watch the segment from 03:13 to 04:28. The presenter implements the ShouldBroadcast interface, defines a private channel in broadcastOn, and then writes the authorization logic in routes/channels.php. This is a perfect visual summary of the steps we just took.

To complete the picture, on the frontend you would use Echo.private('orders.123').listen(...) to subscribe. When you do this, Echo handles the authorization request for you. If the authorization fails, the listen callback will never be triggered.


4. An Introduction to Presence Channels

Presence channels are a powerful enhancement to private channels. They do everything a private channel does, but they also maintain a list of who is currently "present" in the channel.

The changes required are small but significant:

  1. In your event, return an instance of PresenceChannel instead of PrivateChannel.
  2. In your channels.php authorization callback, instead of returning true, you return an array of data about the user if they are authorized. This data is what other members of the channel will see. If they are not authorized, you return null or false.
// In routes/channels.php for a presence channel
Broadcast::channel('chat.{roomId}', function (User $user, int $roomId) {
    if ($user->canJoinRoom($roomId)) {
        // Return user data if authorized
        return ['id' => $user->id, 'name' => $user->name];
    }
    
    // Return null or false if not authorized
    return null;
});

On the frontend, instead of private(), you use join(), which gives you access to special events like here, joining, and leaving.

This video provides an excellent walkthrough of converting a private channel to a presence channel and demonstrates these special frontend events.

Ep50 - Private and Presence Channels

This video from Acadea.io shows a practical example of building a chat feature with a presence channel. It clearly explains the backend and frontend changes needed.

Watch the segment from 06:12 to 10:22. Focus on: How the channels.php authorization callback is changed to return the user instance. How the frontend code uses Echo.join() instead of Echo.private(). The purpose of the here, joining, and leaving methods for managing a list of online users.


5. A Handy Tool: Listing Your Channels

As your application grows, you might have many channel authorization routes defined. Laravel provides a useful Artisan command to see them all at once.

php artisan channel:list
Laravel Artisan Command: Listing Broadcasting Channels
This image shows the output of the `php artisan channel:list` command. It's a great way to verify that your channel routes are registered correctly and to get a quick overview of all the private channels in your application.

Conclusion

You now have the knowledge to direct your real-time events to the correct audience. This control is the key to building sophisticated, secure, and interactive features.

Key Takeaways:

  • Public Channels are created with new Channel('name') and require no authorization. They are for broadcasting to everyone.
  • Private Channels are created with new PrivateChannel('name.{id}') and require an authorization callback in routes/channels.php that returns true or false. They are for broadcasting to specific, authenticated users.
  • Presence Channels are a type of private channel that also tracks who is subscribed. Their authorization callback must return user data instead of a simple boolean.
  • The php artisan channel:list command is a helpful tool for inspecting your registered channel routes.

Up Next:

We've mastered the backend—defining events and authorizing channels to control who can listen. In the next lesson, "Configure Laravel Echo on the frontend to listen for broadcasted events," we will shift our focus entirely to the client-side. You'll learn how to use Laravel Echo to subscribe to these channels, listen for events, and dynamically update your UI with the data you receive.

Can't find a good explanation? Sign up and we'll make it for you

Sign up