Skip to main content

Python SDK — metered-realtime

The official async Python SDK for Metered Realtime Messaging. Speaks the same wire protocol as the JavaScript SDK and the raw WebSocket path, with framing, reconnection, ack correlation, presence diffing, perfect-negotiation WebRTC, and TURN credential injection done for you — so a Python peer is indistinguishable from a browser peer in the same room.

pip install "metered-realtime[webrtc]"

Built on asyncio, websockets, and aiortc. Requires Python 3.10+. Pub/sub-only installs (pip install metered-realtime) pull in just websockets; the webrtc extra adds the media stack.

What it's for

Python is where server-side and edge realtime lives — the places a browser can't reach:

  • AI voice agents that join a room to run speech-to-text → LLM → text-to-speech
  • IoT / telemetry bridges and edge gateways that relay camera/sensor data
  • Recording bots, transcription workers, headless automation
  • Server-side pub/sub — a backend that publishes to, and listens on, channels

A Python MeteredPeer shares a channel with browser and React Native peers transparently: it exchanges audio/video/data with them over real WebRTC and sees the same presence.

Pick your path

The SDK ships two public classes. Pick by what you're building:

You're building…UseWhy
AI agent in a call, media bridge, recording bot, anything exchanging audio/video/data with peersMeteredPeerJoins a channel, discovers peers via presence, manages each peer connection, fans your media out automatically, recovers ICE on network changes
Presence + chat, a roster, a coordination busMeteredPeerThe PeerJoined / PeerLeft events drive your logic; peer.send(data) broadcasts or peer.send_to(id, data) directs
IoT telemetry, pub/sub message bus, fan-out without mediaSignallingClientPub/sub + directed messages without the WebRTC overhead. Smaller, simpler, multiple channels per connection

Not sure? Start with MeteredPeer. Drop to SignallingClient later if you find you don't need the channel-+-peer model.

The event model — one mechanism, three surfaces

Every emitter (MeteredPeer, RemotePeer, DataChannel, SignallingClient) carries typed, frozen-dataclass events. Subscribe in whichever style fits:

from metered_realtime import MeteredPeer, PeerJoined, Data

async with MeteredPeer(api_key="pk_live_…") as peer:
@peer.on(PeerJoined) # 1. decorator, keyed by event TYPE
def _(ev: PeerJoined) -> None:
print("joined:", ev.peer.id)

await peer.join("room-42")

async for msg in peer.events(Data): # 2. async-iterator stream
if msg.data == "stop":
break

@peer.on(EventType) registers a handler (sync or async def — async handlers are scheduled and tracked for you). peer.events(EventType) returns a buffered async iterator. And async with MeteredPeer(...) as peer: closes the peer on exit.

What the SDK does for you

These are the things you'd write yourself against the raw protocol — the SDK handles them:

  • Framing + ack correlation — every subscribe / publish / send awaits the server ack
  • Auto-reconnect with exponential backoff, jitter, and close-code-aware behaviour (terminal codes stop retrying; rate-limit codes slow-backoff)
  • Token refresh — your token_provider is re-invoked on every reconnect, so rotated JWTs + TURN creds land automatically
  • Inactivity watchdog — a half-dead socket is closed and reconnected instead of silently stalling
  • Presence diff — raw presence frames become per-peer PeerJoined / PeerLeft
  • Perfect negotiation — SDP + ICE handled with a tie-breaker that prevents glare, adapted to the aiortc backend
  • ICE recovery — automatic per-peer connection recovery on network change / TURN failover
  • Identity-preserving reconnect — when the signalling socket drops, your RemotePeer references survive; only the underlying connection is swapped (see Reconnect Best Practices)

Media: you provide the track

There is no getUserMedia server-side, so you supply the media — which is the SDK's strength for agents and bridges. Built-in helpers (media reference):

Any aiortc-compatible track works too — pass it straight to add_track.

Where to start

If you want to…Go here
Get something running in 5 minutesGetting Started
Wire up an AI voice agentGuide: AI Agent Communication
Bridge an IoT / edge cameraGuide: IoT Telemetry
Handle reconnects properly (production-grade)Guide: Reconnect Best Practices
Move from publishable keys to JWTsGuide: Authentication
Look up a method / eventAPI Reference: MeteredPeer · SignallingClient

Interop with other SDKs

The Python SDK speaks the protocol byte-for-byte. A Python MeteredPeer, a browser @metered-ca/realtime peer, a React Native peer, and a raw-WebSocket client can all be peers in the same channel — the canonical case being a Python AI agent in a call with a browser human.