---
title: Data Sources – Feed Live Data to Your Dashboards
description: "A **data source** is how your dashboard gets runtime data. Twinnoverse supports **four data-source models**, each suited for a different operating reality. --- ## 1. Types of Data Sources | Type | Best For | How It Works | | --- | ---…"
url: "https://twinnoverse.com/docs/data-sources-feed-live-data-to-your-dashboards/"
updated: "2026-06-18"
category: Dashboard Builder / Dashboard Builder Data
---

# Data Sources – Feed Live Data to Your Dashboards

A **data source** is how your dashboard gets runtime data. Twinnoverse supports **four data-source models**, each suited for a different operating reality.

---

## 1. Types of Data Sources

| Type | Best For | How It Works |
| --- | --- | --- |
| **REST API** | Cloud APIs, MES/ERP services, existing web backends | The TV polls your API endpoint on a schedule |
| **WebSocket** | Realtime streams and low-latency updates | The TV keeps a persistent connection and receives pushed updates |
| **Ingest** | Local plant systems behind a firewall | A local gateway pushes data to Twinnoverse; the TV reads from the cloud snapshot |
| **Manual** | No API yet, operator-entered values | A user updates widget values manually from the Manual KPI screen |

Choose the source type based on how the data exists today, not on what you hope to build later. You can start with **Manual**, then move to REST, WebSocket, or Ingest when the integration is ready.

If you are not sure which path to use:

- choose **REST API** for normal polling from an existing backend
- choose **WebSocket** for pushed live updates
- choose **Ingest** for a local gateway inside the plant network
- choose **Manual** when people will enter the values directly

---

## 2. REST API Data Source

The TV periodically calls your API endpoint to fetch fresh data.

### Settings

| Setting | Description |
| --- | --- |
| **Name** | A friendly name for this data source |
| **Base URL** | The full URL of your API endpoint, for example `https://api.example.com/production` |
| **HTTP Method** | `GET` or `POST` |
| **Refresh Interval** | How often the TV polls, in seconds |
| **Headers** | Optional HTTP headers such as API keys or auth tokens |

### GET vs POST

| Method | When to Use |
| --- | --- |
| **GET** | Simple fetch when no request body is needed |
| **POST** | When your backend needs context such as `prodline_id`, `device_id`, or `layout_id` |

When using **POST**, the TV can send runtime context such as:

```
{
  "prodline_id": "CH1",
  "prodlineID": "CH1",
  "reader_prodline_id": "CH1",
  "device_id": "device-xxx",
  "reader_device_id": "device-xxx",
  "layout_id": "layout-xxx",
  "playlist_slice_sec": 10,
  "playlist_remaining_sec": 10,
  "layout_duration_sec": 10,
  "timestamp": "2026-06-18T09:30:00Z"
}
```

Depending on the runtime path, Twinnoverse can also include fields such as:

- `delivery_id`
- `event_occurrence_id`
- `event_id`
- `event_key`
- `subject_type`
- `subject_id`
- `subject_name`
- `prod_line_index`
- `playlist_item_index`

### Expected Response Format

Your API should return JSON grouped by **widget type**, then by **widget label**:

```
{
  "kpi": {
    "PROD_TOTAL": {
      "title": "Total Production",
      "value": 1247
    }
  },
  "progress_bar": {
    "SHIFT_TARGET": {
      "current": 22,
      "total": 100
    }
  },
  "alerts_list": {
    "ALERTS": {
      "items": [
        { "time": "09:00", "count": 1, "label": "Alert 1", "severity": "warning" }
      ]
    }
  }
}
```

The **label** in your payload must match the **widget label** in the layout(you can define this in the layout editor).

The exact widget object shape depends on the widget family. For the full payload contract by widget type, use [Dashboard Widget Reference Guide](https://twinnoverse.com/docs/dashboard-widget-reference-guide/).

---

## 3. WebSocket Data Source

Use WebSocket when data should appear as soon as the backend publishes it.

### Settings

| Setting | Description |
| --- | --- |
| **Name** | A friendly name for this data source |
| **WebSocket URL** | The endpoint, for example `wss://stream.example.com/data` |
| **Subscription Message** | Optional JSON sent after connection |
| **Message Mode** | `Replace` or `Merge` |

### Subscription Message

You can use placeholders:

| Placeholder | Replaced With |
| --- | --- |
| `{{prodline_id}}` | Current production line ID |
| `{{prodlines_json}}` | JSON array of the device prodlines and active prodline |
| `{{device_id}}` | Current TV device ID |
| `{{layout_id}}` | Active layout ID |
| `{{layout_name}}` | Active layout name |

```
Example:

{
  "action": "subscribe",
  "prodlines": "{{prodlines_json}}",
  "device_id": "{{device_id}}",
  "layout_id": "{{layout_id}}"
}
```

### Expected Server Message Format

```
{
  "prodline": "CH1",
  "mode": "replace",
  "payload": {
    "kpi": {
      "WIP": { "title": "WIP Inventory", "value": 42 }
    }
  }
}
```

| Field | Required | Description |
| --- | --- | --- |
| `prodline` | Yes | Which production line the message belongs to |
| `mode` | No | `replace` or `merge`; defaults to the data source setting |
| `payload` | Yes | The widget data payload |

### Important Notes

- WebSocket data appears only after the server sends a message.
- The TV reconnects automatically if the connection drops.
- Use `merge` only if your backend intentionally sends partial updates.
- If the server does not send a production line field, the reader falls back to the active layout context.

---

## 4. Ingest Data Source

Use Ingest when the source system is on a local network and cannot expose a public API.

### When to Use Ingest

- Your machine, PLC, or local server is inside the plant network
- The local system can make outbound HTTPS calls
- You want a secure, firewall-friendly bridge to Twinnoverse

### How It Works

1. You create an Ingest data source in Twinnoverse.
2. Twinnoverse generates an **ingest endpoint** and **ingest token**.
3. Your local gateway posts snapshots to that endpoint.
4. The TV polls the latest accepted snapshot from Twinnoverse.

### Settings

| Setting | Description |
| --- | --- |
| **Name** | A friendly name |
| **Ingest Endpoint** | The fixed cloud endpoint |
| **Ingest Token** | The secret used by the gateway |
| **Refresh Config** | Refreshes connection details in the admin UI |
| **Rotate Key** | Generates a new token |
| **Revoke Key** | Disables the current token immediately |

### Gateway Sender Format

Send:

```
POST /functions/v1/ingest-data-source
Authorization: Bearer <your_ingest_token>
```

```
Body:

{
  "prodline_id": "CH1",
  "payload": {
    "kpi": {
      "PROD_TOTAL": { "title": "Total", "value": 1247 }
    }
  },
  "source_metadata": {
    "source": "gateway-name"
  }
}
```

---

## 5. Manual Data Source

Use **Manual** when you do not have an integration yet, or when the values must be entered by an operator, supervisor, or shift lead.

### When Manual Is the Right Choice

- You are launching quickly and the API is not ready
- The KPI values are typed in once per shift or once per hour
- The layout is shared by several TVs on the same production line
- Operators need direct control over alert text, counts, or status values

### How Manual Works

1. Create a data source with type **Manual**.
2. Assign that data source to a layout.
3. Open **Manual KPI** from the admin shell.
4. Select the **production line** and **layout**.
5. Click widgets in the preview and enter their runtime values.
6. Save the snapshot.
7. All TVs using that layout for that production line show the same saved values.

### Important Notes

- Manual data is saved per **layout + production line**, not per device.
- Manual KPI changes runtime values only.
- Layout structure, colors, titles, and theme still come from the layout itself.
- `clock` and runtime-context widgets are not edited through Manual KPI.

See [Manual KPI](https://twinnoverse.com/docs/manual-kpi-update-dashboards-without-an-api/) for the full workflow.

---

## 6. Assigning a Data Source to a Layout

1. Create your layout with widgets.
2. In the Layout Editor, deselect all widgets.
3. In the Inspector, choose the **Data Source** for the layout.
4. Save the layout.
5. Add the layout to a playlist and assign that playlist to a device.

Each layout can use **one data source at a time**.

---

## 7. Data Source Health

The TV taskbar and preview tools can show messages such as:

| Message | Meaning |
| --- | --- |
| `No data source assigned` | The layout is not linked to any data source |
| `Data source not found` | The linked data source was deleted |
| `Fetch error: ...` | The data source returned an error and the TV will retry |
| `Last fetch: ...` | The data source is working and reporting status normally |

---

## 8. Admin Preview and Data Sources

Twinnoverse also includes an admin preview path so you can inspect what a device should display without standing in front of the TV.

Important points:

- the preview uses the same runtime rendering logic as the Reader
- the preview can show data-source-related messages and fetch status
- preview is useful for checking payload shape, layout binding, and screen output before testing on the physical TV
- preview helps validate REST, WebSocket, Ingest, and Manual flows from the admin side

Use preview to answer questions like:

- is the layout bound to the correct data source?
- does the payload shape match the widget labels?
- is the device expected to show data or an error state?

Preview is a validation tool. The physical TV is still the final runtime target.

---

## 9. Best Practices

### Do

- Use REST for straightforward polling integrations
- Use WebSocket only when realtime push is truly needed
- Use Ingest when the source lives inside the factory network
- Use Manual when the data is operator-entered or no API exists yet
- Keep widget labels stable after you bind integrations

### Avoid

- Polling too aggressively
- Mixing manual and API expectations for the same layout without a clear process
- Deleting a data source that is still attached to active layouts
