Live Metrics — Real-Time Feed

The Praevis dashboard updates every 5 seconds with live auction data — no manual refresh, no polling. Behind the dashboard is a WebSocket feed powered by a stream aggregation pipeline that turns raw auction events into structured metrics in near-real-time.


What you see

The dashboard metrics ribbon shows, live and updating:

MetricUpdate frequencySource
RPS (requests per second)5 secondsLive Redis counter
Active auctions5 secondsLive Redis counter
Fill rate (rolling 1m)5 secondsRedis stream aggregate
Revenue (period total)60 secondsStream aggregator
P50 / P95 / P99 latency60 secondsStream aggregator

Architecture

Auction engine (Go)
        ↓
Auction event → Redis Stream (XADD)
        ↓
Stream Aggregator (60s batches)
        ↓
Aggregated metrics → Redis time-series keys
        ↓
WebSocket server reads Redis (every 5s)
        ↓
Browser dashboard receives push update

Redis Stream

Every completed auction writes a lightweight event to a Redis Stream:

XADD auction:events * \
  publisher_id pub-uuid \
  dsp_id dsp-uuid \
  winning_price_micros 50000 \
  latency_ms 3 \
  filled 1

The stream is the source of truth for all real-time metrics. It’s append-only and retained for 24 hours before automatic trimming.

Stream Aggregator

The stream aggregator runs as a separate Go service. Every 60 seconds it:

  1. Reads all new events from the Redis Stream since the last run
  2. Aggregates by publisher, DSP, partner, and region
  3. Calculates fill rate, eCPM, latency percentiles, and revenue
  4. Writes aggregated values to Redis time-series keys
  5. PostgreSQL batch-write for persistent storage (90-day retention)

The 60-second aggregation window is the source of the ~60s dashboard lag for revenue and latency metrics. RPS is separately maintained as a live counter and updates instantly.

WebSocket Server

The WebSocket server:

  • Accepts authenticated connections from the dashboard
  • Reads from Redis every 5 seconds
  • Pushes the latest snapshot to all connected clients
  • Automatically reconnects on disconnect (handled client-side)

Time period selector

The dashboard lets you view metrics across different windows:

PeriodBucket sizeData source
1h1-minute bucketsRedis time-series
6h5-minute bucketsRedis time-series
TodayHourly buckets (UTC day)Redis time-series
24hHourly buckets (rolling)Redis time-series
7dDaily bucketsPostgreSQL
30dDaily bucketsPostgreSQL

Switching the time period changes which data source is queried — short windows come from Redis (fast), longer windows from PostgreSQL (accurate, permanent).


Per-entity breakdown

Live metrics are tracked separately for:

  • Per supply source: fill rate, revenue, eCPM, latency
  • Per demand source: win rate, spend, avg CPM, timeout rate
  • Per region: FRA / NYC / LON independent tracking
  • Per partner: aggregate across all partner supply sources/demand sources

All breakdowns are available in the dashboard and via the Metrics API.


API access

Pull the same data that powers the dashboard:

# Platform-wide snapshot
GET /api/metrics?period=1h
 
# Publisher breakdown
GET /api/metrics/publisher/{publisher_id}?period=6h
 
# DSP performance
GET /api/metrics/dsp/{dsp_id}?period=24h

WebSocket API

For programmatic real-time access:

const ws = new WebSocket('wss://api.praevis.com/ws/metrics', {
  headers: { 'Authorization': 'Bearer ' + apiKey }
});
 
ws.on('message', (data) => {
  const update = JSON.parse(data);
  console.log(update.rps, update.fill_rate_1m, update.revenue_cents_1m);
});

Push payload:

{
  "type": "metrics_update",
  "timestamp": "2026-02-17T14:30:05Z",
  "rps": 1359,
  "auctions_1m": 81540,
  "fill_rate_1m": 0.863,
  "revenue_cents_1m": 4820,
  "p50_ms": 3,
  "p95_ms": 15
}

Data retention

DataStorageRetention
Raw auction eventsRedis Stream24 hours
Aggregated time-seriesRedis7 days
Daily aggregatesPostgreSQL90 days
Billing-relevant recordsPostgreSQL7 years (planned)

Flushing Redis (e.g., for infrastructure maintenance) clears the live time-series but does not affect PostgreSQL historical data. The dashboard falls back to PostgreSQL for periods >7 days automatically.