Live Data & WebSockets
UIGen supports live updates through x-uigen-websocket. REST stays in openapi.yaml; WebSocket metadata goes in .uigen/config.yaml and merges onto operations at reconcile time.
The UI still loads data with a normal GET (useApiCall), then merges WebSocket frames into the same React Query cache. Charts, tables, and detail fields update without polling.
When to use
- Board or device snapshots that push full state (
mode: replace) - Telemetry history that grows over time (
mode: append) - Sensor detail pages with embedded child streams (
x-uigen-detail-stream)
Skip WebSockets for health checks, mutations, and routes marked x-uigen-ignore.
Config shape
Add annotations under annotations in .uigen/config.yaml using METHOD:path keys:
annotations:
GET:/api/v1/board:
x-uigen-websocket:
path: /ws/v1/board
mode: replace
GET:/api/v1/readings:
x-uigen-websocket:
path: /ws/v1/readings
mode: append
appendField: readings
subscribe:
sensor_id: 1
| Field | Description |
|---|---|
path |
WebSocket path on the API host (starts with /) |
mode |
replace (default) or append |
appendField |
Dot path to the growing array when mode: append |
subscribe |
Optional JSON sent once after the socket opens (backend-defined) |
Do not put x-uigen-websocket in openapi.yaml. Keep OpenAPI as a portable REST contract.
See x-uigen-websocket and x-uigen-detail-stream for the full reference.
Backend conventions
Device examples use matching REST and WebSocket paths:
| REST | WebSocket |
|---|---|
GET /api/v1/board |
/ws/v1/board |
GET /api/v1/pins |
/ws/v1/pins |
GET /api/v1/readings?sensor_id= |
/ws/v1/readings |
Each message should be JSON with the same shape as the GET response (or an array slice for append mode).
How uigen serve proxies WebSockets
REST and WebSocket traffic both go through the panel origin under /api:
- REST:
http://localhost:4400/api/api/v1/... - WebSocket:
ws://localhost:4400/api/ws/v1/...
The CLI forwards HTTP and WebSocket upgrades to --proxy-base (or the spec's active server). Auth credentials travel as x-uigen-* query parameters on WebSocket upgrades and are injected as headers upstream.
See uigen serve for proxy details and environment switcher behavior.
Detail page child streams
Pin a nested list GET on a detail view with x-uigen-detail-stream:
annotations:
GET:/api/v1/sensors/{sensor_id}:
x-uigen-detail-stream:
operationId: listSensorReadings
Pair with x-uigen-websocket on the child list GET for a live chart or highlighted latest row on the detail page.
Live charts
When a list response has x-uigen-chart and x-uigen-websocket, the chart updates on each frame without replaying enter animations (animations are off by default on refresh; opt in with options.animate: true).
Dense line charts hide per-point dots when more than 24 sampled points are rendered. Override with options.showDots.
See List View and x-uigen-chart.
Example projects
| Example | What it demonstrates |
|---|---|
| ESP32 simulator | GPIO, sensors, telemetry charts, detail child streams |
| DevBoard (Next.js) | Board visualizer + panel, Render deploy with WebSocket proxy |
Ask your AI to run the configure-websockets skill (.agents/skills/configure-websockets.md) against your project.
Deployment note
Serverless hosts (for example Vercel on the board app alone) typically cannot serve /ws/v1/*. Deploy the API with WebSocket support (Docker on Render, custom server.ts, or embedded firmware) and proxy through the UIGen panel.