WebRTC for Node.js, React Native and browser.
- Direct connections. ICE uses STUN for NAT traversal, with TURN relay fallback.
- Low latency. Real-time audio, video and data, with adaptive bitrate.
- Network resilience. Handles packet loss, jitter and network changes.
- Secure by default. DTLS-SRTP encrypts media, while DTLS protects data channels.
- Data channels. SCTP supports ordered or unordered, reliable or unreliable delivery.
- Open ecosystem. Built on W3C and IETF specs, with interoperable implementations.
- One API everywhere.
RTCPeerConnectionacross browsers, Node.js and React Native.
Questions or ideas? Open a GitHub issue :)
Usage
const { RTCPeerConnection } = require('webrtc-runtime') const a = new RTCPeerConnection() const b = new RTCPeerConnection() const signalingA = perfectNegotiation(a, true, signal => signalingB(signal)) const signalingB = perfectNegotiation(b, false, signal => signalingA(signal)) a.ondatachannel = e => { e.channel.onmessage = msg => { console.log('A:', msg.data) e.channel.send('Hello from A') } } const channel = b.createDataChannel('test') channel.onopen = () => channel.send('Hello from B') channel.onmessage = e => console.log('B received:', e.data)
Modern WebRTC perfect negotiation (2020+):
- Automatic offer/answer via
setLocalDescription()without arguments (M80+). - Implicit rollback on colliding offers via
setRemoteDescription()(M80+). - Reliable
negotiationneededand glare handling (M87+).
https://w3c.github.io/webrtc-pc/#perfect-negotiation-example
Click to see a perfect negotiation example
function perfectNegotiation (pc, polite, send) { let makingOffer = false let ignoreOffer = false let settingAnswer = false pc.onnegotiationneeded = async () => { try { makingOffer = true await pc.setLocalDescription() send({ description: pc.localDescription }) } catch (e) { console.error(e) } finally { makingOffer = false } } pc.onicecandidate = ({ candidate }) => { send({ candidate }) } async function receive ({ description, candidate }) { try { if (description) { const readyForOffer = !makingOffer && (pc.signalingState === 'stable' || settingAnswer) const collision = description.type === 'offer' && !readyForOffer ignoreOffer = !polite && collision if (ignoreOffer) return try { settingAnswer = description.type === 'answer' await pc.setRemoteDescription(description) } finally { settingAnswer = false } if (description.type === 'offer') { await pc.setLocalDescription() send({ description: pc.localDescription }) } } else if (candidate) { try { await pc.addIceCandidate(candidate) } catch (e) { if (!ignoreOffer) throw e } } } catch (e) { console.error(e) } } return receive }
Signaling
Complete solution with perfect negotiation and signaling built-in:
https://github.com/lukks/like-webrtc (uses webrtc-runtime internally)
Versions
Other wrtc packages are outdated using M81 or M106.
We use recent WebRTC builds:
- Node.js with
@lukks/wrtcuses M154. - React Native with
react-native-webrtcuses M155. - Browsers and WebViews use ~M150–M157 (Nov 2026).
License
MIT. Copyright (c) Lucas Barrena