{
  "id": 13083877,
  "title": "Browsers answer WebSocket pings and never tell your JavaScript, so we send two heartbeats",
  "url": "https://urgent.news/2026/10/09/browsers-answer-websocket-pings-and-never-tell-your-javascript-so-we",
  "topic": "tech",
  "section": "Tech",
  "published": "2026-10-09T09:41:06.000Z",
  "source": {
    "name": "Dev.to",
    "slug": "dev-to",
    "url": "https://dev.to/daniel_pertu/browsers-answer-websocket-pings-and-never-tell-your-javascript-so-we-send-two-heartbeats-2289"
  },
  "original_language": "en",
  "account": "Both ends of a WebSocket connection continue to believe in a connection that no longer exists when the server writes into a socket nobody is reading, and the browser shows the last data received. This leads to stale numbers on dashboards and players stuck on outdated questions. The app runs in pubs, which have poor connectivity with captive portals, outdated routers, and spotty 4G. Phones lock, freeze tabs, and come back hours later, causing open sockets to appear dead. The WebSocket protocol includes ping and pong control frames to detect liveness, but browsers hide these from JavaScript. The server pings and counts missed pongs, terminating the socket after two missed pongs. Heartbeat messages with no content are used to make noise the client can observe. The watchdog checks for silence and reconnects if there's no message from the server within fifty seconds. Exponential back-off is used for reconnection, but a flat thirty-second delay is used when the client has already fallen back to polling.",
  "summary": "A WebSocket that has died does not tell you it has died. Both ends go on believing in a connection that no longer exists: the server keeps writing into a socket nobody is reading, and the browser keeps showing whatever arrived last. For a dashboard that is a stale number. For a quiz, it is a player staring at question four while the room has moved to question six, and no error anywhere. Our app…",
  "key_points": [],
  "editors_take": null,
  "illustration": null,
  "coverage": {
    "outlets": 1,
    "also_reported_by": []
  },
  "ai_generated": true,
  "disclaimer": "Summaries, key points and the editor’s take are written by software from other outlets’ reporting and may contain errors — always check the linked original."
}