In modern web applications, real-time interactivity is no longer just a luxury—it's an expectation. When users receive a message, complete a task, or get mentioned in a post, they expect immediate feedback without having to refresh the page.
Implementing real-time WebSockets from scratch can be a complex endeavor. However, Laravel elegantly solves this by providing broadcasting capabilities out of the box, seamlessly integrating with services like Pusher. In this tutorial, we will build a real-time notification system in Laravel using Pusher and Laravel Echo.
Step 1: Setting up Pusher
First, head over to Pusher, create an account, and set up a new Channels app. Take note of your app credentials: app_id, key, secret, and cluster.
Next, install the Pusher PHP SDK in your Laravel project:
composer require pusher/pusher-php-server
Open your .env file and configure the broadcast driver and Pusher credentials:
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
Make sure to also enable the BroadcastServiceProvider in config/app.php by uncommenting it in the providers array.
Step 2: Creating the Event
Laravel broadcasts events over WebSockets. Let's create an event that will be triggered when a notification is sent.
php artisan make:event UserNotified
Open the generated UserNotified.php file and implement the ShouldBroadcast interface:
namespace App\Events;
use Illuminate\Broadcasting\Channel;
use Illuminate\Broadcasting\InteractsWithSockets;
use Illuminate\Broadcasting\PresenceChannel;
use Illuminate\Broadcasting\PrivateChannel;
use Illuminate\Contracts\Broadcasting\ShouldBroadcast;
use Illuminate\Foundation\Events\Dispatchable;
use Illuminate\Queue\SerializesModels;
class UserNotified implements ShouldBroadcast
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public $message;
public $userId;
public function __construct($userId, $message)
{
$this->userId = $userId;
$this->message = $message;
}
public function broadcastOn()
{
return new PrivateChannel('user.' . $this->userId);
}
public function broadcastWith()
{
return [
'message' => $this->message
];
}
}
This event broadcasts on a private channel, ensuring only the intended user receives the notification.
Step 3: Authorizing the Channel
Since we are using a private channel, we need to authorize the user in routes/channels.php:
Broadcast::channel('user.{id}', function ($user, $id) {
return (int) $user->id === (int) $id;
});
This ensures users can only subscribe to their own notification channel.
Step 4: Setting up Laravel Echo
On the frontend, we use Laravel Echo and the Pusher JS library to listen for events. Install them via npm:
npm install --save-dev laravel-echo pusher-js
In your resources/js/bootstrap.js, uncomment or add the following Echo configuration:
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,
forceTLS: true
});
Step 5: Listening for Events
Now, you can listen for the broadcasted event on the client side. For example, in a Vue component or vanilla JavaScript:
const userId = document.head.querySelector('meta[name="user-id"]').content;
window.Echo.private(`user.${userId}`)
.listen('UserNotified', (e) => {
console.log('Notification received:', e.message);
// Display notification UI here
});
Conclusion
You've successfully built a real-time notification system! By combining Laravel's elegant event broadcasting system, Pusher's reliable WebSocket infrastructure, and Laravel Echo's intuitive client-side API, adding real-time features to your application becomes an incredibly smooth developer experience.
From here, you could integrate this with Laravel's built-in Notification classes to store notifications in the database alongside broadcasting them in real time.