Skip to main content

Relays and the PeerJS transport

peerjsTransport() connects peers over WebRTC. A PeerJS relay (a signaling server) introduces them: it forwards connection offers between browsers until they can talk directly.

import { peerjsTransport } from "@vaultys/peer-sdk/peerjs";

const transport = peerjsTransport(); // the free public PeerJS cloud

What the relay sees​

Each peer registers under the SHA-256 hash of its DID. The relay sees those hashes, who tries to reach whom, and the handshake frames. It never sees message content, and it can't impersonate a peer or tamper with traffic (see Security model). It can, however, see metadata and refuse service. That's the main reason to run your own.

Running your own relay​

The official server is the peer package:

npx peer --port 9000

Point the transport at it:

const transport = peerjsTransport({
host: "relay.example.com",
port: 443,
path: "/",
secure: true,
});

The public cloud is fine for demos, but it's shared, rate-limited, and comes with no availability guarantee. Run your own for anything real.

TURN for restrictive networks​

WebRTC tries a direct connection first. Behind strict NATs or corporate firewalls, it needs a TURN server to relay the encrypted traffic. Pass ICE servers through PeerJS's config:

const transport = peerjsTransport({
host: "relay.example.com",
secure: true,
config: {
iceServers: [
{ urls: "stun:stun.example.com:3478" },
{ urls: "turn:turn.example.com:3478", username: "user", credential: "secret" },
],
},
});

Traffic through TURN stays end-to-end encrypted by the session.

Options​

peerjsTransport(options) accepts every PeerJS option (host, port, path, secure, key, config…) plus:

OptionDefaultDescription
addressOf(did)hex SHA-256 of the DIDHow a DID maps to a PeerJS id
timeoutMs15000Timeout for registering with the relay and for dialing
log(message)noneCalled on registration changes: drops, recoveries, retries
const transport = peerjsTransport({ host: "relay.example.com", log: (m) => console.info("[relay]", m) });

Staying registered​

The transport keeps its relay registration alive. When the signaling connection drops, it reconnects with backoff (1 s up to 30 s). It also checks every 10 seconds, when the browser comes back online, and when the tab becomes visible again, which covers sleeping laptops and frozen background tabs.

Open sessions don't depend on the relay, so they keep working through a relay outage. New connections wait until the registration is back: dialing in the meantime fails with UNREACHABLE, and queued messages are retried.

If you reload a page, its previous registration may still be held by the relay for a moment. Registration retries until it's released, within timeoutMs.