Skip to main content

Events stream

MethodPathAuth
GET/eventsbearer

Server-Sent Events stream that mirrors the bot's logger event hub line-by-line. Every logger.state(...), TCP/HTTP transport message, and dispatcher result lands here as JSON.

Connecting

curl -N http://localhost:8090/events -H 'authorization: Bearer <token>'

The connection stays open indefinitely. SSE auto-reconnect is built into every browser's EventSource; for raw curl callers, exit and reopen the stream when it dies.

Frame format

Standard Server-Sent Events. Each frame is a data: {…}\n\n block. The body is JSON.

event: log
data: {"timestamp_ms":1778201531241,"level":"info","scope":"auth_client","session_id":"bot-1","transport":"http","direction":"outgoing","message":"POST https://11ef5c.playfabapi.com/Client/LoginWithEmailAddress?sdk=UnitySDK-2.178.230929 body={...}"}

event: log
data: {"timestamp_ms":1778201531870,"level":"info","scope":"tcp","session_id":"bot-1","transport":"tcp","direction":"outgoing","message":"VChk {ID=\"VChk\" OS=\"Android\" OSt=2}"}

event: session
data: {"snapshot":{"id":"bot-1","status":"in_world",...}}

Two event: flavors are emitted:

  • event: log — every logger line. level is info / warn / error / state. scope identifies the source (auth_client, tcp, bot, tutorial, seraph, …).
  • event: session — periodic snapshot of a bot's state, same shape as GET /api/bots/{id}. Emitted on every state transition.

Field reference

log payload

FieldTypeMeaning
timestamp_msi64Unix epoch ms when the event fired.
levelstringinfo / warn / error / state.
scopestringSource module (e.g. auth_client, tcp, bot).
session_idstring|nullBot id if the event is bot-scoped.
transportstring|nulltcp / http for wire events.
directionstring|nulloutgoing / incoming for wire events.
messagestringPre-formatted display line.

session payload

{ "snapshot": { ...BotSnapshot } } — see GET /api/bots/{id} for every field.

Why SSE

SSE is one-way (server → client) which matches the use case exactly — the dashboard wants live tail of what the bot's doing, no client→server messages on this socket. Auto-reconnect is built into every browser's EventSource, no library required.

For WebSocket-style bidirectional communication, use the raw dispatch over POST /invoke.

Using from the browser

Browsers don't let EventSource set custom headers, so use the query- string form of the token:

const es = new EventSource(
`http://localhost:8090/events?token=${encodeURIComponent(token)}`,
);

es.addEventListener("log", (e) => {
const ev = JSON.parse(e.data);
console.log(`[${ev.scope}] ${ev.message}`);
});

es.addEventListener("session", (e) => {
const { snapshot } = JSON.parse(e.data);
ui.updateBotRow(snapshot);
});

// Default `message` event fires for un-typed frames; keep it as a
// fallback so future event kinds don't go silently dropped.
es.onmessage = (e) => console.debug("untyped event:", e.data);