This website is currently under active development (Beta) 🚀. Some features are still work in progress.
Laravel Tutorial

Mastering Laravel Echo: Build Real-time Applications with Ease

Admin User
Admin User
May 18, 2026
4 min read

Key Takeaways

  • # Mastering Laravel Echo: Build Real-time Applications with Ease
  • Building real-time features like live chat, notifications, and dynamic dashboards used to be a...

Mastering Laravel Echo: Build Real-time Applications with Ease

Building real-time features like live chat, notifications, and dynamic dashboards used to be a complex task, often involving intricate WebSocket implementations. Thanks to Laravel, and specifically Laravel Echo, this process has been drastically simplified. Laravel Echo is a powerful JavaScript library that provides a clean and elegant API for subscribing to channels and listening for events broadcast by your Laravel application.

In this detailed tutorial, we'll dive into Laravel Echo, covering its setup, configuration, and practical usage to bring real-time capabilities to your Laravel projects.

What is Laravel Echo? #

Laravel Echo is a client-side JavaScript library that integrates seamlessly with Laravel's broadcasting system. It allows you to easily subscribe to various channels (public, private, presence) and react to events broadcast by your backend. It supports popular WebSocket drivers like Pusher, Ably, and Redis (via laravel-websockets or Soketi), abstracting away the complexities of low-level WebSocket programming.

Prerequisites #

Before we begin, ensure you have the following:

  • A working Laravel application (version 8.x or higher is recommended).
  • Node.js and npm/Yarn installed.
  • Composer installed.
  • A broadcasting service account (e.g., Pusher, Ably). For this tutorial, we will use Pusher.

Step 1: Server-Side Setup (Laravel Broadcasting) #

First, we need to configure our Laravel application to broadcast events.

1. Install Pusher PHP SDK #

Install the Pusher PHP SDK via Composer:

composer require pusher/pusher-php-server

2. Configure Broadcasting Driver #

Open your .env file and set BROADCAST_DRIVER to pusher:

BROADCAST_DRIVER=pusher
PUSHER_APP_ID=YOUR_APP_ID
PUSHER_APP_KEY=YOUR_APP_KEY
PUSHER_APP_SECRET=YOUR_APP_SECRET
PUSHER_APP_CLUSTER=YOUR_APP_CLUSTER

Replace YOUR_APP_ID, YOUR_APP_KEY, YOUR_APP_SECRET, and YOUR_APP_CLUSTER with your actual Pusher application credentials. You can find these on your Pusher dashboard.

3. Uncomment Broadcast Service Provider #

Open config/app.php and uncomment the App\Providers\BroadcastServiceProvider::class line:

'providers' => [
    // Other Service Providers...
    App\Providers\BroadcastServiceProvider::class,
],

This provider contains the necessary logic to register broadcasting routes and services.

4. Run Migrations (Optional, for Authentication) #

If you plan to use private or presence channels (which require authentication), ensure you have a users table and a User model, typically set up by default in new Laravel projects. If not, run:

php artisan migrate

Step 2: Client-Side Setup (Laravel Echo) #

Now, let's set up Laravel Echo in our frontend JavaScript.

1. Install Laravel Echo and Pusher JS #

Install the necessary npm packages:

npm install --save-dev laravel-echo pusher-js

2. Initialize Echo #

Open resources/js/bootstrap.js (or resources/js/app.js if you prefer) and add the following code to initialize Laravel Echo. This file is typically loaded by your app.blade.php layout.

import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

window.Pusher = Pusher;

window.Echo = new Echo({
    broadcaster: 'pusher',
    key: import.meta.env.VITE_PUSHER_APP_KEY,
    cluster: import.meta.env.VITE_PUSHER_APP_CLUSTER ?? 'mt1',
    wsHost: import.meta.env.VITE_PUSHER_HOST ? import.meta.env.VITE_PUSHER_HOST : `ws-${import.meta.env.VITE_PUSHER_APP_CLUSTER}.pusher.com`,
    wsPort: import.meta.env.VITE_PUSHER_PORT ?? 80,
    wssPort: import.meta.env.VITE_PUSHER_PORT ?? 443,
    forceTLS: (import.meta.env.VITE_PUSHER_SCHEME ?? 'https') === 'https',
    enabledTransports: ['ws', 'wss'],
});

This code configures Echo to use Pusher with the credentials from your .env file (which Vite exposes via import.meta.env).

3. Compile Assets #

Run your build process to compile the JavaScript assets:

npm run dev
# or for production
npm run build

Make sure your resources/js/app.js (or bootstrap.js if imported there) is included in your Blade layout file:

<head>
    <!-- ... -->
    @vite(['resources/css/app.css', 'resources/js/app.js'])
</head>

Step 3: Creating and Broadcasting Events #

Now that Echo is set up, let's create an event and broadcast it.

1. Create an Event #

Generate a new event using the Artisan command:

php artisan make:event NewMessage

2. Implement ShouldBroadcast #

Open app/Events/NewMessage.php and make it implement the ShouldBroadcast interface. Also, define the broadcastOn method to specify the channel(s) this event will be broadcast on.

<?php

namespace App\Events;

use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;

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

    public $message;
    public $username;

    /**
     * Create a new event instance.
     *
     * @return void
     */
    public function __construct($message, $username = 'Guest')
    {
        $this->message = $message;
        $this->username = $username;
    }

    /**
     * Get the channels the event should broadcast on.
     *
     * @return \Illuminate\Broadcasting\Channel|array
     */
    public function broadcastOn()
    {
        return new Channel('chat'); // Public channel named 'chat'
    }

    /**
     * The event's broadcast name.
     *
     * @return string
     */
    public function broadcastAs()
    {
        return 'message.new'; // Custom broadcast event name (optional)
    }

    /**
     * Get the data to broadcast.
     *
     * @return array
     */
    public function broadcastWith()
    {
        return [
            'message' => $this->message,
            'user' => $this->username,
            'time' => now()->toDateTimeString()
        ];
    }
}
  • ShouldBroadcast: This interface tells Laravel that this event should be broadcast.
  • broadcastOn(): This method defines the channel(s) the event will be broadcast on. Here, we use a public Channel named chat.
  • broadcastAs() (Optional): Allows you to customize the event name on the client-side. If omitted, the full class name (App.Events.NewMessage) will be used.
  • broadcastWith() (Optional): Allows you to specify which data from the event should be broadcast. If omitted, all public properties of the event will be broadcast.

3. Dispatch the Event #

You can dispatch this event from anywhere in your Laravel application (e.g., a controller, a service, or a job):

<?php

namespace App\Http\Controllers;

use App\Events\NewMessage;
use Illuminate\Http\Request;

class ChatController extends Controller
{
    public function sendMessage(Request $request)
    {
        $message = $request->input('message');
        $username = auth()->user() ? auth()->user()->name : 'Guest';

        NewMessage::dispatch($message, $username);

        return response()->json(['status' => 'Message sent!']);
    }
}

Step 4: Listening to Events (Client-Side) #

Now, let's write the JavaScript code to listen for these events using Laravel Echo.

1. Public Channels #

Public channels are the simplest. Anyone can subscribe to them without authentication.

// In your JavaScript file (e.g., resources/js/app.js or a Vue/React component)

Echo.channel('chat')
    .listen('message.new', (e) => {
        console.log('New message received:', e.message, 'from', e.user);
        // Add the message to your chat UI
        const messagesContainer = document.getElementById('messages');
        if (messagesContainer) {
            const messageElement = document.createElement('div');
            messageElement.textContent = `${e.user} (${e.time}): ${e.message}`;
            messagesContainer.appendChild(messageElement);
        }
    });

console.log('Listening for new messages on the chat channel...');

Here, Echo.channel('chat') subscribes to the 'chat' public channel, and .listen('message.new', ...) registers a callback for the message.new event (our custom broadcastAs name).

2. Private Channels #

Private channels are secured and require authentication. Only authenticated users authorized to listen on a specific channel can do so. This is perfect for user-specific notifications.

First, modify your event to use a PrivateChannel:

// app/Events/NewMessage.php (example for user-specific message)

use Illuminate\Broadcasting\PrivateChannel;

// ...

public function broadcastOn()
{
    return new PrivateChannel('users.' . $this->userId); // Example: Private channel for a specific user ID
}

// Add a constructor property for userId
public $userId;

public function __construct($message, $userId)
{
    $this->message = $message;
    $this->userId = $userId;
}

Next, define an authorization callback in routes/channels.php. This file is loaded by BroadcastServiceProvider.

// routes/channels.php

use Illuminate\Support\Facades\Broadcast;

Broadcast::channel('users.{userId}', function ($user, $userId) {
    return (int) $user->id === (int) $userId;
});

This callback ensures that only the User whose ID matches $userId can subscribe to the users.{userId} channel.

Finally, listen on the client-side:

// Assuming you have a current_user_id available in your frontend
const userId = document.querySelector('meta[name="user-id"]').getAttribute('content'); // Example: get user ID from a meta tag

if (userId) {
    Echo.private(`users.${userId}`)
        .listen('message.new', (e) => {
            console.log('Private message for user', userId, ':', e.message);
            // Handle private message, e.g., show a notification
        });
    console.log(`Listening for private messages on users.${userId} channel...`);
}

3. Presence Channels #

Presence channels are a specialized type of private channel that inform you who is currently subscribed to the channel. This is ideal for features like

FAQs

What is Laravel Echo and why should I use it?
Laravel Echo is a JavaScript library that makes it incredibly easy to subscribe to channels and listen for events broadcast by your Laravel application. It simplifies the process of building real-time features like live chats, notifications, and dashboards by abstracting away the complexities of WebSockets, allowing developers to focus on application logic.
What's the difference between public, private, and presence channels in Laravel Echo?
Public channels are open for anyone to listen to without authentication. Private channels require authentication to subscribe, making them suitable for user-specific data or restricted access. Presence channels are a type of private channel that tracks who is currently subscribed, ideal for features like showing active users in a chat room or collaborative editing.

Want more content like this?

Explore more tutorials in the Laravel section.

Explore Laravel

You might also like