What is OpenRTC?
A simpler way to connect browser, desktop, and mobile apps
OpenRTC helps browser, desktop, and mobile apps find each other and exchange data, audio, and video. Your application works with a small, familiar API while OpenRTC handles the connection system underneath it.
Without OpenRTC, a peer-to-peer feature usually needs a signaling service, presence tracking, authentication, NAT traversal, relay servers, reconnect logic, transport switching, encryption, and separate browser and native implementations. OpenRTC provides those shared pieces as one managed runtime.
The big picture
An OpenRTC feature has three parts:
- An avenue decides which peers are allowed to find each other. Use a device mesh, space, room, or ticket session.
- A connection represents one peer. It stays stable while OpenRTC repairs or changes the physical route underneath it.
- Messages, streams, and media carry your application data over that connection.
devices / space / room / ticket
↓
one logical connection
↓
message · stream · media
↓
Iroh chooses and repairs the route
The route may use direct Iroh QUIC, an Iroh relay, WebRTC, or MoQ. Your message, stream, and media code stays the same when that route changes.
Start with one avenue
import { OpenRTC } from 'openrtc';
const rtc = OpenRTC({ apiKey: import.meta.env.VITE_OPENRTC_API_KEY });
const cursors = await rtc.spaces.join('portfolio-cursors', {
payload: 'latest-state',
});
const position = cursors.state<{ x: number; y: number }>('position');
position.watch(({ peerId, value }) => {
renderRemoteCursor(peerId, value);
});
position.set({ x: 120, y: 80 });
await cursors.leave();
await rtc.close();
Constructing the client performs no network, storage, auth, timer, WASM, or transport work. The first avenue you start activates only that feature.
Choose the smallest surface
| Product need | Capability | Default behavior |
|---|---|---|
| Signed-in users with several devices | rtc.devices.start() | Persistent device identity; connect only to online devices |
| Live cursors or an art experience | rtc.spaces.join() | Session identity and live-only membership |
| A match, call, or collaboration session | rtc.rooms.join() | Ephemeral membership |
| A bounded handoff session | rtc.tickets.issue() | Ephemeral, device-bound capability |
Each active avenue exposes its own peers, channels, diagnostics, and connections. Closing the handle ends only that feature.
Use the connection
For small structured values, send a message:
room.onConnection((connection) => {
connection.onMessage((message) => console.log(message));
void connection.send({ type: 'hello' });
});
For a long or large flow, open a stream. For camera and microphone tracks, use the media API. OpenRTC applies avenue scope, admission, encryption, recovery, and current-route checks before application data is delivered.
Durable membership, relay use, managed attestation, MoQ, and BLE require both
portal enablement and an explicit runtime request. Rooms default to auto:
mesh through eight members and eligible sparse latest-state fan-out through 50.
Managed and authority modes fail closed until their security, capacity, and
pricing gates pass.
Responsibility boundary
Your app owns login UX, its identity provider, product authorization, and platform-attestation registration. OpenRTC validates registered assertions or managed evidence, binds a per-install device key, issues scoped grants, enforces revocation and budgets, and meters OpenRTC usage credits.
OpenRTC does not require consumer apps to configure its Firebase project, database, storage, gateway URL, or internal app identifiers.
See Avenues for the complete TypeScript and Rust decision guide, including defaults, lifecycle, usage behavior, and examples for every avenue.
See Media, streams, and datagrams for the connection data APIs, and Advanced native for pure Rust and Tauri applications.
Specialized protocols
openrtc-netcodeowns matches and replicated/latest state.openrtc-file-transferowns bounded transfer protocol behavior.y-openrtcconnects Yjs to an already activated room handle.openrtc/runtimeis reserved for low-level adapters and specialized protocol integration.