Graine AI

Events and listeners

Every listener, callback, event and stream the in-app SDKs offer — the main listener on iOS, Android and Flutter, React Native's events and client events, Kotlin Multiplatform's event flow, and the calls listeners — with each payload, threading and a JSON example.

Listeners are optional: implement only what you use — every method has a default that does nothing. Where each one runs:

PlatformDelivered onKept
iOSThe main threadWeakly — keep your own reference; a view controller that forgets to remove itself is not leaked
AndroidThe main threadUntil you remove it
FlutterThe UI isolateUntil you remove it
React NativeThe JavaScript threadHooks until unmount; client.on until you call the function it returned
Kotlin MultiplatformYour coroutine scope — collect the flows where you drawWhile you collect

The main listener

useGraineEvents(handler: (e: GraineEvent) => void): void
client.on(event: string, fn: (payload: any) => void): () => void   // returns: unsubscribe
 
useGraineEvents((e) => { if (e.type === "friction_detected") analytics.track("agent_friction", e); });

What each one means

EventWhenPayload
Session readyThe agent's settings loadedSession settings
Call stateThe bar's call connected, or is connectingconnected, connecting
CaptionA line being said, again as it fills inrole, text, live
Component / pendingThe agent drew a component, or one is on its wayThe component / { kind }
EndedThe bar's call is over, however it ended. Once—
Microphone deniedThe microphone was refusedNotAllowedError or NotFoundError
Quality, network, reconnectingThe line changedthe quality word; online; active
Connect progress (Android)Where a call being placed isstage, slow, failed
TransportWhat carries the audio, and why not the one asked fornot_configured, unreachable, screen_channel, media
ConnectivityThe engine page loading, ready, retrying or failedstate, attempt, reason
Action requested / completedThe agent called an action; your answername; the result
FrictionThe customer looks stuck; the agent has been toldname, screen, detail
Theme (iOS)The design's tokens loaded or changedthe tokens
Chat messageA chat turn arrived or changedthe turn (Android: role, text, live)
Chat state (Android)The chat connected or is connectingconnected, connecting
Agent volunteered (Flutter, React Native)The agent spoke without being askedthe text
ErrorSomething your team must fix — loud for you, invisible to the customera message
{ "type": "friction_detected", "name": "repeated_field_error", "screen": "delivery_address", "detail": "The \"Postal code\" field has rejected the customer 2 times." }

React Native events

useGraineEvents delivers:

typePayload
conversation_started—
conversation_endedreason — the customer hanging up, or the connection dying
agent_speakingspeaking
agent_volunteeredtext
action_requestedname
action_completedname, status, message
mutedmuted
mic_deniedreason
launcher_shownscreen
friction_detectedname, screen, detail
connection_qualityquality, rtt, jitter, loss
networkonline
reconnectingattempt, delayMs — the chat dropped; the next try is due
errormessage

Each fires once, at the moment, in order — use them for what you do once (log, count, show a toast), and the provider's state for drawing.

client.on(name, fn) adds the client's own events. It returns a function that removes the listener.

EventPayload
open / close{ transport } / { code, reason, byClient? } — byClient when your app closed it
sessionThe agent's settings, once loaded
turn_start, chunk, turn_endAn agent turn beginning; its words, as a string; its end
agent_speakingtrue or false
clearThe customer talked over the agent: drop whatever is still to be shown or played
text_sent{ id, text } — a waiting message has gone
transcript{ text, final } — the customer's speech, as recognised
widget, widget_pendingA component; { kind } while one is on its way
widget_result{ widget_id, data, summary } — the customer answered a component
action{ action_id, name, kind?, arguments } — the agent called one of your actions
action_result{ name, status, message? } — what your handler answered
diagnostic{ type: "actions", usable, undeclared, unhandled } — see checkActions
highlight{ name, ttlMs } — the agent points at an element; name null to stop
friction{ name, screen, detail } — before the agent is told
app_event{ name, detail?, cooldown_seconds?, max_per_session?, quiet?, data? } — an event reported to the agent
screen{ screen, actions } — the screen as it was sent, and the actions offered
variablesThe merged prompt variables, after a change
mutedtrue or false
quality{ quality, rtt?, jitter?, loss? } — on change only
network{ online }
reconnecting{ attempt, delayMs }
identityThe IdentityChannel changed
memories_changed{ forgotten: true, deleted }
scheduled_calls_changed{ booked: id } or { cancelled: id }
surface{ surface } — the call or the chat
native_call{ live } — a native call started or ended

Other names the client emits are its own plumbing and may change between versions; do not listen for them.

const off = client.on("scheduled_calls_changed", () => refreshUpcoming());
// later
off();

Calls listeners

GraineCalls.onOutcome(fn: (o: GraineCallOutcome) => void): () => void
GraineCalls.onIncomingCall(fn: (c: GraineIncomingCall) => void): () => void
GraineCalls.subscribe(fn: () => void): () => void      // any change to the snapshot

Do not depend on the order between a state change and the outcome it leads to. A call can ring, be answered and end before your app's code is running: React Native and Flutter hold the last 20 outcomes and rings and hand them to the first listener, oldest first. Send each outcome to your server with its callId.

MethodPlatformsWhen
Incoming callall but the websiteA call started ringing on this device — the SDK shows the ring; this is for your own UI or analytics
Call stateiOS, Android, Kotlin Multiplatform, Flutter, React Native (snapshot)The call moved: idle, ringing, connecting, active, ended
Call outcomeall but the websiteWhat became of a call — answered, declined, missed, ended (local, remote, failed) or failed
Call caption (Android)AndroidThe agent's words as they are said, then the finished line; the customer's likewise
Agent speaking (Android)AndroidThe agent's voice started or stopped
Call controls (Android)AndroidMuted or speaker changed — from your app or from the call screen
{ "callId": "c3a8f1d2-5b7e-4a19-9f02-6d4e8b1a7c35", "outcome": "missed", "reason": null, "durationSeconds": null, "hosted": true }

Payload fields: GraineCallOutcome, GraineIncomingCall.

On this page