skip to content

In Livewire 4, how does wire:poll keep a live sales counter fresh, and what does it cost the server at scale?

level: middleimportance: should knowfreq 30%

answer

  1. an interval of full component requests
  2. no value: $refresh
  3. default 2 s in the 4.4 JavaScript
  4. .visible and .keep-alive
  5. background tabs skip most ticks

basics

~10 s

wire:poll makes the browser send a component request on an interval, calling $refresh or a named action; in Livewire 4.4.7 the default interval is 2 seconds, so every open tab adds steady server load.

solid answer

~40 s

`<div wire:poll>` makes the browser send a normal Livewire request on an interval, re-rendering the component (`$refresh`) or calling a named action such as `wire:poll="refreshTotals"`. The interval comes from a modifier (`.15s`, `.1m`, `.15000ms`); without one, Livewire 4.4.7's JavaScript uses **2 seconds**, although the docs still say 2.5. Each tick is a full round trip: the snapshot is sent, the component hydrates, runs, renders and dehydrates. So a thousand open dashboards polling every 2 seconds is about 500 requests per second. Livewire reduces this itself: it skips about 95% of ticks while the tab is in the background (unless `.keep-alive`), pauses with `.visible` while the element is off-screen, pauses while offline, and stops when the element is removed. Longer intervals, `.visible`, or pushing updates via broadcasting are the usual fixes.

code

html · 3 lines
html
<div wire:poll.30s.visible="refreshTotals">
    Sales today: {{ number_format($totalToday / 100, 2) }}
</div>

go deeper

for a junior

Recall that wire:poll re-requests the component on an interval and that modifiers like .15s set it.

for a middle

Explain that each tick is a full hydrate-render cycle and how .visible, .keep-alive and background throttling change it.

for a senior

Estimate load as tabs divided by interval, cache what each tick reads, and know when to switch to pushed updates.

for a principal

Decide which dashboards justify real-time infrastructure and which can live with slower polling.

## What wire:poll does **Polling** means asking the server for updates on a timer. In **Livewire**, adding `wire:poll` to an element inside a component makes the browser send a request for that component at a fixed interval. Each request is an ordinary Livewire update request: the component's snapshot goes to the server, the component is rebuilt, the action runs, the view re-renders and the browser morphs in the changes. For a "sales today" counter on a dashboard, that is all it takes to keep the number current. - `wire:poll` with no value calls `$refresh`, which simply re-renders. - `wire:poll="refreshTotals"` calls a component method on each tick. - Polling inside an `@island` refreshes only that island. ## Interval | Markup | Interval | |---|---| | `wire:poll` | default: 2 s in the pinned JavaScript | | `wire:poll.15s` | 15 seconds | | `wire:poll.1m` | 1 minute | | `wire:poll.750ms` | 750 milliseconds | The documentation says the default is 2.5 seconds, but the pinned Livewire 4.4.7 source passes 2000 ms as the default. When the exact figure matters, set an explicit interval; it documents intent and removes the ambiguity. ## Built-in throttling Livewire already limits needless polling: 1. **Background tabs.** While the tab is hidden, Livewire randomly skips about 95% of ticks. `.keep-alive` opts out. 2. **Off-screen elements.** With `.visible`, polling pauses while the element is outside the viewport. 3. **Offline or expired session.** Polling pauses while the browser is offline or the session has expired. 4. **Removed element.** Polling stops when the element leaves the DOM. Poll requests also do not add the `data-loading` attribute, so a poll does not make the triggering element look busy. ## The cost model Every open tab is a client on a timer. The rough load is **tabs divided by interval**: 1,000 dashboards on a 2-second poll is about 500 requests per second, each paying for session start-up, component hydration, whatever queries the render runs, and dehydration. Most of those requests return nothing new. Ways to bring it down: - **Lengthen the interval** to what the business needs; a sales counter rarely needs 2-second freshness. - **Add `.visible`** so widgets below the fold do not poll. - **Make each tick cheap**: cache the aggregate the counter reads, rather than re-aggregating orders every tick. - **Push instead of pull**: when many clients need near-real-time data, broadcasting events to listening components removes the idle requests; that is covered by the events and broadcasting topics. ## Common mistakes 1. Leaving the default interval on a widget where once a minute would do. 2. Polling an expensive query without caching, multiplying its cost by every open tab. 3. Adding `.keep-alive` to everything and losing the background-tab savings. 4. Expecting `wire:poll` to be a push channel; it is a timed request, so updates arrive up to one interval late. ## A worked estimate A sales team of 200 people keeps the dashboard open all day, each in one tab. With the default interval: - 200 tabs / 2 s = **100 requests per second**, throughout the working day; - background throttling helps only for tabs that are hidden; - if the counter's query takes 40 ms, that is four seconds of database time every second. Changing to `wire:poll.30s.visible` and caching the aggregate for 30 seconds drops that to under 7 requests per second, each served from cache. The business loses nothing, because nobody needs a sales total fresher than half a minute. This kind of back-of-the-envelope reasoning is what interviewers want to hear before any mention of WebSockets.

  • How would you cut the cost of a polled counter without changing its interval?
    Make each tick cheap: have the action or render read a cached aggregate refreshed by a scheduled job, add `.visible` so off-screen widgets stay idle, and keep the polled component small so hydration and rendering stay light.
  • Why might you replace wire:poll with broadcast events for a live sales feed?
    Polling sends a request from every tab on every tick even when nothing changed. Broadcasting pushes a message only when a sale happens, and listening components refresh then, trading idle requests for a persistent connection.

saying these in an interview costs you the question

  • Believes wire:poll keeps a server connection open and pushes changes.
  • Thinks a poll tick only refreshes data without re-rendering the component.
  • Assumes polling stops completely in a background tab.
  • Ignores that server load scales with the number of open tabs.