WebSocket Long-Lived Connection Collection¶
Starting from RUM SDK 3.3.6, native WebSocket connections in the browser can be aggregated as RUM Resources. This allows you to analyze handshake, message traffic, inbound idle, send backlog, and close state.
This feature is currently experimental and disabled by default. The SDK does not read or upload WebSocket message bodies.
Enabling Collection¶
NPM¶
import { datafluxRum } from "@cloudcare/browser-rum"
datafluxRum.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "websocket-client",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
enableExperimentalFeatures: ["track_websockets"],
})
The slim RUM bundle uses the same configuration:
CDN¶
<script
src="https://static.guance.com/browser-sdk/v3/dataflux-rum.js"
type="text/javascript"
></script>
<script>
window.DATAFLUX_RUM &&
window.DATAFLUX_RUM.init({
applicationId: "<APPLICATION_ID>",
site: "<PUBLIC_OPENWAY_URL>",
clientToken: "<CLIENT_TOKEN>",
service: "websocket-client",
env: "production",
version: "1.0.0",
sessionSampleRate: 100,
enableExperimentalFeatures: ["track_websockets"],
})
</script>
The example above uses the public OpenWay. When connecting directly via DataKit, replace site and clientToken with datakitOrigin. Do not configure both report endpoints at the same time.
enableExperimentalFeatures must be an array. Using a string "track_websockets" directly will not enable collection.
Initialization Timing¶
RUM must be initialized before the business creates any WebSocket connection:
datafluxRum.init({
// other configuration
enableExperimentalFeatures: ["track_websockets"],
})
const socket = new WebSocket("wss://example.com/socket")
The following connections will not be collected:
- Connections created before RUM initialization;
- Connections created using a cached original
WebSocketconstructor from before initialization; - Connections created inside a Web Worker or Service Worker;
- Other transport implementations that do not go through
window.WebSocket; - Connections created via
WebSocketStream.
Enabling collection does not change the construction behavior of the native WebSocket, its static constants, instanceof checks, business event listeners, or the return behavior of send().
Collection Model¶
Each WebSocket session segment generates one RUM Resource:
A Resource is generated in the following situations:
- The browser receives a WebSocket
closeevent; - The current RUM Session expires;
- The page triggers
beforeunload; - The SDK stops the current collection instance.
WebSocket is a long-lived connection. While the connection remains open, it is normal that no final RUM Resource appears in the Network tab; the SDK does not periodically report connection snapshots.
When the page is refreshed, closed, or navigated away, the SDK attempts to finalize and send the data during the beforeunload phase. If the page process is forcefully terminated, the browser crashes, or the device loses power, JavaScript may not have a chance to execute, and the last connection Resource may still be lost.
Normal Close¶
After the browser receives a close event:
The event includes the close code, close reason, and was_clean.
Session Expiration¶
When a Session expires, connections that are still open are finalized with the current data:
The business WebSocket is not closed at this point, so the close code, close reason, and was_clean may be absent. After a new Session is established, the SDK starts a new statistics segment for the same physical connection, retains the same connection_id, and resets the message counts and segment duration.
Messages sent during the period between Session expiration and the start of the new Session are not counted in either Session. Connections created during this period and still open when the new Session begins are tracked from the renewal moment of the new Session.
Page Unload¶
When the page triggers beforeunload:
The connection may not trigger a browser close event, so the close fields may be absent.
Handshake Failure¶
When a connection enters close without ever having triggered open:
In this case, setup_duration represents the time from connection construction to close or session finalization, not the time for a successful handshake. The browser typically uses close code 1006 for abnormal closures; the actual value depends on the browser event.
Message Statistics¶
The SDK only counts the number of messages and bytes; it does not capture message bodies:
| Message Type | Bytes Calculation |
|---|---|
| string | UTF-8 byte count |
ArrayBuffer |
byteLength |
TypedArray, DataView |
byteLength of the current view |
Blob |
size |
| Unrecognized types | 0 |
For example, the string 你好 is counted as 6 bytes in UTF-8, not as the JavaScript string length of 2.
View Attribution¶
A WebSocket session segment may span multiple RUM Views. The Resource additionally records:
start_view_id: the View in which the current segment started;end_view_id: the View in which the connection closed or was finalized;end_view_path: the page path at the time of close or finalization (added in RUM SDK 3.3.8).
The page path at the start of the segment reuses the standard View context of the Resource: view.path in beforeSend, and the final intake field is view_path. When a segment spans pages, the start and end View IDs and paths can differ. The path contains only the URL pathname, not the query or hash. The Resource still enters the RUM event pipeline with the start time of the segment.
Reported Fields¶
In beforeSend, you can read event.resource.websocket; the final intake converts these fields to resource_websocket_*.
Basic Resource Fields¶
beforeSend path |
Intake field | Description | Unit |
|---|---|---|---|
resource.type |
resource_type |
Fixed to websocket |
- |
resource.url |
resource_url |
The browser-resolved ws:// or wss:// URL |
- |
resource.url_host |
resource_url_host |
URL host | - |
resource.url_path |
resource_url_path |
URL path | - |
resource.url_query |
resource_url_query |
URL query parameters | - |
resource.duration |
duration |
Duration of the current session segment | ns |
view.path |
view_path |
Page path of the View in which the segment started | - |
WebSocket Resources have no HTTP response, so there is no resource_status, resource_method, TTFB, download size, or HTTP timing.
Connection Fields¶
resource.websocket.* |
Intake field | Description | Unit |
|---|---|---|---|
connection_id |
resource_websocket_connection_id |
Unique physical connection ID, unchanged across session segments | - |
handshake_succeeded |
resource_websocket_handshake_succeeded |
Whether open was received |
boolean |
start_time |
resource_websocket_start_time |
Start time of the current segment | Unix ms |
end_time |
resource_websocket_end_time |
Time of close or finalization | Unix ms |
start_view_id |
resource_websocket_start_view_id |
View ID at the start of the segment | - |
end_view_id |
resource_websocket_end_view_id |
View ID at the end of the connection | - |
end_view_path |
resource_websocket_end_view_path |
Page path at the time of close or finalization | - |
tracking_end_reason |
resource_websocket_tracking_end_reason |
close_event, session_end, or page_exit |
- |
protocol |
resource_websocket_protocol |
Sub-protocol negotiated by the server | - |
setup_duration |
resource_websocket_setup_duration |
For the first segment: time from construction to open; for renewal segments: 0 |
ns |
Message Fields¶
resource.websocket.* |
Intake field | Description | Unit |
|---|---|---|---|
messages_in.count |
resource_websocket_messages_in_count |
Number of inbound messages | count |
messages_in.size |
resource_websocket_messages_in_size |
Total bytes of inbound messages | byte |
messages_out.count |
resource_websocket_messages_out_count |
Number of successful send() calls |
count |
messages_out.size |
resource_websocket_messages_out_size |
Total bytes of outbound messages | byte |
time_to_first_message_in |
resource_websocket_time_to_first_message_in |
Time from open to the first inbound message |
ns |
time_to_first_message_out |
resource_websocket_time_to_first_message_out |
Time from open to the first outbound message |
ns |
last_message_in_at |
resource_websocket_last_message_in_at |
Timestamp of the last inbound message | Unix ms |
longest_inbound_silence |
resource_websocket_longest_inbound_silence |
Longest interval between consecutive inbound messages | ns |
inbound_idle_duration_before_close |
resource_websocket_inbound_idle_duration_before_close |
Time from the last inbound message to close or finalization | ns |
buffered_amount_max |
resource_websocket_buffered_amount_max |
Peak bufferedAmount observed before each send() call |
byte |
buffered_amount_max is the peak sampled before calling send(), not a continuous monitoring value of the browser's send queue.
In the Resource Explorer, you can filter connection segments that started from a specific page using view_path. With RUM SDK 3.3.8 or later, you can also filter connection segments that ended on a specific page using resource_websocket_end_view_path.
Close Fields¶
resource.websocket.* |
Intake field | Description |
|---|---|---|
close_code |
resource_websocket_close_code |
Close code from the browser CloseEvent |
close_reason |
resource_websocket_close_reason |
Close reason |
was_clean |
resource_websocket_was_clean |
Whether the browser considers the connection cleanly closed |
These fields may be absent when the session expires or the page unloads and the data is finalized.
Using beforeSend¶
You can inspect, enrich, or filter WebSocket Resources:
datafluxRum.init({
// other configuration
enableExperimentalFeatures: ["track_websockets"],
beforeSend(event, domainContext) {
if (
event.type === "resource" &&
event.resource?.type === "websocket"
) {
event.context = {
...event.context,
socket_channel: "notifications",
}
console.debug(
"WebSocket completed",
event.resource.websocket,
domainContext?.webSocket
)
}
return true
},
})
The domainContext for a WebSocket Resource contains:
domainContext is only available in the beforeSend callback and is not uploaded.
Returning false can discard a specific connection:
beforeSend(event) {
if (
event.type === "resource" &&
event.resource?.type === "websocket" &&
event.resource.url.includes("/health-stream")
) {
return false
}
return true
}
Privacy and Security¶
The SDK collects the full WebSocket URL and parses the URL query. Do not place sensitive values such as passwords, long-lived tokens, or ID numbers in the URL.
Enabling collection does not bypass the page's CSP connect-src, server-side Origin validation, or other browser security policies, nor does it inject custom trace headers into the handshake request.
As long as third-party libraries call window.WebSocket after RUM initialization, the underlying connections are collected:
- Each automatic reconnection that creates a new connection generates a new
connection_idand Resource; - When a single connection is reused for multiple business topics, the SDK only provides connection-level aggregation;
- HTTP long polling phases are still collected as XHR or fetch Resources.
Verifying Integration¶
- Open the browser developer tools and confirm that the business WebSocket is connected and producing messages.
- Manually execute
socket.close(1000, "done"). - Filter the Network tab for
/v1/write/rum. - Look for
resource_type=websocketin the request data. - Check
handshake_succeeded, message count, byte count, and close fields.
If the connection never closes, wait for the session to expire and check for tracking_end_reason=session_end. Refreshing the page should show tracking_end_reason=page_exit; this send is a best-effort report during the page exit phase.
Frequently Asked Questions¶
No WebSocket Resource after configuration¶
Check in the following order:
- Is
enableExperimentalFeaturesan array containing"track_websockets"? - Is RUM initialized before the connection is created?
- Does the current session hit the
sessionSampleRate? - Has the connection already closed, or has the session expired?
- Did
beforeSendreturnfalse? - Is the connection created by a Worker?
Received a WebSocket error but no Resource yet¶
The SDK generates the final event on close or session finalization, not on the error event alone.
handshake_succeeded=false¶
The browser did not trigger open. Check the WebSocket URL, TLS certificate, CSP connect-src, reverse proxy Upgrade configuration, server-side Origin validation, and authentication.
Message size is 0¶
Confirm that the data type is string, ArrayBuffer, TypedArray, DataView, or Blob. The SDK does not serialize arbitrary objects to estimate size.
No HTTP status code visible¶
The browser WebSocket API does not expose the handshake HTTP status code to the page, so WebSocket Resources do not have a resource_status.