# Reliable Client Telemetry Flushing Using navigator.sendBeacon and VisibilityState

In real-time mobile web applications tracking session metrics, UI performance data, and transaction audit trails, flushing queued analytics during page navigation or tab closure is notoriously fragile. Relying on synchronous `XMLHttpRequest` or standard asynchronous `fetch` calls inside `unload` or `beforeunload` event listeners frequently triggers browser cancellation or blocks thread execution.

To guarantee asynchronous, non-blocking telemetry transport during lifecycle state changes, combine the `visibilitychange` event with the native `navigator.sendBeacon` API:

```javascript
// telemetry/beaconDispatcher.js
export class ResilientTelemetryQueue {
  constructor(endpointUrl, maxBatchSize = 10) {
    this.endpointUrl = endpointUrl;
    this.maxBatchSize = maxBatchSize;
    this.eventBuffer = [];

    this.initLifecycleListeners();
  }

  enqueueEvent(eventType, payload) {
    this.eventBuffer.push({
      type: eventType,
      data: payload,
      timestamp: Date.now()
    });

    if (this.eventBuffer.length >= this.maxBatchSize) {
      this.flushQueue();
    }
  }

  flushQueue() {
    if (this.eventBuffer.length === 0) return;

    const payloadString = JSON.stringify(this.eventBuffer);

    // Prefer navigator.sendBeacon for non-blocking asynchronous transmission
    if (navigator.sendBeacon) {
      const blob = new Blob([payloadString], { type: 'application/json' });
      const transmitted = navigator.sendBeacon(this.endpointUrl, blob);
      if (transmitted) {
        this.eventBuffer = [];
        return;
      }
    }

    // Fallback using fetch with keepalive flag enabled
    fetch(this.endpointUrl, {
      method: 'POST',
      body: payloadString,
      headers: { 'Content-Type': 'application/json' },
      keepalive: true
    }).then(() => {
      this.eventBuffer = [];
    }).catch((err) => console.warn('Telemetry transmission error:', err));
  }

  initLifecycleListeners() {
    // Rely on visibilitychange rather than brittle unload events
    document.addEventListener('visibilitychange', () => {
      if (document.visibilityState === 'hidden') {
        this.flushQueue();
      }
    });
  }
}

// Example usage: monitoring mobile session events
export const sessionAuditor = new ResilientTelemetryQueue('/api/v1/telemetry/ingest');

export function trackUserInteraction(componentId, actionName) {
  sessionAuditor.enqueueEvent('USER_INTERACTION', { componentId, actionName });
}
```

### Key Engineering Advantages:

*   Guaranteed Out-of-Process Delivery: The browser handles beacon delivery in the background even if the originating page context has already been unmounted.
    
*   Zero UI Thread Stalls: Eliminates synchronous network requests during page unload, ensuring fluid transitions between views.
    

For an operational reference of decoupled, low-footprint web viewports running in production, inspect this [reference node](https://bl777.gg/).
