Skip to main content

On This Page

Building 1:1 WebRTC Video Calls without Signaling Server Boilerplate

3 min read
Share

These articles are AI-generated summaries. Please check the original sources for full details.

WebRTC Video Call Tutorial: Build a 1:1 Video Chat in JavaScript with @metered-ca/peer

The @metered-ca/peer SDK simplifies WebRTC by abstracting signaling and NAT traversal. It replaces manual Node/Socket.IO server setups with a managed endpoint and publishable-key authentication.

Why This Matters

Raw WebRTC implementations often fail in production because they ignore the ‘NAT wall’ and network instability. While STUN handles basic discovery, roughly one-third of real-world connections require TURN relays to bypass symmetric NATs and firewalls. Additionally, raw WebRTC lacks built-in reconnection, meaning any network blip typically kills the call unless the developer manually implements ICE restarts and renegotiation.

Key Insights

  • Managed Signaling: The SDK connects to wss://rms.metered.ca/v1, removing the need for developers to host 150–250 lines of Node/WebSocket signaling code (2026).
  • NAT Traversal: The Open Relay Project provides 20 GB/month of free TURN bandwidth to solve the issue where ~33% of connections cannot establish direct P2P paths (accessed 2026-06-01).
  • Three-Layer Reconnection: Automatic recovery is handled via WebSocket exponential backoff, per-peer ICE restarts over ~121 seconds, and channel reconciliation to preserve peer object identity.
  • Channel Model vs Peer ID: Shift from dialing individual IDs (e.g., peer.call(id)) to joining a shared channel string where media is fanned out via addStream().
  • Secure Context Requirement: getUserMedia only initializes over HTTPS or localhost; file:// paths will throw NotAllowedError or NotFoundError.

Working Examples

Complete singlefile implementation for a 1:1 WebRTC video call using MeteredPeer.

<!doctype html>
<html>
<head>
<meta charset="utf-8" />
<title>WebRTC video call — @metered-ca/peer</title>
<style>
video { width: 320px; background: #111; border-radius: 8px; margin: 4px; }
body { font-family: system-ui, sans-serif; padding: 16px; }
#status { color: #6d5efc; font-weight: 600; }
</style>
</head>
<body >
<h1 >2-tab WebRTC video call</h1>
<button id="join">Join call</button>
<p id="status">idle</p>
<div>
<video id="local" autoplay playsinline muted></video>
<video id="remote" autoplay playsinline></video>
</div>
<script type="module">
import { MeteredPeer } from "https://esm.sh/@metered-ca/[email protected]";
const CHANNEL = "room-42"; 
const PK = "pk_live_REPLACE_ME"; 
const localVideo = document.getElementById("local");
const remoteVideo = document.getElementById("remote");
const statusEl = document.getElementById("status");
document.getElementById("join").onclick = async () => {
const localStream = await navigator.mediaDevices.getUserMedia({
video: true,
audio: true,
});
localVideo.srcObject = localStream;
const peer = new MeteredPeer({ apiKey: PK });
pier.on("peer-joined", ({ peer: remote }) => {
remote.on("stream-added", ({ stream }) => {
remoteVideo.srcObject = stream;
ity});
remote.on("state-change", ({ to }) => {
statusEl.textContent = to;
ity});
ity});
pier.addStream(localStream, { role: "camera" });
await pier.join(CHANNEL);
asstatusEl.textContent = "joined " + CHANNEL;
ity};
script>

Practical Applications

  • .

References:

Continue reading

Next article

Evidence-First AI Security: Building the EllipticZero Research Lab

Related Content