The websocket library provides WebSocket client connections and a local WebSocket server, backed by IXWebSocket.
Sockets run on background threads and deliver all events to Lua on the main thread.
See Getting started for the shared runtime threading rule.
The client supports ws:// and wss:// (TLS via mbedTLS). The server is plain ws:// only.
type WebSocketConnectOptions = {
headers: { [string]: string }?,
protocols: { string }?,
pingIntervalSecs: number?,
handshakeTimeoutSecs: number?,
autoReconnect: boolean?, -- default false
certVerification: boolean?, -- default true
caBundle: string?, -- PEM bundle content, in-memory
}
type WebSocketServeOptions = {
host: string?, -- default "127.0.0.1"
}
type WebSocketReadyState = "connecting" | "open" | "closing" | "closed"Userdata types:
WebSocketConnectionWebSocketServerWebSocketPeer
websocket.connect(url: string, options: WebSocketConnectOptions?) -> (WebSocketConnection?, string?)
websocket.serve(port: number, options: WebSocketServeOptions?) -> (WebSocketServer?, string?)connect starts the socket immediately and returns the connection.
Events arrive on the next frame at the earliest, so attaching callbacks right after connect never misses events.
serve binds and starts listening, or returns nil and an error message. See globals Error shapes.
ws:send(data: string) -> (boolean?, string?)
ws:sendBinary(data: string) -> (boolean?, string?)
ws:ping(payload: string?) -> (boolean?, string?)
ws:close(code: number?, reason: string?) -> ()
ws:readyState() -> WebSocketReadyState
ws:url() -> string
ws:onOpen(callback: () -> ()) -> WebSocketConnection
ws:onMessage(callback: (data: string, isBinary: boolean) -> ()) -> WebSocketConnection
ws:onClose(callback: (code: number, reason: string, remote: boolean) -> ()) -> WebSocketConnection
ws:onError(callback: (message: string) -> ()) -> WebSocketConnectionCallback setters return the connection for chaining.
Automatic reconnection is disabled unless autoReconnect = true is passed.
Dropping the last reference to a connection closes it on garbage collection.
local ws = websocket.connect("wss://echo.websocket.org")
ws:onOpen(function()
ws:send("hello")
end):onMessage(function(data, isBinary)
print("received:", data)
end):onClose(function(code, reason, remote)
print("closed:", code, reason)
end):onError(function(message)
print("error:", message)
end)server:broadcast(data: string) -> (boolean?, string?)
server:broadcastBinary(data: string) -> (boolean?, string?)
server:clients() -> { WebSocketPeer }
server:port() -> number
server:stop() -> ()
server:onClientConnect(callback: (peer: WebSocketPeer, headers: { [string]: string }) -> ()) -> WebSocketServer
server:onMessage(callback: (peer: WebSocketPeer, data: string, isBinary: boolean) -> ()) -> WebSocketServer
server:onClientDisconnect(callback: (peer: WebSocketPeer, code: number, reason: string) -> ()) -> WebSocketServer
server:onError(callback: (message: string) -> ()) -> WebSocketServerThe server binds to loopback by default. See Security for host = "0.0.0.0" LAN exposure.
Peer-to-peer setups run serve on one peer and connect on the other:
-- host peer
local server = websocket.serve(7777, { host = "0.0.0.0" })
server:onClientConnect(function(peer)
peer:send("welcome")
end):onMessage(function(peer, data)
server:broadcast(data)
end)
-- joining peer
local ws = websocket.connect("ws://192.168.1.5:7777")peer:send(data: string) -> (boolean?, string?)
peer:sendBinary(data: string) -> (boolean?, string?)
peer:close(code: number?, reason: string?) -> ()
peer:remoteAddress() -> string? -- "ip:port"
peer:id() -> string? -- stable per connection, use as table keyPeer userdata handed to different callbacks may be distinct Lua values for the same connection.
Use peer:id() to key tables.
Methods on a disconnected peer return nil and "websocket peer is disconnected".
See Limits and errors for connection caps and error strings.
WebSocket traffic is not sandboxed and has no host allowlist. See web Security for the shared egress and TLS rules.
The local server binds to loopback (127.0.0.1) by default.
Passing host = "0.0.0.0" listens on all interfaces, so anything on the LAN can connect.
Only do this intentionally.
TLS on the client:
certVerificationdefaults totrueforwss://.- Setting
certVerification = falsedisables verification. This is unsafe for production (see web Security). - On platforms without a usable system certificate store for mbedTLS, pass a PEM bundle via
caBundle. - The server side does not support TLS.
For HTTP request caps and TLS options on geode.utils.web, see web Security.
See LuauAPI mod guidelines for loadstring and network abuse rules.
Connections and servers are closed when garbage collected, when close/stop is called, or when the runtime shuts down.
Nothing closes them when an individual script run returns, so keep a reference for as long as the socket should live.
src/bindings/websocket/WebSocketBinding.cppsrc/bindings/websocket/WebSocketConnection.cppsrc/bindings/websocket/WebSocketServer.cppsrc/bindings/websocket/WebSocketInternal.hpptools/luau_codegen/extra_bindings/websocket.dluau