WebSockets
High-performance WebSockets for React Native, built as a Nitro Module (libwebsockets + mbedTLS). This package lives alongside react-native-nitro-fetch in the same repo; HTTP stays in nitro-fetch, sockets in nitro-websockets.
Installation
Install three packages: the WebSocket module, Nitro Modules (required by all Nitro libraries), and react-native-nitro-text-decoder (a peer dependency used to decode UTF-8 text frames).
npm i react-native-nitro-websockets react-native-nitro-text-decoder react-native-nitro-modules
If you already use react-native-nitro-fetch, just add the websockets and text-decoder packages. Keep react-native-nitro-modules on a compatible version.
Then install native pods and rebuild:
cd ios && pod install && cd ..
npx react-native run-ios # or run-android
NitroWebSocket API
The JS surface is a small class modeled after the browser WebSocket.
Constructor
import { NitroWebSocket } from 'react-native-nitro-websockets';
const ws = new NitroWebSocket(
url: string,
protocols?: string | string[],
headers?: Record<string, string>
);
- url —
ws:/wss:endpoint - protocols — optional subprotocol string or list (
Sec-WebSocket-Protocol) - headers — optional extra HTTP headers for the upgrade request
Properties
| Property | Type | Description |
|---|---|---|
readyState | 'CONNECTING' | 'OPEN' | 'CLOSING' | 'CLOSED' | Current connection state |
url | string | The WebSocket URL |
protocol | string | Negotiated subprotocol |
bufferedAmount | number | Bytes queued for sending |
extensions | string | Negotiated extensions |
Methods
send(data: string | ArrayBuffer)— Send text or binary dataclose(code?: number, reason?: string)— Close the connection (default code1000)
Events
ws.onopen = () => void;
ws.onmessage = (e: WebSocketMessageEvent) => void;
ws.onerror = (error: string) => void;
ws.onclose = (e: { code: number; reason: string }) => void;
The WebSocketMessageEvent contains:
e.data— string for text framese.isBinary—truefor binary frames; usee.binaryData(ArrayBuffer)
Example
const ws = new NitroWebSocket('wss://echo.websocket.org');
ws.onopen = () => console.log('open');
ws.onmessage = (e) => console.log('message', e.data, e.isBinary);
ws.onerror = (err) => console.error(err);
ws.onclose = (e) => console.log('closed', e.code, e.reason);
ws.send('hello');
ws.close(1000, 'bye');
Prewarm on next app launch
Prewarming starts the TLS/WebSocket handshake natively on startup (before JS runs), using URLs you enqueue from JavaScript.
Prewarm uses the same NativeStorage queue as nitro-fetch, so react-native-nitro-fetch must be installed.
JS helpers
import {
prewarmOnAppStart,
removeFromPrewarmQueue,
clearPrewarmQueue,
} from 'react-native-nitro-websockets';
// Queue or update an entry (deduped by URL)
prewarmOnAppStart('wss://api.example.com/ws', ['chat-v1'], {
Authorization: 'Bearer ...',
});
// Remove one URL from the queue
removeFromPrewarmQueue('wss://api.example.com/ws');
// Clear the entire queue
clearPrewarmQueue();
Android native hook
In Application.onCreate, before or after loadReactNative:
import com.margelo.nitro.nitrofetchwebsockets.NitroWebSocketAutoPrewarmer
override fun onCreate() {
super.onCreate()
NitroWebSocketAutoPrewarmer.prewarmOnStart(this)
// ...
}
Expo Plugin (Android)
If you use Expo, the plugin automatically injects NitroWebSocketAutoPrewarmer.prewarmOnStart() into MainApplication.kt during expo prebuild — no manual native code changes needed.
Add to your app.json:
{
"plugins": ["react-native-nitro-websockets"]
}
Auth on cold start
If prewarmed sockets need fresh headers, register token refresh with target: 'websocket' or 'all' using registerTokenRefresh from react-native-nitro-fetch. See the Token Refresh guide for details.
iOS transport
On iOS, connections run on a client built on Network.framework, which reads the socket in bulk and frames messages in-process. It is much faster for bursts of messages than NSURLSessionWebSocketTask. Setting NitroWebSocketsUseNetworkFramework to false in Info.plist switches back to NSURLSessionWebSocketTask, which you need for App Transport Security, NSPinnedDomains pinning, proxies or HTTP authentication.
<key>NitroWebSocketsUseNetworkFramework</key>
<false/>
With Expo, set it under ios.infoPlist in the app config.
App Transport Security does not apply to Network.framework, so ws:// connects to any host and NSPinnedDomains pinning is not applied. wss:// connections still validate the server certificate against the system trust store, and redirects from wss:// to ws:// are refused.
Other differences from NSURLSessionWebSocketTask:
- the system HTTP or PAC proxy may not be used
user:pass@credentials and401challenges are not handled- the handshake sends no
Accept,Accept-LanguageorAccept-Encodingheader - messages can be up to 16 MB instead of 1 MB
- if the server does not answer
close()within 5 seconds,onclosefires with code1006 - a close frame with a reserved code or a reason that is not valid UTF-8 fails the connection:
onerror, thenonclosewith1006 - a failed send does not fire
onerrorby itself; the connection failing does - network changes are not watched and no TCP keepalives are sent, so an idle connection can stay open after the network changes until a read or write fails
See also
- Prefetch & Auto-Prefetch — HTTP prefetch; pairs conceptually with WS prewarm
- Token Refresh — Auth token configuration for cold-start requests