Lag diagnostics (JavaScript)
Lag diagnostics is an opt-in debug tool, not a gameplay or telemetry feature. It records a small, bounded metadata stream when an operator asks for one. It is designed to help compare movement delivery behaviour across clients; it does not measure a player’s one-way latency, RTT, path asymmetry, or packet loss.
Enable it in application source
Section titled “Enable it in application source”The JavaScript SDK is off by default. Enable the recorder only in the code that creates the client:
const client = await CitadelClient.connect("wss://game.example/realtime", { diagnostics: { lagRecorder: { enabled: true } },});There is intentionally no URL parameter, browser-storage value, or remote
configuration bit that can enable it. When the option is missing or false,
the SDK allocates no ring buffer, advertises no diagnostics capability, ignores
all diagnostics control frames, and never uploads an artifact. This makes a
new server safe with an older or disabled client, and a new client safe with a
server that does not support diagnostics.
Capture lifecycle
Section titled “Capture lifecycle”After authentication, an opted-in client waits for the server’s SERVER_TIME
offer and advertises its supported diagnostics capability. A trusted server
then controls the lifecycle:
- It sends
STARTwith a capture id, generation, deadline, fixed byte cap, and an allowed movement-metadata filter. - The SDK records only that locally allowed metadata in a fixed-size ring. A full ring overwrites its oldest row and marks the artifact as truncated.
- The server sends a per-client
FLUSHgrant when it is ready to collect. Ending a match is the usual time to flush, but the game developer chooses when to start and stop a capture. - The SDK freezes the snapshot, gzip-compresses its
CLAGv1 bytes, uploads it once, and clears the snapshot only after a successful response.
The server’s clock offer is correlation metadata. The SDK derives observed arrival timestamps from that anchor and local elapsed time, including its clock uncertainty. It must not present those timestamps as a network timing proof.
The SDK never records application payloads, entity identifiers, player-private
identifiers, or arbitrary packet bodies. The server cannot weaken that local
metadata-only policy through START.
Upload rules
Section titled “Upload rules”FLUSH carries a same-origin relative upload_path, a short-lived signed
bearer, the permitted MIME/content encoding, and a compressed-byte cap. The
SDK uses:
POST <same origin><upload_path>Authorization: Bearer <one-use grant>Content-Type: application/vnd.citadel.lag-captureContent-Encoding: gzipThe grant belongs to one capture, session/player, tenant, match, attempt, and
deadline. It is not exposed through normal status frames. Do not log it or put
it in crash reports. A failed or ambiguous upload consumes no reusable client
credential: retain the frozen bytes and wait for the server to issue a new
FLUSH attempt. The SDK deliberately does not retry a bearer automatically.
Compatibility and troubleshooting
Section titled “Compatibility and troubleshooting”| Situation | Expected result |
|---|---|
| Debug option is disabled | No capability, recording, or upload. |
| Server has no diagnostics support | Normal connection and gameplay; no capture begins. |
| Legacy client | It never advertises the capability, so it is ineligible for a capture. |
START is malformed or outside local policy |
It is ignored and current evidence is preserved. |
| Upload rejects or expires | The server can request a fresh attempt; never reuse a token. |
| Capture ring fills | The result stays bounded and reports truncation/overwrite quality. |
For the native lifecycle that produces START and FLUSH, see
Lag diagnostics native API. For
configuration and metric interpretation, see
Lag diagnostics operations.