How to send ping/pong to Binance websocket Server

  • Binance Websocket Server sends ping frame to client every 3 minutes. If no pong frame returned back from client in 10 minutes, the server will disconnect the connection.
  • Client can send ping message to Websocket server, the server will return pong as response. This is useful for client to actively validate if the connection is alive.

I’m using websocket market streams in a node js application with ws library. It receives data all right but connection gets closed every 10 minutes. I’ve tried listening to ping events with ws.onping but it never gets triggered which makes me thing that the server never sends the ping frame. How can I send a ping message to the server? I’ve tried ws.send('ping') but the server responses with { error: { code: 3, msg: 'Invalid JSON: expected value at line 1 column 1' } }. What is the correct format for the ping message?

As mentioned the websocket sends a ping frame and your client needs to answer with a pong frame. So it’s as simple as listening to the ping event and sending a pong frame…

_ws.on('ping', (e) => { //listen for ping event
	_ws.pong(); //send pong frame
});

Also unsolicited pong frames are allowed. Therefore, you could simply send a pong frame periodically without even needing to receive a ping as long as you do it every x minutes (x < 10).

@ren0d1

I’ve tried listening to ping events with ws.onping but it never gets triggered which makes me thing that the server never sends the ping frame.

ping pong is standard control frame, please check the rfc:

Hi @dino, can you please look into the issues discussed with @ren0d1 below.

Alright so the code I provided you with is for a node js application as well and it works since I’m using this exact code. It specifies directly to listen to the ping event instead of calling the wrapper, but it’s essentially doing the same, only the syntax for its usage differs. My guess would be that you’re using the wrong syntax for your callback upon receival of the ping request which then leads you to think you’re not receiving a ping from the server.
So now for completeness, here are the two syntaxes.

Specifying the event to listen to:

ws.on('ping', (e) => { //Defines callback for ping event
    ws.pong(); //send pong frame
});

Using the wrapper like you:

ws.onping = () => { //Defines event handler for ping event
    ws.pong(); //send pong frame
};

Now that it’s out of the way, once again, you DO NOT need to send a ping, BUT a pong request instead to the server. (Server sends ping, you answer pong… Like ping-pong, you know…).
Finally, to send that pong request, as stated in my previous response, you simply need to call ws.pong()

@ren0d1 it turns out the problems was in the wrapper. The ws.on('ping', (e) => {} listener is triggered correctly. Thanks!

It still does not work. Even with the listener and pong responses in place the connection is interrupted every 10 minutes.
Here is statistics from my logs:
Jul 14 08:48:16: startup
Jul 14 08:50:44: onping
Jul 14 08:56:00: onping
Jul 14 08:58:26: connection interrupted
Jul 14 09:02:27: onping
Jul 14 09:05:26: onping
Jul 14 09:11:20: onping
Jul 14 09:11:58: connection interrupted
Jul 14 09:16:50: onping
Jul 14 09:17:36: connection interrupted
Jul 14 09:19:45: onping
Jul 14 09:27:40: onping
Jul 14 09:28:27: connection interrupted

@yaugenka You’re welcome!
Now concerning the fact that it isn’t working, sadly I cannot do much more to help and I think it might deviate too much from the original topic. But I would suggest to check if your connection triggers an error event, in which case you might have more information in its details.

On my hand, it doesn’t seem to have any issue, but looking at the pattern of ping requests, I would wonder if your pong request is properly sent. Make sure to call ws.pong() without passing in any data. From what I recall, and what can be seen in my logs, you should receive a ping approximately every 3 minutes if you answer by a pong everytime.

Market activites listener connected
Received ping from server at Wed Jul 14 2021 09:22:34 GMT+0200 (Central European Summer Time)
Received ping from server at Wed Jul 14 2021 09:25:34 GMT+0200 (Central European Summer Time)
Received ping from server at Wed Jul 14 2021 09:28:34 GMT+0200 (Central European Summer Time)
Received ping from server at Wed Jul 14 2021 09:31:34 GMT+0200 (Central European Summer Time)
Received ping from server at Wed Jul 14 2021 09:34:34 GMT+0200 (Central European Summer Time)
Received ping from server at Wed Jul 14 2021 09:37:34 GMT+0200 (Central European Summer Time)

For completeness, you can also get some information to help you out even if it closed without error. The structures of the two events I mentioned are as follow in node js:

interface ErrorEvent {
    error: any;
    message: string;
    type: string;
    target: WebSocket;
}

interface CloseEvent {
    wasClean: boolean;
    code: number;
    reason: string;
    target: WebSocket;
}

Thanks for your replies @ren0d1
There are no error events and the connection is interrupted with an empty reason and 1006 code.

@yaugenka The empty reason is expected given the 1006 code as is further explained here. However, it is stranger that no error event was triggered.
Make sure to properly setup the listener, an example would be as follow:

ws.onerror = (err) => {
    console.log('Error information: ', err);
};

Also, I know that there is a callback function for the pong function in case of an error. It might be interesting to look into it. I have never tried it so I cannot provide you with a direct example, but here is the signature of the pong function which should be more than enough for you to link your callback and debug:

WebSocket.pong(data?: any, mask?: boolean, cb?: (err: Error) => void): void

Finally, if none of the above is of help, it might be better suited to contact @dino for more intricate details.

I’m sure that my onerror listener works correctly because if for example I try instantiate ws with an invalid uri, then the error event is received.
Tried ws.pong(null,null, (e) => console.error(e)); but it logs undefined

I’ve got on ping listener installed like this

 ws.on('ping', () => {
	ws.pong(null,null, (e) => {
		if(e !== undefined)
			console.error(`${this.logPrefix()} pong error: ${e.message}`)
	});
});

And also have ws.ping(); (yes, it’s ping not pong) called at 3 min intervals.

Here is this night’s statistics.
Jul 16 03:07:32: binance: connection interrupted (code=1006)
Jul 16 05:51:33: binance: connection interrupted (code=1006)
Jul 16 06:12:00: binance: connection interrupted (code=1006)
Jul 16 06:20:59: binance: connection interrupted (code=1006)
Jul 16 06:33:14: binance: pong error: Cannot call write after a stream was destroyed
Jul 16 06:33:15: binance: connection interrupted (code=1006)
Jul 16 06:41:35: binance: connection interrupted (code=1006)
Jul 16 08:02:41: binance: connection interrupted (code=1006)
Jul 16 08:12:20: binance: connection interrupted (code=1006)
Jul 16 08:22:57: binance: connection interrupted (code=1006)
Jul 16 08:33:46: binance: connection interrupted (code=1006)
Jul 16 08:42:39: binance: connection interrupted (code=1006)

One can read it as follows. The periodic ping() call made the connection more stable. It is not interrupted every 10 mins now, but still the 10 min interrupts happen every couple of hours. There was a pong error logged which proves that ws.pong() in response to server’s ping works correctly.

Jul 16 06:33:14: binance: pong error: Cannot call write after a stream was destroyed

This means, the WS connection is gone, can’t send pong frame into the socket.


Do you have any proxy or VPN in your network?
Have you received ping messages from server?
How long are you able to keep the connection since it’s connected?

My TS implementation:

ws.on('connect', function (connection) {

      connection.on('ping', (cancel: () => void, binaryPayload: Buffer) => {
        connection.pong(binaryPayload);
      });

}