@getuserfeedback/protocol
Public contracts for host integrations that load and control the getuserfeedback widget, plus versioned realtime wire messages shared by clients and services.
Chat realtime
The chat-realtime export defines the registration and invalidation messages used after a WebSocket transport opens. A socket has one protocol mode and cannot switch between widget and chat registration. Registration sequences are scoped to one chat socket and increase for every client send, including retries after a missing or retryable outcome. A new socket starts a new sequence. Servers atomically claim only newer sequences before authentication; older or equal attempts are superseded and cannot mutate registration state. Clients apply outcomes only for their latest sequence and ignore older outcomes.
Only chat.connected establishes an authorized audience. That audience is an immutable registration snapshot: it is never silently retargeted when identity configuration changes. audienceRevision identifies the snapshot, and registrationExpiresAt is the authoritative moment when the server stops authorizing it. registrationExpiresInMs is the remaining lease duration measured when the server constructs the response. It is a clock-independent scheduling hint, not a new expiry boundary: transport time has already consumed part of it, so clients refresh and stop with a safety margin. The socket may remain open after expiry or revocation, but it receives no audience events until a newer registration succeeds. Clients register again before expiry and after changing credentials or identity inputs.
A rejection for a newly claimed latest sequence leaves the socket unauthorized. superseded is different: it reports an attempt that did not claim state and therefore does not clear a newer registration. retryable governs automatic retry of the same operation with unchanged inputs; false does not prevent a later registration after credentials or configuration change. A structurally invalid request with a usable sequence produces invalid_request; failed authentication produces invalid_auth. A routed chat.connect request whose sequence cannot be parsed clears server-side authorization and closes the socket without an outcome, because an uncorrelated rejection cannot be applied safely.
conversations.sync is scoped to its named audience revision, is only a best-effort invalidation hint, and never establishes or changes authorization. Clients reconcile through authenticated HTTP after registration, after each matching hint, and periodically while connected; the socket is not a source of truth.
Lifecycle contract
This package defines the public shapes for:
- init-time widget configuration
- post-load widget commands
- host SDK types and settlement helpers
What hosts can do after init
After the widget has been initialized, a public host integration may:
- identify the current user with
identify - update consent with
configure({ consent }) - update theme with
configure({ colorScheme }) - update auth with
configure({ auth }) - open, prefetch, prerender, close, or reset flows
Identification
Public identification is already supported.
Use one of these public command shapes:
{ kind: "identify", userId, traits? }{ kind: "identify", traits }
identify is a post-init lifecycle operation. The public root contract does not currently accept identity inside init or configure.
Navigation updates
Explicit public navigation update commands are not part of the current public contract.
There is no public navigate, updatePage, or hostContextUpdated command in @getuserfeedback/protocol. Hosts should not invent private navigation bridges on top of internal loader or core commands.
Loader-driven integrations may still observe browser URL changes internally for targeting and telemetry, but that behavior is internal runtime behavior, not a stable public contract yet.
GTM and other adapters
Adapters built on top of this package should only bridge capabilities that exist in this public contract.
- Use
identifyonly because it is public and supported. - Keep consent and theme updates mapped to
configure. - Do not expose custom navigation-update fields until this package defines a public navigation contract.