Real-Time with Laravel (Pusher & Broadcasting)
Laravel provides a powerful broadcasting system that makes it easy to build real-time applications. In this lesson, we'll explore how to use Laravel's broadcasting features with Pusher and Laravel Echo.
Understanding Laravel Broadcasting
Laravel's broadcasting system allows you to broadcast server-side events to client-side JavaScript applications using WebSockets.
Note: Laravel Broadcasting abstracts away the complexity of WebSocket implementations, allowing you to focus on your application logic.
Setting Up Pusher
First, install the Pusher PHP SDK:
composer require pusher/pusher-php-server
Configure your broadcasting driver in .env:
BROADCAST_DRIVER=pusher
PUSHER_APP_ID=your-app-id
PUSHER_APP_KEY=your-app-key
PUSHER_APP_SECRET=your-app-secret
PUSHER_APP_CLUSTER=mt1
Update config/broadcasting.php to ensure Pusher is configured:
'pusher' => [
'driver' => 'pusher',
'key' => env('PUSHER_APP_KEY'),
'secret' => env('PUSHER_APP_SECRET'),
'app_id' => env('PUSHER_APP_ID'),
'options' => [
'cluster' => env('PUSHER_APP_CLUSTER'),
'useTLS' => true,
],
],
Creating Broadcast Events
Generate a new broadcast event:
php artisan make:event MessageSent
Implement the event class:
<?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 MessageSent implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public $user;
public function __construct($message, $user)
{
$this->message = $message;
$this->user = $user;
}
public function broadcastOn()
{
return new Channel('chat');
}
public function broadcastAs()
{
return 'message.sent';
}
public function broadcastWith()
{
return [
'message' => $this->message,
'user' => $this->user->name,
'timestamp' => now()->toDateTimeString(),
];
}
}
Tip: Use broadcastAs() to customize the event name that clients listen for, and broadcastWith() to control what data is sent.
Broadcasting Events
Dispatch the event from your controller:
use App\Events\MessageSent;
public function sendMessage(Request $request)
{
$message = $request->input('message');
$user = auth()->user();
// Save message to database
$chat = Chat::create([
'user_id' => $user->id,
'message' => $message,
]);
// Broadcast the event
broadcast(new MessageSent($message, $user));
return response()->json(['success' => true]);
}
Private Channels
For user-specific broadcasts, use private channels:
public function broadcastOn()
{
return new PrivateChannel('user.' . $this->user->id);
}
Define authorization logic in routes/channels.php:
Broadcast::channel('user.{userId}', function ($user, $userId) {
return (int) $user->id === (int) $userId;
});
Presence Channels
Presence channels are perfect for showing who's online:
use Illuminate\Broadcasting\PresenceChannel;
public function broadcastOn()
{
return new PresenceChannel('chat.room');
}
Authorize presence channels:
Broadcast::channel('chat.room', function ($user) {
return [
'id' => $user->id,
'name' => $user->name,
'avatar' => $user->avatar_url,
];
});
Setting Up Laravel Echo
Install Laravel Echo and Pusher JS on the frontend:
npm install --save laravel-echo pusher-js
Configure Echo in resources/js/bootstrap.js:
import Echo from 'laravel-echo';
import Pusher from 'pusher-js';
window.Pusher = Pusher;
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
forceTLS: true
});
Listening to Events with Echo
Listen for public channel events:
Echo.channel('chat')
.listen('.message.sent', (e) => {
console.log('New message:', e.message);
console.log('From:', e.user);
// Update UI with new message
appendMessage(e.user, e.message, e.timestamp);
});
Listen to private channels:
Echo.private('user.' + userId)
.listen('NotificationSent', (e) => {
showNotification(e.title, e.message);
});
Warning: Private channels require authentication. Make sure your user is logged in and the /broadcasting/auth route is accessible.
Working with Presence Channels
Join a presence channel and track users:
Echo.join('chat.room')
.here((users) => {
console.log('Currently online:', users);
updateOnlineUsersList(users);
})
.joining((user) => {
console.log(user.name + ' joined');
addUserToList(user);
})
.leaving((user) => {
console.log(user.name + ' left');
removeUserFromList(user);
})
.listen('.message.sent', (e) => {
appendMessage(e.user, e.message, e.timestamp);
});
Client Events
Send client-to-client events (only on presence/private channels):
// Send typing indicator
Echo.join('chat.room')
.whisper('typing', {
name: currentUser.name
});
// Listen for typing indicators
Echo.join('chat.room')
.listenForWhisper('typing', (e) => {
showTypingIndicator(e.name);
});
Tip: Client events (whispers) don't hit your server, making them perfect for ephemeral states like typing indicators or cursor positions.
Broadcasting Notifications
Laravel notifications can be broadcast automatically:
<?php
namespace App\Notifications;
use Illuminate\Notifications\Notification;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
class NewFollower extends Notification implements ShouldBroadcast
{
public function via($notifiable)
{
return ['broadcast', 'database'];
}
public function toBroadcast($notifiable)
{
return [
'follower_name' => $this->follower->name,
'follower_avatar' => $this->follower->avatar_url,
];
}
}
Listen for notifications:
Echo.private('App.Models.User.' + userId)
.notification((notification) => {
console.log('Notification received:', notification);
showToast(notification.follower_name + ' followed you!');
});
Queue Broadcasts for Better Performance
Use ShouldBroadcastNow for immediate broadcasts or queue them:
// Immediate broadcast
class MessageSent implements ShouldBroadcastNow
{
// ...
}
// Queued broadcast (better for high traffic)
class MessageSent implements ShouldBroadcast
{
// ...
}
Exercise: Create a Laravel application with real-time notifications. When a user creates a new post, broadcast a notification to all followers. Use presence channels to show which followers are currently online. Implement a "typing" indicator for comments using client events.