Js-libp2p: can discover peers, but can't connect to them

Hello! Hopefully I’m posting in the correct area.

I’m currently trying to get two browser nodes to subscribe to a specific pubsub topic. I’m following the js-libp2p browser example (js-libp2p/examples/libp2p-in-the-browser at master · libp2p/js-libp2p · GitHub).

The provided example compiles and runs, and two different browser nodes do fire the “peer:connect” event on their respective peerId’s. I suppose this indicates that the two peers connected succesfuly and are eligible to receive messages from the same pubsub topic.

However, my application fails to connect to any of the other peers after discovery (the “peer:discovery” events get triggered, the “peer:connect” events do not) apart from the nodes already in the bootstrap list. My code (seemingly) replicates everything that the example provides.

I’ve tried dialing the discovered peers manually, but this causes runtime exceptions. Calling libp2p.peerStore.addressBook.getMultiaddrsForPeer(peerId) for a discovered (but seemingly not connected) peer does yield multiaddrs.

Code snippet in question:

const libp2p = await Libp2p.create({
      addresses: {
        listen: [
      modules: {
        transport: [Websockets, WebRTCStar],
        streamMuxer: [Mplex],
        connEncryption: [NOISE],
        peerDiscovery: [Bootstrap],
        pubsub: Gossipsub,
      config: {
        pubsub: {
          enabled: true,
          emitSelf: false,
        peerDiscovery: {
          [Bootstrap.tag]: {
            enabled: true,
            list: [

    libp2p.on('peer:discovery', async (peerId) => {
      console.log(`Found peer ${peerId.toB58String()}`);

    libp2p.connectionManager.on('peer:connect', (connection) => {
      console.log(`Connected to ${connection.remotePeer.toB58String()}`);

    libp2p.connectionManager.on('peer:disconnect', (connection) => {
      console.log(`Disconnected from ${connection.remotePeer.toB58String()}`);

    await libp2p.start();
    console.log(`Libp2p started!\nlibp2p id is ${libp2p.peerId.toB58String()}`);

    libp2p.pubsub.on(identifier, (msg) => {
      console.log('message received');
      console.log(`node1 received: ${uint8ArrayToString(msg.data)}`);

    await libp2p.pubsub.subscribe(identifier);
    console.log(`subscribed to ${identifier}`);

I’ve also noticed that there are some dependency differences in the example and my solution.

My project:

"@babel/polyfill": "^7.12.1",
    "@chainsafe/libp2p-noise": "^5.0.3",
    "@libp2p/crypto": "^0.22.9",
    "@libp2p/mdns": "^0.18.0",
    "ipfs-core": "^0.14.1",
    "libp2p": "^0.36.2",
    "libp2p-bootstrap": "^0.14.0",
    "libp2p-crypto": "^0.21.2",
    "libp2p-gossipsub": "^0.13.0",
    "libp2p-mplex": "^0.10.7",
    "libp2p-pubsub-peer-discovery": "^4.0.0",
    "libp2p-webrtc-star": "^0.25.0",
    "libp2p-websockets": "^0.16.2",

Example project:

"@chainsafe/libp2p-noise": "^5.0.2",
    "libp2p": "../../",
    "libp2p-bootstrap": "^0.14.0",
    "libp2p-gossipsub": "^0.13.0",
    "libp2p-mplex": "^0.10.4",
    "libp2p-webrtc-star": "^0.25.0",
    "libp2p-websockets": "^0.16.1"

Testing was done on the same machine (Chrome <-> Chrome, Chrome <-> Firefox). My code runs in a react.js project. My network is behind NAT.