> For the complete documentation index, see [llms.txt](https://docs.ndi.video/all/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ndi.video/all/developing-with-ndi/metadata-labs/chat-over-ndi-v1.0.md).

# CHAT over NDI v1.0

> Metadata Specification (v1.0)
>
> Roberto Musso, December 2025

## 1. Purpose

This document defines a small XML metadata format to carry **bidirectional text messages** over NDI metadata streams.

### Goals:

* Provide a simple, interoperable chat channel between NDI endpoints (UIs, controllers, gateways).
* Allow different devices/apps to map CHAT messages to their own UI (chat window, log panel, on-screen overlays, etc.).
* Support multi-participant scenarios via explicit `sessionId` and `senderId`.

This specification is intentionally minimal but extensible.

## 2. Design Overview

CHAT messages travel as NDI metadata frames whose root element is:

```xml
<ndi_metadata type="chat" version="1.0">...</ndi_metadata>
```

Inside the root, each metadata frame carries one or more “chat sessions”, each containing one or more “messages”.

High-level model:

* `<Session>`\
  A logical conversation or chat room (e.g. point-to-point, group, production channel).
* `<Message>`\
  A single chat event (text message, status, system notification).

Typical example (single session, single message):

```xml
<ndi_metadata type="chat" version="1.0"><Session id="session_production_A" scope="point_to_point"><Message><MessageId>msg_0001</MessageId><SenderId>director_room</SenderId><MessageType>text</MessageType><Text>Hello, ready on CAM 3?</Text><Lang>en</Lang><Format>plain</Format><Priority>normal</Priority><TimestampUtc>2025-12-06T10:15:30.123Z</TimestampUtc></Message></Session></ndi_metadata>
```

NDI endpoints decide how to interpret `Session.id`, `SenderId`, `MessageType`, etc., and how to render them in their UI.

## 3. Root Element

### 3.1 `<ndi_metadata>`

* Element name: `ndi_metadata`
* Attributes:
  * `type` (required): MUST be `"chat"`.
  * `version` (optional): schema version. Current: `"1.0"`.

Constraints:

* Exactly one `<ndi_metadata>` root element per NDI metadata frame.
* No XML prolog (`<?xml ... ?>`) – the XML fragment is embedded directly in the NDI metadata payload.
* Implementations SHOULD ignore NDI metadata frames whose `type` is not `"chat"`.

## 4. Session and Message Structure

### 4.1 `<Session>`

Represents a logical chat conversation.

* **Parent:** `<ndi_metadata>`
* Attributes:
  * `id` (required): identifier of the chat session.
    * SHOULD be stable and unique within the sender’s or facility’s context.
    * Recommended format: lower-case snake\_case or similar (e.g. `session_production_A`, `session_replay_room`, `global_broadcast`).
  * `scope` (optional): semantic scope of the session.
    * `point_to_point` – one-to-one conversation (e.g. director ↔ replay operator).
    * `group` – multi-participant (e.g. “production team”).
    * `broadcast` – messages intended for anyone listening.

Implementations MAY define additional values.

Multiple `<Session>` elements MAY appear in one metadata frame to carry messages for separate conversations.

Example with two sessions:

```xml
<ndi_metadata type="chat" version="1.0"><Session id="session_director_replay" scope="point_to_point">...</Session><Session id="session_control_room" scope="group">...</Session></ndi_metadata>
```

### 4.2 `<Message>`

Represents a single chat event within a session.

* Parent: `<Session>`
* Children (standard elements):
  * `<MessageId>`
  * `<SenderId>`
  * `<MessageType>`
  * `<Text>`
  * `<Lang>`
  * `<Format>`
  * `<Priority>`
  * `<InReplyTo>` (optional)
  * `<TimestampUtc>`

Order of child elements is not semantically significant, but examples use a consistent order for readability.

A single `<Session>` MAY contain multiple `<Message>` elements in one frame, for batching.

Example (session with two messages):

```xml
<ndi_metadata type="chat" version="1.0"><Session id="session_director_replay" scope="point_to_point"><Message><MessageId>msg_1001</MessageId><SenderId>director_room</SenderId><MessageType>text</MessageType><Text>We go to replay after this action.</Text><Lang>en</Lang><Format>plain</Format><Priority>normal</Priority><TimestampUtc>2025-12-06T10:16:05.000Z</TimestampUtc></Message><Message><MessageId>msg_1002</MessageId><SenderId>replay_room</SenderId><MessageType>text</MessageType><Text>Copy, ready with angle 2.</Text><Lang>en</Lang><Format>plain</Format><Priority>normal</Priority><InReplyTo>msg_1001</InReplyTo><TimestampUtc>2025-12-06T10:16:07.250Z</TimestampUtc></Message></Session></ndi_metadata>
```

## 5. Standard Message Elements

This section defines the standard child elements of `<Message>`.

Unless otherwise stated, all elements are optional but recommended. Implementations SHOULD ignore unknown elements and treat missing optional elements with sensible defaults.

Standard elements:

* `<MessageId>`
* `<SenderId>`
* `<MessageType>`
* `<Text>`
* `<Lang>`
* `<Format>`
* `<Priority>`
* `<InReplyTo>`
* `<TimestampUtc>`
* `<To>` (optional destination hint)

Order of elements is not semantically significant.

### 5.1 `<MessageId>`

Logical identifier of the message.

* Parent: `<Message>`
* Type: string.
* Usage: SHOULD be unique within the context of a session (`Session.id`).
  * Useful for de-duplication, threading, and acknowledgements.

Examples:

* `msg_0001`
* `d_20251206_00123`
* `replay_room_000045`

If omitted, receivers MAY generate a local identifier, but SHOULD treat such messages as not safely referenceable (e.g. for threading).

### 5.2 `<SenderId>`

Identifier of the originator of the message.

* **Parent:** `<Message>`
* **Type:** string

Semantics:

* Logical identity of the chat participant (UI, controller, device).
* SHOULD be stable and unique within the chat domain (e.g. facility, production, or logical application domain).

Examples:

* `director_room`
* `replay_room`
* `automation_1`
* `studio_A_panel`

Receivers can use `SenderId` to:

* render distinct labels or colors,
* tag messages by origin (for logs, filters),
* enforce access control policies if desired.

If omitted, receivers MAY treat the message as anonymous.

### 5.3 `<MessageType>`

Type of the message.

* **Parent:** `<Message>`
* **Type:** string (enum)

Recommended baseline values:

* `text` – standard human-readable chat text.
* `system` – system notification (join/leave, warnings, status).
* `typing` – typing indicator (user is composing).
* `ack` – acknowledgement of another message (often used with `InReplyTo`).
* `custom` – application-specific type (requires extra semantics on top of).

Implementations:

* SHOULD support at least `text`.
* MAY define additional values as needed.
* SHOULD NOT fail if encountering unknown values; instead, they MAY fall back to generic handling (e.g. render as standard text).

Examples:

```xml
<MessageType>text</MessageType>
<MessageType>system</MessageType>
<MessageType>typing</MessageType>
```

If omitted, receivers MAY assume `text` as a default, but this is not required.

### 5.4 `<Text>`

Message content.

* **Parent:** `<Message>`
* **Type:** UTF-8 string

Semantics:

* For `MessageType="text"`: the actual chat text.
* For `MessageType="system"`: human-readable system message (status, alerts).
* For other types: MAY be used as a human-friendly description; precise semantics are implementation-specific.

Implementations SHOULD support at least plain text rendering.

Example:

```xml
<Text>Hello, ready on CAM 3?</Text>
```

Size considerations

NDI metadata is not intended for very large payloads. Implementations SHOULD:

* keep `<Text>` reasonably short (typical chat messages),
* avoid using CHAT for large blobs or file transfer.

For large content, an out-of-band mechanism is recommended (e.g. URL or reference), with CHAT used to carry references plus short human-readable descriptions.

### 5.5 `<Lang>`

Language of the message, if known.

* **Parent:** `<Message>`
* **Type:** string
* **Format:** recommended BCP 47 language code, e.g.:
  * `en`, `it`, `fr`
  * `en-US`, `pt-BR`

If omitted, receivers MAY assume a default language or ignore language information entirely.

Example:

```xml
<Lang>en</Lang>
```

This field is primarily useful for:

* multi-language environments,
* filtering or UI adaptations based on language.

### 5.6 `<Format>`

Text formatting description.

* **Parent:** `<Message>`
* **Type:** string (enum)

Recommended values:

* `plain` – plain text, no markup.
* `markdown` – Markdown or a constrained subset.
* `html` – HTML snippet (use only in trusted environments).

If omitted, receivers SHOULD treat the text as plain.

Example:

```xml
<Format>plain</Format>
```

Implementations that do not support rich text MAY:

* ignore formatting hints,
* render the content as plain text.

CHAT does not prescribe a specific Markdown or HTML subset; this is application-specific.

### 5.7 `<Priority>`

Relative priority or urgency.

* **Parent:** `<Message>`
* **Type:** string (enum)

Recommended values:

* `low`
* `normal`
* `high`
* `critical`

Usage examples:

* `low` – non-essential information, debug chatter.
* `normal` – regular production chat.
* `high` – attention-critical; UI may highlight or pin the message.
* `critical` – urgent; UI may trigger audible alerts or overlays.

Example:

```xml
<Priority>normal</Priority>
```

If omitted, receivers SHOULD treat priority as normal.

Applications MAY map these values to their own severity or notification systems.

### 5.8 `<InReplyTo>`

Reference to another message.

* **Parent:** `<Message>`
* **Type:** string

Semantics:

* Contains the `MessageId` of a previous message within the same session.
* Used to express:
  * simple reply threads,
  * acknowledgements (with `MessageType="ack"`),
  * correlations between command and response messages.

Example (acknowledgement):

```xml
<Message> <MessageId>msg_1003</MessageId> <SenderId>replay_room</SenderId> <MessageType>ack</MessageType> <InReplyTo>msg_1001</InReplyTo> <Text>Received.</Text> <Lang>en</Lang> <Format>plain</Format> <Priority>normal</Priority> <TimestampUtc>2025-12-06T10:16:08.500Z</TimestampUtc></Message>
```

Receivers MAY:

* group messages by `InReplyTo` for threaded display,
* use it for correlation in logs or automation,
* ignore it if threading is not implemented.

If `InReplyTo` points to an unknown `MessageId`, the receiver SHOULD still accept the message but may not be able to render the full thread context.

### 5.9 `<TimestampUtc>`

Timestamp of when the message was generated, in UTC.

* **Parent:** `<Message>`
* **Type:** string (ISO 8601 / RFC 3339)
* Format:
  * `YYYY-MM-DDThh:mm:ssZ`, or
  * `YYYY-MM-DDThh:mm:ss.sssZ` for millisecond precision.

Example:

```xml
<TimestampUtc>2025-12-06T10:15:30.123Z</TimestampUtc>
```

Usage:

* hOLA

Implementations SHOULD preserve `TimestampUtc` when re-emitting or relaying messages.

### 5.10 `<To>` (optional destination hint)

Optional routing hint for intended recipient(s) within a session.

* **Parent:** `<Message>`
* **Type:** string

Semantics:

* If `<To>` is **omitted**, the message SHOULD be treated as **broadcast** to all participants in the session (`Session.id`).
* If `<To>` is present, it identifies one or more intended recipients using the same logical ID space as `SenderId`.

Single-recipient example (unicast A → B):

```xml
<Message>

<MessageId>msg_2001</MessageId>

<SenderId>A</SenderId>

<MessageType>text</MessageType>

<Text>@B ready for next take?</Text>

<Lang>en</Lang>

<Format>plain</Format>

<Priority>normal</Priority>

<To>B</To>

<TimestampUtc>2025-12-06T11:30:00.000Z</TimestampUtc>

</Message>
```

Multi-recipient example (A → B and C):

```xml
<To>B,C</To>
```

* Multiple recipients MAY be specified as a comma-separated list.
* Implementations SHOULD trim whitespace around each ID when parsing.

Usage notes:

* `<To>` is a **hint** that intermediaries (e.g. an NDI sender acting as a hub) or receivers MAY use to implement:
  * unicast routing (only to a specific participant),
  * multicast routing (subset of participants),
  * or filtering logic at the receiver.
* Applications that do not understand or use `<To>` SHOULD ignore it and treat the message as broadcast.

In user-facing chat UIs, `<To>` is often derived from conventions in `<Text>` such as `@recipient`. Parsing such conventions is considered application logic and is out of scope for this specification.

## 6. Participant Identity & Multi-Endpoint Scenarios

In many NDI workflows:

* A single NDI source can have multiple receivers (workstations, panels, automation, etc.).
* Each receiver could send CHAT metadata back to the same source.

To keep semantics clear:

* `Session.id` identifies the **conversation** (logical room / channel).
* `SenderId` identifies the **participant**.

**Recommended practices:**

1. Stable participant IDs

Each UI or controller SHOULD use a stable `SenderId` (e.g. `director_room`, `replay_room`) instead of per-connection IDs.

2. Access control

Implementations MAY define policies:

* Allow all `SenderId` for a given `Session.id`.
* Restrict write access to a subset of `SenderId`.
* Treat some sessions as read-only or system-only.

3. Anonymous senders

If a system does not set `SenderId`, receivers MAY treat messages as anonymous and:

* display a generic origin (`Unknown`), or
* ignore them in strictly controlled environments.

Unlike GPIO, CHAT typically does not require strict single-controller arbitration, so there is no **required controllerId** equivalent. However, implementations MAY combine `SenderId` with NDI connection information for additional policies if needed.

## 7. Typical Usage Patterns

### 7.1 Point-to-point chat (director ↔ replay)

* Use a dedicated `Session.id`, e.g. `session_director_replay`.
* Both sides send `Message` elements within that session.
* Receivers display messages from all `SenderId` in that session.

Example:

```xml
<ndi_metadata type="chat" version="1.0">

<Session id="session_director_replay" scope="point_to_point">

<Message>

<MessageId>d_0001</MessageId>

<SenderId>director_room</SenderId>

<MessageType>text</MessageType>

<Text>Next: slow-mo on CAM 2.</Text>

<Lang>en</Lang>

<Format>plain</Format>

<Priority>high</Priority>

<TimestampUtc>2025-12-06T10:20:00.000Z</TimestampUtc>

</Message>

</Session>

</ndi_metadata>
```

### 7.2 Group chat (control room)

* `Session.id = "session_control_room"`, `scope="group"`.
* Multiple participants (`SenderId`) write to the same session.
* UI may visually distinguish participants by color or label.

### 7.3 System notifications

* `MessageType = "system"`.
* Used for join/leave notices, warnings, or status messages, possibly generated by automation rather than humans.

Example:

```xml
<Message>

<MessageId>sys_0001</MessageId>

<SenderId>automation_1</SenderId>

<MessageType>system</MessageType>

<Text>Recording started on server A.</Text>

<Lang>en</Lang>

<Format>plain</Format>

<Priority>high</Priority>

<TimestampUtc>2025-12-06T10:21:10.000Z</TimestampUtc>

</Message>
```

## 8. Extensibility & Vendor-Specific Fields

The core schema is intentionally small. Implementations MAY add extension elements or attributes, provided that:

* Extensions do not break receivers that ignore unknown elements/attributes.
* Core semantics (`Session`, `Message`, `Text`, `TimestampUtc`, etc.) remain intact.

Examples of possible extensions:

* Delivery status (e.g. `Delivered`, `Seen`).
* Rich presence information (online/offline).
* Additional routing hints (e.g. severity categories, channel mapping).

Recommended pattern:

* Use extra child elements within `<Message>` or `<Session>`.
* If needed, use XML namespaces or identifiable prefixes to avoid collisions.

## 9. Evolution

* Senders SHOULD include a `version` attribute on `<ndi_metadata>` (e.g. `"1.0"`).
* Receivers SHOULD:
  * ignore unknown elements and attributes,
  * use sensible defaults for missing optional fields.

Future versions may:

* add optional elements (delivery receipts, presence, attachments metadata),
* refine recommended enums (`MessageType`, `Priority`, etc.),
* define best practices for latency, batching, or message ordering.

Implementations SHOULD be written to be **forward-compatible**, especially regarding:

* new `MessageType` values,
* new optional message fields,
* additional `scope` values for `<Session>`.

## 10. Summary

The CHAT over NDI metadata format defines:

* A root `<ndi_metadata type="chat">` element.
* A flexible hierarchy of:
  * `<Session>` (conversation container),
  * `<Message>` (individual chat events).
* Core message elements:
  * `MessageId`, `SenderId`, `MessageType`, `Text`, `Lang`, `Format`, `Priority`, `InReplyTo`, `TimestampUtc`.

On top of this neutral, NDI-friendly schema, endpoints are free to:

* Render messages in chat windows, logs, or on-screen overlays.
* Implement UI features like threading, acknowledgements, and priorities.
* Evolve their internal behavior without changing the on-wire XML contract.

This approach keeps NDI metadata **clean and protocol-agnostic**, while enabling a simple, interoperable, bidirectional text messaging system across NDI-based workflows.


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter, and the optional `goal` query parameter:

```
GET https://docs.ndi.video/all/developing-with-ndi/metadata-labs/chat-over-ndi-v1.0.md?ask=<question>&goal=<endgoal>
```

`ask` is the immediate question: it should be specific, self-contained, and written in natural language.
`goal` is optional and describes the broader end goal you are ultimately trying to accomplish on behalf of the user. GitBook uses it to tailor the answer towards what is most useful for that goal.

The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
