Gathering detailed insights and metrics for simple-peer-light
Gathering detailed insights and metrics for simple-peer-light
Gathering detailed insights and metrics for simple-peer-light
Gathering detailed insights and metrics for simple-peer-light
npm install simple-peer-light
Typescript
Module System
Node Version
NPM Version
76.7
Supply Chain
99.5
Quality
75.3
Maintenance
100
Vulnerability
100
License
JavaScript (100%)
Total Downloads
0
Last Day
0
Last Week
0
Last Month
0
Last Year
0
MIT License
23 Stars
1,092 Commits
8 Forks
3 Watchers
47 Branches
1 Contributors
Updated on Nov 18, 2024
Latest Version
9.10.0
Package Id
simple-peer-light@9.10.0
Size
19.39 kB
NPM Version
6.14.8
Node Version
14.16.0
Published on
Mar 22, 2021
Cumulative downloads
Total Downloads
Last Day
0%
NaN
Compared to previous day
Last Week
0%
NaN
Compared to previous week
Last Month
0%
NaN
Compared to previous month
Last Year
0%
NaN
Compared to previous year
This is a light-weight, browser-friendly fork of feross/simple-peer:
<script type="module">
without bundlingCaveats compared to feross/simple-peer
Peer
class does not inherit from Duplex
. Instead, it has only the essential EventEmitter
methods .on()
, .off()
, .once()
and .emit()
.index.js
uses an ESM export instead of CJS, it does not work in node.index.js
.The documentation below is updated to reflect these changes.
Regarding ongoing development in simple-peer
, the strategy for this repo is to keep merging in upstream changes while maintaining the initial diff. We will update the npm package accordingly and our versioning will track the version of simple-peer
1:1, to make it obvious at what point of the release history we are.
concise, node.js style API for WebRTC
supports video/voice streams
supports data channel
supports advanced options like:
npm install simple-peer-light
This package works in the browser without modification. The simplepeer.min.js
script is just a minified version for usage without a build pipeline.
Let's create an html page that lets you manually connect two peers:
1<html> 2 <body> 3 <style> 4 #outgoing { 5 width: 600px; 6 word-wrap: break-word; 7 white-space: normal; 8 } 9 </style> 10 <form> 11 <textarea id="incoming"></textarea> 12 <button type="submit">submit</button> 13 </form> 14 <pre id="outgoing"></pre> 15 <script type="module"> 16 import Peer from './simplepeer.min.js'; 17 const p = new Peer({ 18 initiator: location.hash === '#1', 19 trickle: false, 20 }); 21 22 p.on('error', err => console.log('error', err)); 23 24 p.on('signal', data => { 25 console.log('SIGNAL', JSON.stringify(data)); 26 document.querySelector('#outgoing').textContent = JSON.stringify(data); 27 }); 28 29 document.querySelector('form').addEventListener('submit', ev => { 30 ev.preventDefault(); 31 p.signal(JSON.parse(document.querySelector('#incoming').value)); 32 }); 33 34 p.on('connect', () => { 35 console.log('CONNECT'); 36 p.send('whatever' + Math.random()); 37 }); 38 39 p.on('data', data => { 40 console.log('data: ' + data); 41 }); 42 </script> 43 </body> 44</html>
Visit index.html#1
from one browser (the initiator) and index.html
from another
browser (the receiver).
An "offer" will be generated by the initiator. Paste this into the receiver's form and hit submit. The receiver generates an "answer". Paste this into the initiator's form and hit submit.
Now you have a direct P2P connection between two browsers!
This example create two peers in the same web page.
In a real-world application, you would never do this. The sender and receiver Peer
instances would exist in separate browsers. A "signaling server" (usually implemented with
websockets) would be used to exchange signaling data between the two browsers until a
peer-to-peer connection is established.
1import Peer from 'simple-peer-light'; 2 3var peer1 = new Peer({initiator: true}); 4var peer2 = new Peer(); 5 6peer1.on('signal', data => { 7 // when peer1 has signaling data, give it to peer2 somehow 8 peer2.signal(data); 9}); 10 11peer2.on('signal', data => { 12 // when peer2 has signaling data, give it to peer1 somehow 13 peer1.signal(data); 14}); 15 16peer1.on('connect', () => { 17 // wait for 'connect' event before using the data channel 18 peer1.send('hey peer2, how is it going?'); 19}); 20 21peer2.on('data', data => { 22 // got a data channel message 23 console.log('got a message from peer1: ' + data); 24});
Video/voice is also super simple! In this example, peer1 sends video to peer2.
1import Peer from 'simple-peer-light'; 2 3// get video/voice stream 4navigator.mediaDevices 5 .getUserMedia({ 6 video: true, 7 audio: true, 8 }) 9 .then(gotMedia) 10 .catch(() => {}); 11 12function gotMedia(stream) { 13 var peer1 = new Peer({initiator: true, stream: stream}); 14 var peer2 = new Peer(); 15 16 peer1.on('signal', data => { 17 peer2.signal(data); 18 }); 19 20 peer2.on('signal', data => { 21 peer1.signal(data); 22 }); 23 24 peer2.on('stream', stream => { 25 // got remote video stream, now let's show it in a video tag 26 var video = document.querySelector('video'); 27 28 if ('srcObject' in video) { 29 video.srcObject = stream; 30 } else { 31 video.src = window.URL.createObjectURL(stream); // for older browsers 32 } 33 34 video.play(); 35 }); 36}
For two-way video, simply pass a stream
option into both Peer
constructors. Simple!
Please notice that getUserMedia
only works in pages loaded via https.
It is also possible to establish a data-only connection at first, and later add a video/voice stream, if desired.
1import Peer from 'simple-peer-light'; // create peer without waiting for media 2 3var peer1 = new Peer({initiator: true}); // you don't need streams here 4var peer2 = new Peer(); 5 6peer1.on('signal', data => { 7 peer2.signal(data); 8}); 9 10peer2.on('signal', data => { 11 peer1.signal(data); 12}); 13 14peer2.on('stream', stream => { 15 // got remote video stream, now let's show it in a video tag 16 var video = document.querySelector('video'); 17 18 if ('srcObject' in video) { 19 video.srcObject = stream; 20 } else { 21 video.src = window.URL.createObjectURL(stream); // for older browsers 22 } 23 24 video.play(); 25}); 26 27function addMedia(stream) { 28 peer1.addStream(stream); // <- add streams to peer dynamically 29} 30 31// then, anytime later... 32navigator.mediaDevices 33 .getUserMedia({ 34 video: true, 35 audio: true, 36 }) 37 .then(addMedia) 38 .catch(() => {});
peer = new Peer([opts])
Create a new WebRTC peer connection.
A "data channel" for text/binary communication is always established, because it's cheap and often useful. For video/voice communication, pass the stream
option.
If opts
is specified, then the default options (shown below) will be overridden.
{
initiator: false,
channelConfig: {},
channelName: '<random string>',
config: { iceServers: [{ urls: 'stun:stun.l.google.com:19302' }, { urls: 'stun:global.stun.twilio.com:3478?transport=udp' }] },
offerOptions: {},
answerOptions: {},
sdpTransform: function (sdp) { return sdp },
stream: false,
streams: [],
trickle: true,
allowHalfTrickle: false,
wrtc: {}, // RTCPeerConnection/RTCSessionDescription/RTCIceCandidate
}
The options do the following:
initiator
- set to true
if this is the initiating peerchannelConfig
- custom webrtc data channel configuration (used by createDataChannel
)channelName
- custom webrtc data channel nameconfig
- custom webrtc configuration (used by RTCPeerConnection
constructor)offerOptions
- custom offer options (used by createOffer
method)answerOptions
- custom answer options (used by createAnswer
method)sdpTransform
- function to transform the generated SDP signaling data (for advanced users)stream
- if video/voice is desired, pass stream returned from getUserMedia
streams
- an array of MediaStreams returned from getUserMedia
trickle
- set to false
to disable trickle ICE and get a single 'signal' event (slower)wrtc
- custom webrtc implementation, mainly useful in node to specify in the wrtc package. Contains an object with the properties:
peer.signal(data)
Call this method whenever the remote peer emits a peer.on('signal')
event.
The data
will encapsulate a webrtc offer, answer, or ice candidate. These messages help
the peers to eventually establish a direct connection to each other. The contents of these
strings are an implementation detail that can be ignored by the user of this module;
simply pass the data from 'signal' events to the remote peer and call peer.signal(data)
to get connected.
peer.send(data)
Send text/binary data to the remote peer. data
can be any of several types: String
,
ArrayBufferView
(Uint8Array
,
etc.), ArrayBuffer
, or Blob
(in browsers that support it).
Note: If this method is called before the peer.on('connect')
event has fired, then an exception will be thrown.
peer.addStream(stream)
Add a MediaStream
to the connection.
peer.removeStream(stream)
Remove a MediaStream
from the connection.
peer.addTrack(track, stream)
Add a MediaStreamTrack
to the connection. Must also pass the MediaStream
you want to attach it to.
peer.removeTrack(track, stream)
Remove a MediaStreamTrack
from the connection. Must also pass the MediaStream
that it was attached to.
peer.replaceTrack(oldTrack, newTrack, stream)
Replace a MediaStreamTrack
with another track. Must also pass the MediaStream
that the old track was attached to.
peer.addTransceiver(kind, init)
Add a RTCRtpTransceiver
to the connection. Can be used to add transceivers before adding tracks. Automatically called as neccesary by addTrack
.
peer.destroy([err])
Destroy and cleanup this peer connection.
If the optional err
parameter is passed, then it will be emitted as an 'error'
event on the stream.
Peer.WEBRTC_SUPPORT
Detect native WebRTC support in the javascript environment.
1import Peer from 'simple-peer-light'; 2 3if (Peer.WEBRTC_SUPPORT) { 4 // webrtc support! 5} else { 6 // fallback 7}
peer.on('signal', data => {})
Fired when the peer wants to send signaling data to the remote peer.
It is the responsibility of the application developer (that's you!) to get this data to
the other peer. This usually entails using a websocket signaling server. This data is an
Object
, so remember to call JSON.stringify(data)
to serialize it first. Then, simply
call peer.signal(data)
on the remote peer.
(Be sure to listen to this event immediately to avoid missing it. For initiator: true
peers, it fires right away. For initatior: false
peers, it fires when the remote
offer is received.)
peer.on('connect', () => {})
Fired when the peer connection and data channel are ready to use.
peer.on('data', data => {})
Received a message from the remote peer (via the data channel).
data
will be either a String
or a Uint8Array
.
peer.on('stream', stream => {})
Received a remote video stream, which can be displayed in a video tag:
1peer.on('stream', stream => { 2 var video = document.querySelector('video'); 3 if ('srcObject' in video) { 4 video.srcObject = stream; 5 } else { 6 video.src = window.URL.createObjectURL(stream); 7 } 8 video.play(); 9});
peer.on('track', (track, stream) => {})
Received a remote audio/video track. Streams may contain multiple tracks.
peer.on('close', () => {})
Called when the peer connection has closed.
peer.on('error', (err) => {})
Fired when a fatal error occurs. Usually, this means bad signaling data was received from the remote peer.
err
is an Error
object.
Errors returned by the error
event have an err.code
property that will indicate the origin of the failure.
Possible error codes:
ERR_WEBRTC_SUPPORT
ERR_CREATE_OFFER
ERR_CREATE_ANSWER
ERR_SET_LOCAL_DESCRIPTION
ERR_SET_REMOTE_DESCRIPTION
ERR_ADD_ICE_CANDIDATE
ERR_ICE_CONNECTION_FAILURE
ERR_SIGNALING
ERR_DATA_CHANNEL
ERR_CONNECTION_FAILURE
The simplest way to do that is to create a full-mesh topology. That means that every peer opens a connection to every other peer. To illustrate:
To broadcast a message, just iterate over all the peers and call peer.send
.
So, say you have 3 peers. Then, when a peer wants to send some data it must send it 2 times, once to each of the other peers. So you're going to want to be a bit careful about the size of the data you send.
Full mesh topologies don't scale well when the number of peers is very large. The total
number of edges in the network will be
where
n
is the number of peers.
For clarity, here is the code to connect 3 peers together:
1// These are peer1's connections to peer2 and peer3 2var peer2 = new Peer({initiator: true}); 3var peer3 = new Peer({initiator: true}); 4 5peer2.on('signal', data => { 6 // send this signaling data to peer2 somehow 7}); 8 9peer2.on('connect', () => { 10 peer2.send('hi peer2, this is peer1'); 11}); 12 13peer2.on('data', data => { 14 console.log('got a message from peer2: ' + data); 15}); 16 17peer3.on('signal', data => { 18 // send this signaling data to peer3 somehow 19}); 20 21peer3.on('connect', () => { 22 peer3.send('hi peer3, this is peer1'); 23}); 24 25peer3.on('data', data => { 26 console.log('got a message from peer3: ' + data); 27});
1// These are peer2's connections to peer1 and peer3 2var peer1 = new Peer(); 3var peer3 = new Peer({initiator: true}); 4 5peer1.on('signal', data => { 6 // send this signaling data to peer1 somehow 7}); 8 9peer1.on('connect', () => { 10 peer1.send('hi peer1, this is peer2'); 11}); 12 13peer1.on('data', data => { 14 console.log('got a message from peer1: ' + data); 15}); 16 17peer3.on('signal', data => { 18 // send this signaling data to peer3 somehow 19}); 20 21peer3.on('connect', () => { 22 peer3.send('hi peer3, this is peer2'); 23}); 24 25peer3.on('data', data => { 26 console.log('got a message from peer3: ' + data); 27});
1// These are peer3's connections to peer1 and peer2 2var peer1 = new Peer(); 3var peer2 = new Peer(); 4 5peer1.on('signal', data => { 6 // send this signaling data to peer1 somehow 7}); 8 9peer1.on('connect', () => { 10 peer1.send('hi peer1, this is peer3'); 11}); 12 13peer1.on('data', data => { 14 console.log('got a message from peer1: ' + data); 15}); 16 17peer2.on('signal', data => { 18 // send this signaling data to peer2 somehow 19}); 20 21peer2.on('connect', () => { 22 peer2.send('hi peer2, this is peer3'); 23}); 24 25peer2.on('data', data => { 26 console.log('got a message from peer2: ' + data); 27});
If you call peer.send(buf)
, simple-peer-light
is not keeping a reference to buf
and sending the buffer at some later point in time. We immediately call
channel.send()
on the data channel. So it should be fine to mutate the buffer
right afterward.
If a direct connection fails, in particular, because of NAT traversal and/or firewalls, WebRTC ICE uses an intermediary (relay) TURN server. In other words, ICE will first use STUN with UDP to directly connect peers and, if that fails, will fall back to a TURN relay server.
In order to use a TURN server, you must specify the config
option to the Peer
constructor. See the API docs above.
MIT. Copyright (c) Feross Aboukhadijeh.
No vulnerabilities found.
Reason
no binaries found in the repo
Reason
0 existing vulnerabilities detected
Reason
license file detected
Details
Reason
0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0
Reason
Found 0/30 approved changesets -- score normalized to 0
Reason
no SAST tool detected
Details
Reason
no effort to earn an OpenSSF best practices badge detected
Reason
security policy file not detected
Details
Reason
project is not fuzzed
Details
Reason
branch protection not enabled on development/release branches
Details
Score
Last Scanned on 2025-07-07
The Open Source Security Foundation is a cross-industry collaboration to improve the security of open source software (OSS). The Scorecard provides security health metrics for open source projects.
Learn More