WebSocket subprotocols
A raw WebSocket connection just moves opaque frames; a subprotocol defines the
application-level message format running over it — MQTT, STOMP, WAMP, GraphQL
subscriptions and more. The client and server agree on one during the handshake
using the Sec-WebSocket-Protocol header. This reference lists common
IANA-registered subprotocol identifiers with their purpose.
How the negotiation works
The client lists the subprotocols it supports, most-preferred first; the server selects exactly one and echoes it back:
GET /chat HTTP/1.1
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Protocol: graphql-transport-ws, graphql-ws
HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Protocol: graphql-transport-ws
The chosen token must be one the client offered, compared with exact casing. If
the server returns no Sec-WebSocket-Protocol header, the connection runs with
no application subprotocol. Names are coordinated in the IANA registry so
independent implementations interoperate.
Common subprotocols and when to use them
| Token | Purpose |
|---|---|
mqtt | IoT device messaging — lightweight publish/subscribe for sensors and embedded hardware |
mqttv3.1 | Explicit MQTT 3.1 version negotiation |
stomp | Simple Text Oriented Messaging Protocol, common in enterprise message brokers like ActiveMQ and RabbitMQ |
v12.stomp | STOMP version 1.2 — prefer this over bare stomp in new code |
wamp.2.json | Web Application Messaging Protocol v2, JSON encoding — used for RPC and pub/sub in browser apps |
wamp.2.msgpack | WAMP v2 with MessagePack binary encoding (more compact) |
graphql-transport-ws | The current GraphQL over WebSocket protocol (graphql-ws library) |
graphql-ws | The older Apollo subscription protocol (subscriptions-transport-ws) — mostly superseded |
soap | SOAP over WebSockets for legacy web-service interoperability |
xmpp | XMPP (Jabber) instant messaging and presence |
sip | SIP signalling for WebRTC voice/video call negotiation |
Choosing between graphql-transport-ws and graphql-ws
This is the most common question when setting up GraphQL subscriptions. graphql-ws is the token associated with the older Apollo subscriptions-transport-ws library; graphql-transport-ws is the newer graphql-ws library that replaced it. The graphql-ws library uses the graphql-transport-ws subprotocol token — the naming is confusing because the library name and the subprotocol token do not match.
For new projects, prefer graphql-transport-ws (the token used by the current graphql-ws npm package).
Debugging subprotocol mismatches
If your WebSocket connection opens but messages are not working, the most common cause is a subprotocol mismatch: the client offered one set of tokens and the server expects a different one. Check the browser DevTools Network tab, find the WebSocket connection, and look at the Request and Response headers for Sec-WebSocket-Protocol. If the response header is absent when you expected a token, the server did not recognise any offered subprotocol.
Registration rules
- For public or interoperable protocols, register the subprotocol name with IANA to prevent collisions.
- Private subprotocols (used only between your own client and server) do not need registration, but a non-registered name beginning with
x-is a useful convention to signal that it is proprietary. - Tokens are compared with exact byte-for-byte casing —
MQTTandmqttare different identifiers.