📄 RFC 6455: The WebSocket Protocol
Status: Internet Standard Last Updated: December 2011 Stability: Stable ✅
The foundational WebSocket protocol specification defining the framing, handshake, and core protocol mechanics.
Stay up-to-date with the evolving WebSocket ecosystem. This page tracks all WebSocket-related specifications, their current status, browser implementations, and upcoming changes that may affect your applications.
📄 RFC 6455: The WebSocket Protocol
Status: Internet Standard Last Updated: December 2011 Stability: Stable ✅
The foundational WebSocket protocol specification defining the framing, handshake, and core protocol mechanics.
🌐 WHATWG WebSockets Living Standard
Status: Living Standard Last Updated: Continuously updated Stability: Stable with ongoing improvements ✅
The browser API specification defining how WebSockets work in web browsers.
🗜️ RFC 7692: Compression Extensions
Status: Proposed Standard Last Updated: December 2015 Stability: Stable with security considerations ⚠️
Defines permessage-deflate compression extension for WebSocket.
⚡ RFC 8441: HTTP/2 WebSockets
Status: Proposed Standard Last Updated: September 2018 Stability: Experimental implementation 🚧
Bootstrapping WebSockets over HTTP/2 using Extended CONNECT.
🚀 RFC 9220: HTTP/3 WebSockets
Status: Proposed Standard Last Updated: June 2022 Stability: Early implementation 🚧
Bootstrapping WebSockets over HTTP/3 and QUIC.
⏩ W3C WebTransport
Status: Working Draft Last Updated: October 2024 Stability: Experimental 🔬
Next-generation bidirectional communication protocol built on HTTP/3.
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Basic WebSocket | ✅ 16+ | ✅ 11+ | ✅ 7+ | ✅ 12+ |
| Binary data | ✅ 16+ | ✅ 11+ | ✅ 7+ | ✅ 12+ |
| Sub-protocols | ✅ 16+ | ✅ 11+ | ✅ 7+ | ✅ 12+ |
| Extensions | ✅ 16+ | ✅ 11+ | ✅ 7+ | ✅ 12+ |
| Secure WebSocket (WSS) | ✅ 16+ | ✅ 11+ | ✅ 7+ | ✅ 12+ |
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| permessage-deflate | ✅ 32+ | ✅ 37+ | ✅ 9+ | ✅ 12+ |
| Client context takeover | ✅ 32+ | ✅ 37+ | ✅ 9+ | ✅ 12+ |
| Server context takeover | ✅ 32+ | ✅ 37+ | ✅ 9+ | ✅ 12+ |
| Window bits negotiation | ✅ 32+ | ✅ 37+ | ✅ 9+ | ✅ 12+ |
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| Extended CONNECT | ✅ 91+ | ❌ | ❌ | ✅ 91+ |
| :protocol pseudo-header | ✅ 91+ | ❌ | ❌ | ✅ 91+ |
| SETTINGS_ENABLE_CONNECT_PROTOCOL | ✅ 91+ | ❌ | ❌ | ✅ 91+ |
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| HTTP/3 WebSocket bootstrap | 🚧 Experimental | ❌ | ❌ | 🚧 Experimental |
| QUIC transport | ✅ 87+ (HTTP/3) | ✅ 88+ (HTTP/3) | ✅ 14+ (HTTP/3) | ✅ 87+ (HTTP/3) |
| Extended CONNECT over HTTP/3 | 🚧 Flag required | ❌ | ❌ | 🚧 Flag required |
| Feature | Chrome | Firefox | Safari | Edge |
|---|---|---|---|---|
| WebTransport API | ✅ 97+ | 🚧 114+ (Nightly) | ❌ | ✅ 97+ |
| Datagrams | ✅ 97+ | 🚧 | ❌ | ✅ 97+ |
| Streams | ✅ 97+ | 🚧 | ❌ | ✅ 97+ |
| Connection pooling | ✅ 97+ | 🚧 | ❌ | ✅ 97+ |
| Server | HTTP/1.1 WebSocket | HTTP/2 WebSocket | HTTP/3 WebSocket |
|---|---|---|---|
| Nginx | ✅ 1.3.13+ | ✅ 1.25+ | 🚧 Experimental |
| Apache | ✅ 2.4+ (mod_proxy_wstunnel) | ❌ | ❌ |
| Caddy | ✅ v1+ | ✅ v2+ | ✅ v2.6+ |
| HAProxy | ✅ 1.4+ | ✅ 2.0+ | 🚧 2.6+ |
| Node.js | ✅ All versions | ✅ 10.0+ | 🚧 Experimental |
| IIS | ✅ 8.0+ | ✅ 10+ | ❌ |
| Provider | WebSocket Support | HTTP/2 | HTTP/3 | Notes |
|---|---|---|---|---|
| Cloudflare | ✅ | ✅ | ✅ | 100-second timeout |
| AWS CloudFront | ✅ | ✅ | ✅ | Regional edge locations |
| AWS ALB | ✅ | ❌ | ❌ | 4000-second timeout |
| Google Cloud LB | ✅ | ✅ | 🚧 | Global load balancing |
| Azure App Gateway | ✅ | ✅ | ❌ | Session affinity required |
| Fastly | ✅ | ✅ | ✅ | Real-time purging |
binaryType behavior for ArrayBuffer// Check basic WebSocket supportif ('WebSocket' in window) { console.log('WebSocket supported');}
// Check for specific features function checkWebSocketFeatures() { constfeatures = { basic: 'WebSocket' in window, binaryType: false, compression:false, protocols: false };
if (features.basic) { try { const ws = newWebSocket('wss://echo.websocket.org'); features.binaryType = 'binaryType' in ws;features.protocols = ws.protocol !== undefined;
// Check for compression support ws.onopen = () => { features.compression = ws.extensions.includes('permessage-deflate'); ws.close(); }; } catch (e) { console.error('WebSocket test failed:', e); }
}
return features; }
// Check WebTransport support if ('WebTransport' in window) {console.log('WebTransport supported'); }class ProtocolDetector { static async detectCapabilities() { const caps = { websocket: { basic: false, secure: false, compression: false, http2: false, http3: false }, webtransport: false, performance: {} };
// Basic WebSocket caps.websocket.basic = 'WebSocket' in window;
// Secure WebSocket if (caps.websocket.basic && location.protocol === 'https:') { try { const ws = new WebSocket('wss://echo.websocket.org'); await new Promise((resolve) => { ws.onopen = () => { caps.websocket.secure = true; caps.websocket.compression = ws.extensions.includes('permessage-deflate'); ws.close(); resolve(); }; ws.onerror = resolve; setTimeout(resolve, 5000); }); } catch (e) {} }
// WebTransport caps.webtransport = 'WebTransport' in window;
// Performance features if (window.performance && performance.timing) { caps.performance = { navigation: 'navigation' in performance, memory: 'memory' in performance, timeOrigin: 'timeOrigin' in performance }; }
return caps; }}// Negotiate best available protocolasync function connectWithBestProtocol(url) { const caps = await ProtocolDetector.detectCapabilities();
// Try WebTransport first (if available and supported) if (caps.webtransport && url.startsWith('https://')) { try { const transport = new WebTransport(url); await transport.ready; console.log('Connected via WebTransport'); return transport; } catch (e) { console.log('WebTransport failed, falling back'); } }
// Fall back to WebSocket if (caps.websocket.secure) { const ws = new WebSocket(url.replace('https://', 'wss://')); await new Promise((resolve, reject) => { ws.onopen = resolve; ws.onerror = reject; }); console.log('Connected via WebSocket'); return ws; }
throw new Error('No suitable protocol available');}# Nginx configuration for HTTP/2 WebSocketserver { listen 443 ssl http2; server_name example.com;
# Enable HTTP/2 WebSocket support (Nginx 1.25+) http2_recv_timeout 300s; http2_idle_timeout 300s;
location /ws { proxy_pass http://backend; proxy_http_version 1.1;
# Standard WebSocket headers proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection "upgrade";
# HTTP/2 specific settings proxy_set_header X-Forwarded-Proto $scheme; proxy_buffering off;
# Extended CONNECT support proxy_set_header :protocol websocket; }}// Abstraction layer for protocol migrationclass RealtimeConnection { constructor(url, options = {}) { this.url = url; this.options = options; this.protocol = null; }
async connect() { // Try WebTransport if ('WebTransport' in window && this.url.startsWith('https://')) { try { return await this.connectWebTransport(); } catch (e) { console.log('WebTransport unavailable, using WebSocket'); } }
// Fall back to WebSocket return await this.connectWebSocket(); }
async connectWebTransport() { this.transport = new WebTransport(this.url); await this.transport.ready; this.protocol = 'webtransport';
// Set up bidirectional stream const stream = await this.transport.createBidirectionalStream(); this.reader = stream.readable.getReader(); this.writer = stream.writable.getWriter();
return this; }
async connectWebSocket() { const wsUrl = this.url .replace('https://', 'wss://') .replace('http://', 'ws://');
this.ws = new WebSocket(wsUrl); this.protocol = 'websocket';
return new Promise((resolve, reject) => { this.ws.onopen = () => resolve(this); this.ws.onerror = reject; }); }
async send(data) { if (this.protocol === 'webtransport') { const encoded = new TextEncoder().encode(data); await this.writer.write(encoded); } else { this.ws.send(data); } }
async receive() { if (this.protocol === 'webtransport') { const { value } = await this.reader.read(); return new TextDecoder().decode(value); } else { return new Promise((resolve) => { this.ws.onmessage = (event) => resolve(event.data); }); } }
close() { if (this.protocol === 'webtransport') { this.transport.close(); } else { this.ws.close(); } }}IETF httpbis Working Group: HTTP/2 and HTTP/3 WebSocket specifications
W3C WebTransport Working Group: Next-generation transport protocol
WHATWG Streams: WebSocket Living Standard
Stay informed about WebSocket standards updates with our monthly digest.
📧 Subscribe to Standards Watch
Get monthly updates on WebSocket standards and implementations delivered to your inbox.
Coming Soon - Email subscription system under development.
Follow @mattyoriordan for updates.
Track your WebSocket implementation’s compliance with the protocol specification:
# Run Autobahn TestSuitedocker run -it --rm \ -v "${PWD}/config:/config" \ -v "${PWD}/reports:/reports" \ crossbario/autobahn-testsuite \ wstest -m fuzzingclient -s /config/fuzzingclient.json| Implementation | RFC 6455 | RFC 7692 | Pass Rate |
|---|---|---|---|
| Chrome 120 | ✅ 100% | ✅ 100% | 517/517 |
| Firefox 120 | ✅ 100% | ✅ 100% | 517/517 |
| Safari 17 | ✅ 100% | ✅ 100% | 517/517 |
| Node.js ws | ✅ 100% | ✅ 100% | 517/517 |
| Python websockets | ✅ 100% | ✅ 100% | 517/517 |
| Go gorilla | ✅ 99.8% | ✅ 100% | 516/517 |