Mastering Real-Time Interaction: A Guide to Laravel Reverb and Livewire Volt
Overview
marks a significant milestone in the ecosystem. As a first-party, high-performance server, it eliminates the historical friction of integrating real-time features into PHP applications. Traditionally, developers had to rely on third-party services like Pusher or complex Node.js setups to handle bi-directional communication. Reverb changes this by bringing the entire infrastructure under the Laravel umbrella, allowing for seamless integration with and .
This guide explores how to build a collaborative environment where users can see each other's actions instantly. We will implement a shared toggle switch and a real-time cursor tracking system similar to collaborative tools like Figma. By the end of this tutorial, you will understand how to manage state across multiple clients, broadcast events efficiently, and deploy a production-ready WebSocket server using .
Prerequisites
To follow along effectively, you should be comfortable with:
- PHP and Laravel 11: Basic understanding of routing, controllers, and Eloquent.
- Livewire Volt: Familiarity with the class-based API for single-file components.
- JavaScript (Alpine.js): Basic knowledge of reactive front-end directives like
x-dataandx-on. - Terminal/CLI: Ability to run Artisan commands and manage NPM packages.
- Local Environment: is highly recommended for its built-in Reverb support, but a standard Laravel setup works as well.
Key Libraries & Tools
- : The core WebSocket server handling real-time data transmission.
- : A single-file component syntax for Livewire that keeps logic and templates unified.
- : The JavaScript library used to subscribe to channels and listen for events on the client side.
- : Handles local UI state and ensures "optimistic" updates for a snappier user experience.
- Font Awesome: Provides the visual icons for our cursor effects.
Code Walkthrough: The Multi-Player Toggle
Our first task is creating a toggle switch that stays in sync for every user currently on the site. We use a combination of database caching and event broadcasting to ensure state persistence.
1. Scaffolding the Component
Generate the Volt component using the following command:
php artisan make:volt toggle
In the component, we define the toggle_switch property and use the mount method to retrieve the initial state from the cache. This ensures that if a new user joins, they see the current state immediately.
public bool $toggle_switch = false;
public function mount()
{
$this->toggle_switch = Cache::get('toggle_switch', false);
}
2. The Broadcasting Event
We need a dedicated event class to signal the WebSocket server. Create it with php artisan make:event SwitchFlipped. Crucially, this event must implement ShouldBroadcastNow to bypass the queue and send data immediately.
class SwitchFlipped implements ShouldBroadcastNow
{
use Dispatchable, InteractsWithSockets, SerializesModels;
public function __construct(public bool $toggle_switch) {}
public function broadcastOn(): array
{
return [new Channel('switch')];
}
public function broadcastWith(): array
{
return ['toggle_switch' => $this->toggle_switch];
}
}
3. Triggering the Flip
Inside the Volt component, the flipSwitch method updates the cache and broadcasts the new state to all other connected clients.
public function flipSwitch()
{
Cache::forever('toggle_switch', $this->toggle_switch);
broadcast(new SwitchFlipped($this->toggle_switch))->toOthers();
}
On the front end, we use Alpine.js to entangle the local state with the Livewire property. This creates an "optimistic UI" where the switch moves instantly for the user who clicked it, while the server call happens in the background.
<div x-data="{ localToggle: $wire.entangle('toggle_switch') }">
<input type="checkbox" x-model="localToggle" x-on:change="$wire.flipSwitch()">
</div>
Syntax Notes: Attributes and Entanglement
The On Attribute
Livewire provides a powerful PHP attribute, #[On], which allows your component to listen for client-side events directly within the class. When using Reverb, we prefix the event name with echo:. This tells Livewire to listen to the WebSocket channel rather than a standard internal event.
#[On('echo:switch,SwitchFlipped')]
public function handleBroadcast($payload)
{
$this->toggle_switch = $payload['toggle_switch'];
}
State Entanglement
The $wire.entangle() method is the bridge between Alpine.js (client-side) and Livewire (server-side). It creates a two-way binding. If you change a variable in Alpine, it reflects in Livewire, and vice versa. This is critical for real-time apps because it allows the UI to react to broadcasts without full page reloads.
Practical Examples: Advanced Cursor Tracking
Beyond simple toggles, we can track mouse movements to create a collaborative workspace. This requires calculating cursor positions relative to the screen center so that users on different monitor sizes see the pointer in the correct logical position.
Calculating Relative Position
In our JavaScript, we calculate the offset from the center of the viewport. This prevents the cursor from appearing "broken" when users have different browser window dimensions.
const relativeX = (e.clientX - (window.innerWidth / 2)) / (window.innerWidth / 2);
const relativeY = (e.clientY - (window.innerHeight / 2)) / (window.innerHeight / 2);
We then send these coordinates to the Livewire component, which broadcasts them via a MouseMoved event. To prevent overwhelming the server with hundreds of events per second, we implement a slight throttle or check to ensure the mouse has actually moved a significant distance before broadcasting.
Smooth Cursor Animation
Directly binding a div to the coordinates received from a broadcast can look choppy due to network latency. To fix this, we use a requestAnimationFrame loop in Alpine.js to interpolate the cursor's current position toward the target position, creating a fluid, professional feel.
Tips & Gotchas
- Queue vs. Now: By default, Laravel events are queued. In real-time apps, this can cause a noticeable lag. Always use
ShouldBroadcastNowfor interactions that require immediate feedback, like mouse movement or chat messages. - Environment Variables: Ensure your
.envfile hasBROADCAST_CONNECTION=reverb. If you're using Herd, it manages the credentials for you, but on a manual setup, you must verify theREVERB_APP_IDandREVERB_APP_KEYmatch your server configuration. - Browser Backgrounding: Browsers often throttle JavaScript in background tabs. We added a
visibilitychangelistener to stop broadcasting cursor data when a user switches tabs. This saves server resources and keeps the active user count accurate. - Sticky Sessions: When deploying to production, ensure your load balancer (if using one) supports WebSockets. Reverb handles the connections, but your infrastructure must allow the long-lived HTTP connection to remain open.
- 15%· products
- 15%· products
- 8%· concepts
- 8%· products
- 8%· products
- Other topics
- 46%

Build a Real-Time Web App with Laravel Reverb - COMPLETE TUTORIAL (Laravel, Livewire, Alpine & more)
WatchLaravel // 1:07:48
The official YouTube channel of Laravel, the clean stack for Artisans and agents. We will update you on what's new in the world of Laravel, from the framework to our products Cloud, Forge, and Nightwatch.