Back to Blog
Lesson 23 of the Intermediate Laravel: Real-World Application Patterns course
LaravelJune 26, 20263 min read

Real-time Notifications with Broadcasting in Laravel

Master real-time notifications with Laravel broadcasting. Learn to configure WebSockets, create broadcast events, and sync your UI using Laravel Echo.

LaravelWebSocketsBroadcastingReal-timeEchoReverbphpbackend

Previously in this course, we explored Introduction to Laravel Events and Listeners for Clean Code to decouple our business logic. In this lesson, we are taking that concept a step further by pushing those events directly to the client's browser, enabling real-time UI updates for our project board.

Understanding Real-time Broadcasting

In a standard HTTP request-response cycle, the client must poll the server to see if anything has changed. This is inefficient. With websockets and broadcasting, the server pushes data to the client the moment an event occurs.

Laravel handles this complexity by providing an abstraction layer. You trigger an event in your backend, and Laravel’s broadcasting system sends it to a driver (like Pusher or a local Soketi/Reverb server), which then pushes it to the connected client.

Configuring Broadcasting

First, ensure your broadcasting.php config file is set up. For local development, many developers prefer Laravel Reverb, which is a first-party, high-performance WebSocket server.

  1. Install Reverb: php artisan install:broadcasting
  2. Update your .env file to use BROADCAST_CONNECTION=reverb.
  3. Start the server: php artisan reverb:start.

This creates a persistent connection between your client and server, allowing for near-instant communication.

Creating Broadcast Events

To make an event broadcastable, it must implement the ShouldBroadcast interface. Let’s evolve our TaskCreated event from our project board project.

PHP
namespace App\Events;

use App\Models\Task;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Queue\SerializesModels;

class TaskCreated implements ShouldBroadcast
{
    use InteractsWithSockets, SerializesModels;

    public function __construct(public Task $task) {}

    public function broadcastOn(): Channel
    {
        #6A9955">// Broadcast to a private channel scoped to the project
        return new \Illuminate\Broadcasting\PrivateChannel('project.' . $this->task->project_id);
    }
}

By implementing ShouldBroadcast, Laravel will automatically queue this event. When the event is dispatched, it serializes the Task model and sends it to the configured WebSocket driver.

Implementing Client-Side Listeners

Now that the backend is broadcasting, we need the frontend to listen. We use Laravel Echo, the companion library for interacting with these broadcasts.

Assuming you have Laravel Echo installed (via npm install laravel-echo pusher-js), add this to your JavaScript entry point:

JAVASCRIPT
import Echo from CE9178">'laravel-echo';
import Pusher from CE9178">'pusher-js';

window.Echo = new Echo({
    broadcaster: CE9178">'reverb',
    key: import.meta.env.VITE_REVERB_APP_KEY,
    wsHost: import.meta.env.VITE_REVERB_HOST,
    forceTLS: false,
});

// Listening for the event
window.Echo.private(CE9178">`project.${projectId}`)
    .listen(CE9178">'TaskCreated', (e) => {
        console.log(CE9178">'New task received:', e.task);
        // Update your UI state here(e.g., append to the task list)
    });

Hands-on Exercise

  1. Modify your existing TaskService from Service-Oriented Task Management: Building Robust Business Workflows to dispatch the TaskCreated event after a task is saved.
  2. Open your browser console and the terminal running php artisan reverb:start.
  3. Trigger a task creation through your API and verify that the JSON payload appears in the client-side console.

Common Pitfalls

  • Forgetting to dispatch the event: Broadcasting only works if the event is actually dispatched. Ensure you are calling event(new TaskCreated($task)) in your service layer.
  • Authorization Failures: If you are using PrivateChannel, your routes/channels.php must define who is allowed to listen. If you don't return true in the callback, the client will never connect.
  • Queue Driver: Broadcasting relies on the queue system. If your QUEUE_CONNECTION is set to sync, your broadcast might feel slow or fail if the WebSocket server isn't responsive. Use redis or database for production-like behavior.

Recap

We've bridged the gap between our backend events and the client UI. By configuring Reverb, implementing ShouldBroadcast on our events, and using Laravel Echo to listen on private channels, we have enabled true real-time capabilities in our project board. This eliminates the need for manual page refreshes and creates a polished, reactive experience for our users.

Up next: We will explore Job Chaining and Batching to handle complex, multi-step background processes efficiently.

Similar Posts