Using Livewire Polling for Real‑Time UI Updates in Laravel
Learn how to add real‑time updates to a Laravel UI using Livewire’s wire:poll directive, with a working order‑counter example and guidance on intervals, modifiers, and performance trade‑offs.
21 Jul 2025, 17:49 UTC

Problem: Keeping a UI slice fresh without a full page reload
Many Laravel applications need to show data that changes frequently – for example, a live order count, a status flag, or a timer. Traditionally you would write custom JavaScript with setInterval and fetch JSON endpoints, or rely on Echo/Pusher for websockets. Both approaches add complexity: you must manage extra routes, handle authentication for the API, and deal with reconnection logic.
Livewire offers a built‑in way to refresh a component at regular intervals using only Blade syntax. The wire:poll directive triggers an AJAX request, runs the component’s lifecycle, and patches only the changed parts of the DOM. This gives you near‑real‑time updates while staying inside the Laravel request‑response flow.
How wire:poll works
When Livewire renders a component, it attaches a small JavaScript runtime to the page. If an element carries wire:poll.<ms>, that runtime sets a setInterval that, every <ms> milliseconds, sends a POST to /livewire/message/<component-id>. The server:
- Re‑hydrates the component instance (calling
mountif needed, thenhydratewith the latest property values). - Renders the component’s Blade view.
- Computes a DOM diff and returns only the HTML fragments that changed.
The client swaps those fragments in, leaving untouched parts of the page intact. Because the request goes through Livewire’s standard middleware, session, CSRF protection, and validation rules are automatically applied.
Worked example: a live order counter
Suppose you want to show the number of pending orders in the admin dashboard, updating every two seconds.
1. Generate the component
php artisan make:livewire OrderCounter
This creates app/Http/Livewire/OrderCounter.php and resources/views/livewire/order-counter.blade.php.
2. Component class
<?php
namespace App\Http\Livewire;
use Livewire\Component;
use App\Models\Order;
class OrderCounter extends Component
{
public int $pending = 0;
public function mount()
{
$this->pending = Order::where('status', 'pending')->count();
}
// No extra methods needed; mount runs on each poll.
public function render()
{
return view('livewire.order-counter');
}
}
3. Blade template with polling
<div>
Pending Orders
{{ $pending }}
</div>
The wire:poll.2000 attribute tells Livewire to request an update every 2000 ms (2 seconds). On each poll, the mount method re‑queries the database, updates $pending, and the Blade template re‑renders just the number.
4. Verifying the behavior
- Open the page in a browser, open DevTools → Network.
- Filter by
livewireand look for requests to/livewire/message/<id>. - Confirm that a request appears roughly every two seconds.
- In the Response tab, you should see a small JSON payload containing the updated HTML for the
<p>element. - Update the order count directly in the database (e.g., via a seed or tinker) and watch the number change without a manual refresh.
Customizing polling behavior
Livewire provides modifiers to fine‑tune the polling loop:
wire:poll.2000.debounce– delays the actual request until 2000 ms have passed without a new poll trigger, useful if you might reset the timer via user interaction.wire:poll.2000.ignoreChanges– skips the poll if none of the component’s public properties have changed since the last request, saving server work when the data is static.
You can chain them: wire:poll.2000.debounce.ignoreChanges.
Trade‑offs and limitations
While polling is simple, it is not free:
- Server load: Every interval triggers a full Laravel request (routing, middleware, session start). With many concurrent users or very short intervals, this can add noticeable CPU and database pressure.
- Network traffic: Each poll sends a request and receives a response, even if nothing changed. Over mobile or high‑latency connections this may affect perceived responsiveness.
- Staleness window: The UI is only as fresh as the interval you choose. For sub‑second updates, consider Laravel Echo with WebSockets or a dedicated streaming solution.
To mitigate load, consider:
- Caching expensive queries (e.g.,
Cache::remember('pending-orders', 30, fn() => Order::where('status','pending')->count())) insidemount. - Increasing the interval when the data tolerates slight delay.
- Using
.ignoreChangesto skip polls when the component’s state hasn’t shifted.
Actionable closing
If you need a lightweight way to show periodically refreshed data without leaving the Laravel ecosystem, start with wire:poll. Build a small component, test the network traffic in DevTools, and then adjust the interval or add modifiers based on your traffic and freshness requirements. For higher‑frequency or ultra‑low‑latency needs, evaluate WebSocket‑based alternatives, but for many dashboards, admin panels, and public‑facing counters, Livewire polling offers a pragmatic, low‑maintenance solution.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.