JavaScript SDK — @metered-ca/peer
The official browser + Node SDK for Metered Realtime Messaging. Speaks the same wire protocol as the raw WebSocket path, with the framing, reconnection, ack correlation, presence diffing, perfect-negotiation WebRTC, and TURN credential injection done for you.
npm install @metered-ca/peer
~10 KB gzipped for pub/sub-only use, ~30 KB combined with WebRTC. ESM + CJS + UMD bundles. Zero runtime dependencies — everything else comes from the browser (or Node 22+).
Pick your path
The SDK ships two public classes. Pick by what you're building:
| You're building… | Use | Why |
|---|---|---|
| WebRTC video / voice call, screen share, peer-to-peer game | MeteredPeer | Joins a channel, discovers peers via presence, manages each RTCPeerConnection for you, fans MediaStreams out automatically, recovers ICE on network changes |
| Live chat with presence, classroom roster, multiplayer lobby | MeteredPeer | The peer-joined / peer-left events drive your UI; peer.send(data) broadcasts or directs |
| IoT telemetry, MQTT-style pub/sub, AI agent message bus, collaborative cursors | SignallingClient | Pub/sub + directed messages without the WebRTC overhead. Smaller, simpler, multiple channels per connection |
Not sure? Start with MeteredPeer. Drop down to SignallingClient later if you find you don't need the channel-+-peer model.
What the SDK does for you
These are the things you'd write yourself if you used the raw WebSocket path — the SDK handles them:
- Framing + ack correlation — every
subscribe,publish,sendresolves a promise when the server acks - Auto-reconnect with exponential backoff, jitter, and close-code-aware behaviour (terminal codes stop retrying, rate-limit codes slow-backoff, etc.)
- Token refresh — your
tokenProvideris re-invoked on every reconnect so JWT-rotated TURN creds + permissions land automatically - Inactivity watchdog — if the server stops sending frames, the SDK closes-and-reconnects instead of leaving you on a half-dead socket
- Presence diff — translates raw
presenceevents into per-peerpeer-joined/peer-leftso your UI doesn't have to diff rosters - Perfect negotiation — automatic SDP + ICE handling with a tie-breaker that prevents glare
- ICE-restart ladder — 9 retries spanning ~121 s for WebRTC-level recovery (Wi-Fi → cellular roam, TURN failover)
- Channel-level reconcile — when the signalling socket drops, your
RemotePeerreferences survive the reconnect; only the underlyingRTCPeerConnectionis swapped (see Reconnect Best Practices)
What your code still owns
The SDK does not silently make decisions on your behalf for things that affect UX or billing. You still own:
- Auth mode + token minting — see Authentication
- Reconnect UI — the SDK fires
state-changeevents; how (or whether) you surface a "reconnecting…" banner is up to you. See Reconnect Best Practices for the standard patterns - Token expiry handling — if your
tokenProviderkeeps failing, the SDK fires atoken-provider-errorevent after 3 consecutive failures. Show a "please log in again" prompt - DataChannel reopening — if you use the
remote.pc.createDataChannel(...)escape hatch for P2P data, those handles don't survive a reconnect. See Data Channels & Low Latency - Channel naming + JWT claims — your backend decides who can subscribe to what; the SDK enforces what the server tells it
Where to start
| If you want to… | Go here |
|---|---|
| Get something running in 5 minutes | Getting Started |
| Build a WebRTC video call | Guide: WebRTC Video Call |
| Build a video call from a static site with no backend | Guide: WebRTC No Backend |
| Build chat / presence / a lobby | Guide: Presence & Chat |
| Wire up AI agents | Guide: AI Agent Communication |
| Pipe IoT telemetry | Guide: IoT Telemetry |
| Handle reconnects properly (production-grade) | Guide: Reconnect Best Practices |
| Port from simple-peer / PeerJS | Migration: from simple-peer · from PeerJS |
| Look up a method / event | API Reference: MeteredPeer · SignallingClient |
Or — use the raw WebSocket path
The SDK is the recommended path for JavaScript + TypeScript apps. If you're on a stack the SDK doesn't cover (Go, Python, Java, Swift, Kotlin, Rust, Unity/C#, etc.), implement the protocol directly. Everything the SDK does on top of the wire is documented in the Protocol Reference and the Use Case Guides show end-to-end raw-WS code for the same scenarios.
The SDK speaks the same protocol byte-for-byte. You can mix and match — an SDK client and a raw-WS client can be peers in the same channel.