In Livewire 4, how does wire:poll keep a live sales counter fresh, and what does it cost the server at scale?
answer
- an interval of full component requests
- no value: $refresh
- default 2 s in the 4.4 JavaScript
- .visible and .keep-alive
- background tabs skip most ticks
basics
~10 swire: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<div wire:poll.30s.visible="refreshTotals">
Sales today: {{ number_format($totalToday / 100, 2) }}
</div>go deeper
Recall that wire:poll re-requests the component on an interval and that modifiers like .15s set it.
Explain that each tick is a full hydrate-render cycle and how .visible, .keep-alive and background throttling change it.
Estimate load as tabs divided by interval, cache what each tick reads, and know when to switch to pushed updates.
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.