---
title: "Dash SDK"
description: "Live dashboards with real-time metrics, time-series aggregation, and widgets."
---

# @nolag/dash

Live dashboards with real-time metrics, time-series aggregation, and widgets.

## Overview

`@nolag/dash` powers live operational dashboards with streaming metrics and interactive widgets. Agents or servers publish metric data points and widget state snapshots to panels; viewers connected to the same panel receive updates instantly and can query rolling aggregations (average, min, max, sum, count) over any time window without hitting a separate time-series database.

### Key Features

- Streaming metric ingestion with per-stream data point buffering
- Client-side rolling aggregation over configurable time windows
- Widget state publishing for KPI cards, gauges, tables, and custom types
- 1-hour replay for both metrics and widgets so new viewers see recent history immediately
- Tag-based metadata on metrics for multi-dimensional filtering
- Automatic reconnection with panel restoration

## How It Works

`NoLagDash` wraps the `@nolag/js-sdk` client. Calling `joinPanel()` creates a `DashboardPanel` that subscribes to two topics: `metrics` for time-series data points and `widgets` for widget state snapshots. A `MetricBuffer` inside the panel accumulates data points per stream ID and provides efficient rolling-window aggregation, while a `WidgetStore` keeps the latest state for each widget keyed by widget ID.

| Topic | Purpose | Replay |
| --- | --- | --- |
| `metrics` | Time-series data points: value, timestamp, unit, tags | 1 hour |
| `widgets` | Widget state snapshots: type, data payload, last updated | 1 hour |

## Installation

```bash [Terminal]
npm install @nolag/dash @nolag/js-sdk
```

## Quick Start

```typescript [TypeScript]
import { NoLagDash } from '@nolag/dash'

// Create and connect the client
const dash = new NoLagDash('your-access-token')

await dash.connect()

// Join a dashboard panel
const panel = await dash.joinPanel('ops-overview')

// Publish a metric (typically called from a server or agent)
await panel.publishMetric('cpu.usage', 74.2, {
  unit: 'percent',
  tags: { host: 'web-01', region: 'us-east-1' },
})

// Listen for incoming metrics
panel.on('metric', ({ streamId, value, timestamp, tags }) => {
  console.log(`[${streamId}] ${value} @ ${new Date(timestamp).toISOString()}`)
})

// Get all buffered data points for a metric stream
const points = panel.getMetrics('cpu.usage')
console.log('Data points:', points.length)

// Get a rolling aggregation over the last 5 minutes
const agg = panel.getAggregation('cpu.usage', 5 * 60_000)
console.log('Avg CPU:', agg.avg.toFixed(1) + '%')
console.log('Max CPU:', agg.max.toFixed(1) + '%')

// Publish a widget state (e.g. a status card)
await panel.publishWidget('status-card', 'kpi', {
  label: 'Active Sessions',
  value: 1_248,
  trend: 'up',
})

// Listen for widget updates
panel.on('widgetUpdate', ({ widgetId, type, data }) => {
  console.log(`Widget ${widgetId} (${type}):`, data)
})

// Read current widget state
const widget = panel.getWidget('status-card')

await dash.leavePanel('ops-overview')
dash.disconnect()
```

## API Reference

### NoLagDash

The main class. Manages the WebSocket connection and dashboard panel lifecycle.

| Method | Description |
| --- | --- |
| `connect()` | Establish WebSocket connection |
| `disconnect()` | Gracefully close the connection and leave all panels |
| `joinPanel(name)` | Join a dashboard panel; returns a `DashboardPanel` instance |
| `leavePanel(name)` | Leave a panel and unsubscribe from its topics |

### Events: NoLagDash

| Event | Payload | Description |
| --- | --- | --- |
| `connected` | none | WebSocket connection established |
| `disconnected` | `reason: string` | Connection closed |
| `reconnected` | none | Reconnection successful; panels are restored automatically |
| `error` | `error: Error` | Unrecoverable error occurred |
| `viewerOnline` | `viewer: DashViewer` | A viewer joined any panel |
| `viewerOffline` | `viewer: DashViewer` | A viewer left any panel |

### DashboardPanel

Returned by `joinPanel()`. Handles metric ingestion, aggregation, widget state, and per-panel viewer presence.

| Method | Description |
| --- | --- |
| `publishMetric(streamId, value, opts)` | Publish a single data point to a metric stream; `opts` accepts `unit`, `tags`, and `timestamp` |
| `publishWidget(widgetId, type, data)` | Publish a widget state snapshot; replaces the previous state for that widget ID |
| `getMetrics(streamId)` | Return all buffered data points for the given metric stream, ordered by timestamp |
| `getAggregation(streamId, windowMs)` | Return `{ avg, min, max, sum, count }` for all data points within the last `windowMs` milliseconds |
| `getWidget(widgetId)` | Return the latest state snapshot for a single widget |
| `getWidgets()` | Return the latest state snapshots for all widgets in this panel |

### Events: DashboardPanel

| Event | Payload | Description |
| --- | --- | --- |
| `metric` | `{ streamId: string, value: number, timestamp: number, unit?: string, tags?: Record<string, string> }` | A new data point arrived for a metric stream |
| `widgetUpdate` | `{ widgetId: string, type: string, data: unknown }` | A widget state snapshot was updated |
| `viewerJoined` | `viewer: DashViewer` | A viewer joined this panel |
| `viewerLeft` | `viewer: DashViewer` | A viewer left this panel |
| `replayStart` | `{ count: number }` | Historical data replay is beginning |
| `replayEnd` | `{ replayed: number }` | Historical data replay is complete |
