Using ExpressTURN with simple-peer

A few lines of config. Calls connect through corporate firewalls and carrier-grade NAT.

Pass iceServers via the config option

simple-peer accepts a config object that's forwarded to the underlying RTCPeerConnection. That's where the TURN credentials go.

// npm install simple-peer
import Peer from 'simple-peer';

const turnConfig = {
  iceServers: [
    { urls: 'stun:stun.expressturn.com:3478' },
    {
      urls: [
        'turn:relay1.expressturn.com:3478?transport=udp',
        'turn:relay1.expressturn.com:3478?transport=tcp',
        'turns:relay1.expressturn.com:443?transport=tcp'
      ],
      username: 'YOUR_EXPRESSTURN_USERNAME',
      credential: 'YOUR_EXPRESSTURN_PASSWORD'
    }
  ]
};

// Initiator
const peer1 = new Peer({ initiator: true, trickle: true, config: turnConfig });

// Responder
const peer2 = new Peer({ trickle: true, config: turnConfig });

peer1.on('signal', data => peer2.signal(data));
peer2.on('signal', data => peer1.signal(data));
peer1.on('connect', () => peer1.send('hello'));
peer2.on('data', d => console.log('got:', d.toString()));

Streams (audio / video)

Adding a stream option doesn't change the TURN config — same iceServers array works for data, audio, and video.

const stream = await navigator.mediaDevices.getUserMedia({ audio: true, video: true });
const peer = new Peer({ initiator: true, stream, config: turnConfig });
peer.on('stream', remoteStream => document.querySelector('video').srcObject = remoteStream);

Force-relay testing

const peer = new Peer({
  initiator: true,
  config: { ...turnConfig, iceTransportPolicy: 'relay' }
});

Common pitfalls

  • Trickle ICE off: simple-peer's trickle: false mode waits for all candidates before signaling. Works but slower; leave trickle on for production.
  • Missing TLS-443: Without turns:relay1.expressturn.com:443 you'll fail behind strict corporate firewalls.
  • Backend signaling delay: If your signaling server is slow, ICE candidates pile up before transmission. Use a fast WebSocket relay.

Related: PeerJS recipe · mediasoup recipe

Done.

Get Free TURN Credentials