Beyond the request/response RPC surface, ClutchCall exposes a realtime track API: a publisher streams a named track into the relay, and any number of subscribers receive it live over QUIC. Tracks ride MoQT (Media-over-QUIC Transport) and are fanned out by the ClutchCall relay mesh, so a robot, an agent, a browser, and a recorder can all consume the same stream without the publisher knowing they exist. Every SDK ships a MoqtClient with method names in that language’s idiomatic case. The C++, Python, and Go SDKs share one engine via the clutchcall_moqt_ffi native library; the TypeScript SDK is a standalone WebTransport implementation with its own queueing, late-join, and reconnect behaviour. Treat the two families as separate conformance surfaces — a result on one does not automatically carry to the other until they’re held to a common behaviour contract (publish/subscribe APIs match; queue depth, filter handling, and unsubscribe lifecycle can differ).

Track kinds

KindUse it forPer-object key
AudioContinuous voice (Opus / PCM / G.711).rollover ~1 s
VideoEncoded video; a group per keyframe (GOP).keyframe
FrameRobot telemetry, LIDAR, game state — opaque binary with a per-frame priority.per group
TextReliable ordered messages (chat, control).per 64 msgs
A track is addressed by a namespace + name (e.g. robot/turtlebot4-001
  • odom) and carries a capability string — an open-ended routing intent ("asr", "tts", "ros.telemetry", "media.passthrough") that the relay / gateway uses to route the track to whatever registered that capability. You route on intent, not on media kind.

Connect

from clutchcall.moqt import MoqtClient

client = MoqtClient.connect("quic://relay.clutchcall.dev", token="…",
                            on_state=lambda s: print("state", s))
connect returns immediately and dials in the background. The client auto-reconnects with capped exponential backoff if the link drops, and re-establishes every publication and subscription on each reconnect — your code does nothing. on_state reports the lifecycle:
StateMeaning
Connectingdialling the relay
Connectedsession up; tracks (re)attached
Reconnectinglink dropped; retrying with backoff
Closedyou called close()
Failedunrecoverable (e.g. bad URL)
You may publish or subscribe before the session is up — calls are queued and replayed once connected (and the relay holds a subscribe for a namespace that has not been announced yet, so a robot can subscribe to its command track before any controller has connected).

Publish & subscribe a frame track

Frame tracks carry opaque binary objects with a per-frame priority — the right fit for robot telemetry and game state. Below: a publisher streaming a track and a subscriber receiving it, fanned out through the relay.
from clutchcall.moqt import MoqtClient

pub = MoqtClient.connect("quic://relay.clutchcall.dev")
track = pub.publish_frame("robot/turtlebot4-001", "odom",
                          capability="ros.telemetry", schema_tag="ros2/cdr")
track.write(ts_us, cdr_bytes, priority=200)

sub = MoqtClient.connect("quic://relay.clutchcall.dev")
sub.subscribe_frame("robot/turtlebot4-001", "odom",
                    lambda ts, priority, data: handle(priority, data))
Keep the subscription handle alive for as long as you want frames. In garbage-collected languages (Python/Java/C#) it owns the native callback; if it is collected, the engine calls into freed memory. The publication handle owns the track — drop it (or call close) to stop publishing.

Audio tracks

Audio tracks are the same shape with codec metadata instead of a priority — publish_audio(ns, name, capability, sample_rate, channels, frame_ms) and subscribe_audio(ns, name, on_frame), where on_frame(ts_us, bytes) delivers one decoded object. Use them for live voice between an SDK client and an agent; the capability (“asr”, “tts”, …) routes the track to the right module.

Namespacing & routing

  • Telemetry vs commands: give command (inbound) tracks a distinct namespace from telemetry — e.g. publish telemetry under robot/<id> and subscribe commands under robot/<id>/ctl. If both share robot/<id>, the relay can route a command subscription to the robot’s own telemetry announce.
  • Capability is the routing key. Two publishers may use different capabilities on the same namespace; subscribers and modules select by intent.
  • Fan-out is free. The relay copies each object to every subscriber; the publisher opens one stream per group regardless of subscriber count.
See the per-language SDK reference for the full method list, and Architecture for how the relay mesh fans tracks out.