---
title: Live Dashboards
description: Build real-time dashboards and live data visualizations with NoLag.
---

# Live Dashboards

Build real-time dashboards that update instantly as data changes.

## Overview

Real-time dashboards provide immediate visibility into your business metrics. With NoLag, you can push updates to dashboards the moment data changes, without polling or page refreshes.

## Dashboard Setup

```typescript [TypeScript]
import { NoLag } from '@nolag/js-sdk'

const client = NoLag('your_access_token')
await client.connect()

const dashboard = client.setApp('analytics').setRoom('live')

// Subscribe to real-time metrics
dashboard.subscribe('page-views')
dashboard.subscribe('active-users')
dashboard.subscribe('sales')

// Update charts in real-time
dashboard.on('page-views', (data) => {
  pageViewsChart.update(data.count, data.timestamp)
})

dashboard.on('active-users', (data) => {
  activeUsersGauge.setValue(data.count)
})

dashboard.on('sales', (data) => {
  salesChart.addDataPoint(data.amount, data.timestamp)
  totalSales.increment(data.amount)
})
```
```python [Python]
from nolag import NoLag

client = NoLag('your_access_token')
await client.connect()

dashboard = client.set_app('analytics').set_room('live')

# Subscribe to real-time metrics
await dashboard.subscribe('page-views')
await dashboard.subscribe('active-users')
await dashboard.subscribe('sales')

# Update charts in real-time
def on_page_views(data, meta):
    page_views_chart.update(data['count'], data['timestamp'])

def on_active_users(data, meta):
    active_users_gauge.set_value(data['count'])

def on_sales(data, meta):
    sales_chart.add_data_point(data['amount'], data['timestamp'])
    total_sales.increment(data['amount'])

dashboard.on('page-views', on_page_views)
dashboard.on('active-users', on_active_users)
dashboard.on('sales', on_sales)
```
```go [Go]
package main

import nolag "github.com/NoLagApp/nolag-go"

func main() {
    client := nolag.New("your_access_token")
    client.Connect()

    dashboard := client.SetApp("analytics").SetRoom("live")

    // Subscribe to real-time metrics with handlers
    dashboard.Subscribe("page-views", func(data any, meta nolag.MessageMeta) {
        d, _ := data.(map[string]any)
        pageViewsChart.Update(d["count"], d["timestamp"])
    })

    dashboard.Subscribe("active-users", func(data any, meta nolag.MessageMeta) {
        d, _ := data.(map[string]any)
        activeUsersGauge.SetValue(d["count"].(int))
    })

    dashboard.Subscribe("sales", func(data any, meta nolag.MessageMeta) {
        d, _ := data.(map[string]any)
        salesChart.AddDataPoint(d["amount"], d["timestamp"])
        totalSales.Increment(d["amount"].(float64))
    })
}
```

## Filtering Dashboard Updates

Most dashboards show a subset of data. A few bookings, specific orders, or selected devices. Without filters, every update on the topic is delivered to every subscriber, even if they're only watching 3 items out of thousands.

**Topic filters** solve this at the infrastructure level. Subscribe with the IDs of the entities currently visible on screen, and only updates for those entities are delivered. When the user navigates, swap filters dynamically, no resubscribe needed.

```typescript [TypeScript]
import { NoLag } from '@nolag/js-sdk'

const client = NoLag('your_access_token')
await client.connect()

const dashboard = client.setApp('booking-system').setRoom('ops')

// User is viewing 3 specific bookings on their dashboard
const visibleBookings = ['booking_42', 'booking_87', 'booking_153']

// Subscribe with filters: only receive updates for these bookings
dashboard.subscribe('bookings', {
  filters: visibleBookings
})

dashboard.on('bookings', (data, meta) => {
  // meta.filter tells you which booking was updated
  updateBookingCard(meta.filter, data)
})

// User navigates to a different page, swap filters instantly
function onPageChange(newBookingIds: string[]) {
  dashboard.setFilters('bookings', newBookingIds)
}

// User opens a booking detail, add it to filters
function onBookingOpen(bookingId: string) {
  dashboard.addFilters('bookings', [bookingId])
}

// User closes a booking detail, remove it
function onBookingClose(bookingId: string) {
  dashboard.removeFilters('bookings', [bookingId])
}
```
```python [Python]
from nolag import NoLag, SubscribeOptions

client = NoLag('your_access_token')
await client.connect()

dashboard = client.set_app('booking-system').set_room('ops')

# User is viewing 3 specific bookings on their dashboard
visible_bookings = ['booking_42', 'booking_87', 'booking_153']

# Subscribe with filters
await dashboard.subscribe('bookings', SubscribeOptions(
    filters=visible_bookings
))

def on_booking_update(data, meta):
    update_booking_card(meta.filter, data)

dashboard.on('bookings', on_booking_update)

# User navigates to a different page
async def on_page_change(new_booking_ids):
    await dashboard.set_filters('bookings', new_booking_ids)

# Add/remove individual bookings
async def on_booking_open(booking_id):
    await dashboard.add_filters('bookings', [booking_id])

async def on_booking_close(booking_id):
    await dashboard.remove_filters('bookings', [booking_id])
```
```go [Go]
package main

import nolag "github.com/NoLagApp/nolag-go"

func main() {
    client := nolag.New("your_access_token")
    client.Connect()

    dashboard := client.SetApp("booking-system").SetRoom("ops")

    // User is viewing 3 specific bookings
    visibleBookings := []string{"booking_42", "booking_87", "booking_153"}

    // Subscribe with filters and handler
    dashboard.Subscribe("bookings", func(data any, meta nolag.MessageMeta) {
        updateBookingCard(meta.Filter, data)
    }, nolag.SubscribeOptions{
        Filters: visibleBookings,
    })

    // Swap filters on page change
    dashboard.SetFilters("bookings", []string{"booking_200", "booking_201"})
}
```

### Publishing Filtered Updates

On the backend, publish with a `filter` to target specific entities. Only dashboard clients watching that entity receive the update:

```typescript [TypeScript]
// Backend service publishes updates with filters
// Only dashboard users watching this specific booking receive it
room.emit('bookings', {
  status: 'confirmed',
  guest: 'John Smith',
  checkIn: '2026-03-15'
}, {
  filter: 'booking_42'  // Target a specific booking
})

// Publish a different booking update
room.emit('bookings', {
  status: 'cancelled',
  reason: 'Guest request'
}, {
  filter: 'booking_87'
})
```
```python [Python]
from nolag import EmitOptions

# Backend service publishes updates with filters
await room.emit('bookings', {
    'status': 'confirmed',
    'guest': 'John Smith',
    'check_in': '2026-03-15'
}, EmitOptions(filter='booking_42'))

await room.emit('bookings', {
    'status': 'cancelled',
    'reason': 'Guest request'
}, EmitOptions(filter='booking_87'))
```
```go [Go]
// Backend service publishes updates with filters
room.Emit("bookings", map[string]string{
    "status": "confirmed",
    "guest":  "John Smith",
    "checkIn": "2026-03-15",
}, nolag.EmitOptions{Filter: "booking_42"})

room.Emit("bookings", map[string]string{
    "status": "cancelled",
    "reason": "Guest request",
}, nolag.EmitOptions{Filter: "booking_87"})
```

**Tip:** Filtering happens at the infrastructure level, no payload inspection, no wasted bandwidth. See [Topic Filters](/docs/concepts/filters) for full details.

## Use Cases

- **Analytics dashboards** - Page views, user sessions, conversion rates
- **Sales dashboards** - Revenue, orders, inventory levels
- **Operations dashboards** - Server health, error rates, response times
- **Trading dashboards** - Stock prices, market data, portfolio values

## Architecture

1. Backend services publish metrics to NoLag topics
2. Dashboard clients subscribe to relevant topics
3. Charts and gauges update in real-time as data arrives

## Best Practices

- Use **filters** to subscribe only to entities visible on screen to avoid receiving thousands of irrelevant updates
- Use `setFilters` when the user navigates, it swaps filters atomically with minimal message gaps
- Use separate topics for different metric types
- Batch updates for high-frequency data to reduce rendering overhead
- Use per-topic hydration webhooks to load initial dashboard state
- Consider data retention and historical data storage separately

## Next Steps

- [Topic Filters](/docs/concepts/filters) - full reference for filter-based subscriptions
- [Topics & Pub/Sub](/docs/concepts/topics)
- [Quality of Service](/docs/concepts/qos)
