Skip to main content
The stream is the recommended event channel: your backend holds one outbound WebSocket to Gleap’s realtime cluster and receives every event for your project on it — no inbound endpoint to expose, no per-delivery signature verification, no retry windows, and lower latency than webhooks (which queue and retry per delivery). The stream speaks the Pusher wire protocol, so any mature off-the-shelf Pusher client (Node, Java, Go, .NET) works unmodified. Webhooks remain fully supported when your infrastructure policy prefers inbound HTTP.

Connect

Read the connection parameters at startup — never hardcode them:
Point your client’s channel authorization at authEndpoint (with your token as the Authorization header) and subscribe to channel. Include two custom auth params:
  • consumerId names the connecting instance ([A-Za-z0-9_-]{1,64}).
  • typingEvents: true opts this stream into agent.typing.* (high volume; default off).
Also configure the client’s user authentication against userAuthEndpoint (Pusher “signin”) — that is what allows the server to cleanly terminate a superseded connection during takeover. Event data arrives as a JSON string of the same envelope webhooks receive — JSON.parse it (Pusher clients usually do this for you). Payloads larger than the socket limit arrive as a slim pointer (data.truncated: true with the conversation/message id) — fetch the full object over REST.

Exactly one consumer

Gleap holds one active consumer per project. When a connection authorizes with a new consumerId, it takes over: the previous consumer’s connection is terminated and a s2s.takeover control event is published (disconnect yourself if you receive it and the consumerId isn’t yours). Rolling deployments therefore need no coordination — the new pod connects, the old one is dropped. During the handover both may briefly receive the same events: deduplicate by (conversation id, sequence).

Resync on every (re)connect — mandatory

A dropped connection loses the events published during the gap; there is no replay. After every connect — first connect, reconnect, and after a takeover — run per-conversation catch-up for anything you track:
  1. GET /v3/s2s/contacts/{userId}/conversations for contacts with open activity, and/or
  2. GET /v3/s2s/conversations/{id}/messages?after=<last message id you have> per conversation.
This is the same self-healing model the Gleap widget uses, and it also covers webhook consumers after their retry window.