Transports
Keep one Iroh session while choosing direct, WebRTC, or MoQ packet paths
OpenRTC separates coordination from payload. The Cloudflare gateway establishes the scoped avenue; Rust owns admission, the peer session, path proof, replacement, retry, and recovery in native and browser/WASM runtimes.
Most applications should omit transports. OpenRTC starts one Iroh endpoint
and chooses its normal direct or relay path automatically.
Use direct-only mode only when the application accepts failed connections on networks that require a relay:
const rtc = OpenRTC({
apiKey,
transports: { webrtc: true, relay: false },
});
use openrtc::client::TransportConfig;
let transports = TransportConfig {
relay: false,
..Default::default()
};
Both forms must be applied before the Iroh endpoint starts. They remove Iroh relay, TURN, and MoQ routes while retaining eligible direct routes. See the transport API reference for portal precedence, defaults, and rate-limit semantics.
const rtc = OpenRTC({
apiKey,
transports: {
webrtc: true,
moq: {
relayUrl: 'https://draft14-relay.example.com/moq',
accessToken: await shortLivedMoqToken(),
},
},
});
WebRTC and MoQ are Iroh packet carriers. Application code keeps using the same Iroh streams and channels regardless of which physical carrier Rust selects.
Carrier negotiation reuses the admitted peer control stream. It does not open another gateway socket, presence subscription, device row, or cloud retry loop. The current admitted Iroh path stays usable until a generation-current carrier passes protected proof and is committed atomically. Network changes, wake, background/resume, and carrier failure wake that same Rust owner; delayed work from retired generations is ignored.
webrtc: true is the minimal WebRTC-carrier switch. MoQ requires an explicit
relay URL. There is no separate implementation selector or external
application-data upgrade.
When both carriers are configured, OpenRTC does not start both. The Rust peer-session policy chooses one mutually supported carrier from the exact route priority and advances only after terminal failure. This avoids duplicate transport setup and negotiation traffic.
use openrtc::client::{Client, MoQConfig, TransportConfig, WebRTCConfig};
let transports = TransportConfig {
relay: true,
webrtc: Some(WebRTCConfig {
lan_mode: true,
..Default::default()
}),
moq: Some(MoQConfig {
relay_url: "https://draft14-relay.example.com/moq".into(),
access_token: short_lived_moq_token(),
}),
optimize_for: openrtc::route_policy::RouteOptimization::Balanced,
route_priority: vec![
openrtc::route_policy::KnownRoute::IrohLan,
openrtc::route_policy::KnownRoute::IrohQuic,
openrtc::route_policy::KnownRoute::IrohWebRtc,
openrtc::route_policy::KnownRoute::IrohMoq,
openrtc::route_policy::KnownRoute::IrohRelay,
],
..Default::default()
};
let client = Client::builder(api_key, identity)?
.transport_config(transports)
.signaling_backend(avenue.signaling())
.build();
WebRTC carriers use the negotiated unreliable, unordered data channel
openrtc-iroh-packets-v1 (ID 1). MoQ carriers require an explicit compatible
Draft 14 relay and use FIFO, send-complete subgroup objects; credentials must
remain separate from the relay URL.
Direct application payload does not consume relay credits. Managed relay usage is measured and shown in the Developer Portal.
Privacy and latency policy
TypeScript uses privacy: 'relay-only'; Rust uses
TransportConfig::privacy_mode. Both remove direct Iroh and nearby routes,
disable BLE/local discovery, and require relay-only WebRTC ICE. This provides
peer-address privacy, not anonymity from service operators or account systems.
The policy fails closed when no eligible relay route succeeds.
TransportConfig::iroh_relay_only is the advanced, Iroh-only endpoint switch.
It does not silently constrain WebRTC, MoQ, BLE, or exact route priority.
For latency-sensitive native applications, set
RouteOptimization::LowestLatency. OpenRTC compares passive, proven Iroh
and WebRTC RTTs without creating another probe loop. It changes preference only
for an improvement of at least 20 ms, after five seconds of candidate
stability, a 30-second current-route hold, and with samples at most ten seconds
old. Browser carriers continue to use deterministic priority because inactive
carrier measurement would create the very parallel traffic this policy avoids.
Transport state is host-reported. Do not infer native WebRTC, MoQ, LAN, or BLE capability from TypeScript constants.