docs / Runtime

Network State

Reactive browser network state: getNetworkState with online, effectiveType, downlink, rtt, saveData, plus watchNetwork subscriptions.

Vesk tracks browser connectivity through the Network Information API and `navigator.onLine`. It is designed for connectivity-aware boundaries and the router's offline fallback UI, and it degrades gracefully where the API is missing (Safari/Firefox): the extra fields become `null` / `'unknown'` and consumers fall back to the `online` flag alone.

getNetworkState

`getNetworkState()` returns a snapshot of the current connectivity as a plain `NetworkState` object. It is a read, not a subscription — combine it with `watchNetwork` to react to changes.

Field Type Meaning
online boolean `navigator.onLine` — whether the browser believes it has connectivity.
effectiveType 'slow-2g' | '2g' | '3g' | '4g' | 'unknown' Estimated connection quality; `'unknown'` when the Network Information API is unavailable.
downlink number | null Estimated downlink in Mbps, or `null` when unsupported.
rtt number | null Estimated round-trip time in ms, or `null` when unsupported.
saveData boolean Whether the user's data-saver mode is active.
app/lib/net.ts
									
										// @client-only — the network APIs live in the client barrel
import { getNetworkState } from '@vesk/runtime';

const state = getNetworkState();
console.log(state.online);        // true | false
console.log(state.effectiveType); // '4g' | '3g' | '2g' | 'slow-2g' | 'unknown'
console.log(state.downlink);      // Mbps | null
console.log(state.rtt);           // ms | null
console.log(state.saveData);      // boolean
									
								

watchNetwork

`watchNetwork(cb)` subscribes to connectivity changes — online/offline flips plus `connection.change` events where the Network Information API is supported — and calls `cb(state)` with a fresh `NetworkState` on every change. It returns an unsubscribe function, and it is a no-op-safe no-op on the server (no `window` access is attempted). It is not auto-imported, so pull it from `@vesk/runtime`.

app/components/NetworkStatus.vsk
										
											// @client-only — the network APIs live in the client barrel
import { watchNetwork } from '@vesk/runtime';

component NetworkStatus() {
  let &[online] = track(navigator.onLine ?? true);

  // watchNetwork calls you with a plain snapshot. Assigning to the tracked
  // binding is the write — the compiler turns it into a cell set, so the
  // template above follows it.
  const unsubscribe = watchNetwork((state) => online = state.online);
  on_destroy(unsubscribe);

  <p class={online ? 'text-green-600' : 'text-red-600'}>
    {online ? 'Online' : 'Offline'}
  </p>
}
										
									

For a richer badge that reacts to the full state object, keep a tracked cell of the whole `NetworkState` and write it from the subscription:

app/components/NetworkStatus.vsk
										
											// @client-only — the network APIs live in the client barrel
import { watchNetwork } from '@vesk/runtime';

component NetworkStatus() {
  let &[online] = track(navigator.onLine ?? true);

  // watchNetwork calls you with a plain snapshot. Assigning to the tracked
  // binding is the write — the compiler turns it into a cell set, so the
  // template above follows it.
  const unsubscribe = watchNetwork((state) => online = state.online);
  on_destroy(unsubscribe);

  <p class={online ? 'text-green-600' : 'text-red-600'}>
    {online ? 'Online' : 'Offline'}
  </p>
}
										
									

On browsers without the Network Information API, `effectiveType` stays `'unknown'` and `downlink` / `rtt` are `null` — never assume those fields are present. Only `online` is universally available.