Installation and initialisation

KletsoConfig fields, anonymous versus signed-in users, context, app events and lifecycle.

Install

flutter pub add kletso_flutter

Requires Dart 3.9 / Flutter 3.35 or newer. Optional companions: url_launcher (open url actions), a notifications plugin such as flutter_local_notifications (OS tray for system notifications), firebase_messaging (push tokens).

Initialise once

final client = await Kletso.init(KletsoConfig(
  publishableKey: 'kl_pub_dev_…',
  agentId: 'agt_…',
  environment: KletsoEnvironment.development,   // default: production
));

Kletso.init returns the client and makes it available as Kletso.instance. Calling it again disposes the previous client (handy on hot restart). Kletso.isInitialized and Kletso.reset() exist for tests.

KletsoConfig

FieldDefaultPurpose
publishableKeyrequiredMust start with kl_pub_; the constructor throws on a secret key.
agentIdrequiredThe agent to talk to. Change at runtime with client.useAgent(id).
environmentproductiondevelopment or production. Should match the key.
baseUrlhttps://api.kletso.aiPoint at http://127.0.0.1:8788 for a local runtime.
transportautoauto (WebSocket, then SSE after 2 failures), webSocket, sse.
heartbeatInterval / heartbeatTimeout25 s / 10 sPing cadence and how long to wait for pong before reconnecting.
connectTimeout10 sHandshake budget.
backoffBase / backoffCap500 ms / 30 sReconnect backoff with full jitter.
outboundQueueLimit100Frames kept while offline; the oldest is dropped beyond this.
typingIndicatorTtl4 sHow long agentTyping stays true without new deltas.
reportLocalActionstrueTell the runtime when a local action ran (for the transcript).
allowServerCommandsfalseLet the agent run your local actions without a tap (app.command).
debugValidateUifalseValidate every surface in debug builds and log issues.
logLevelwarningdebug, info, warning, error, none.

Optional constructor arguments to Kletso.init: api and transport (inject the fake backend), httpClient, logger, device (KletsoDevice(platform:, sdk:, version:, locale:) sent with the session), tokenStore.

Identity

Exactly one of these after init:

await client.identifyAnonymous();
// or
await client.authenticate(
  token: hostJwt,
  onTokenExpired: () async => await myBackend.freshKletsoToken(),
);
  • Anonymous: a visitor id is generated and stored under the key kletso.anonymousId in the tokenStore. The default store is KletsoMemoryTokenStore, so implement KletsoTokenStore over shared preferences or secure storage if visitors should keep their history across launches.
  • Signed in: the token is a JWT your backend signs (HS256 shared secret, or RS256/ES256 published at a JWKS URL; configured in Settings → End-user auth). Required claim sub; optional name, email, plan, locale, tier, exp, nbf, iss, aud. When the runtime rejects an expired token the refresher is called and the connection resumes.
  • client.logout() revokes the session server side and clears local state. client.isAuthenticated tells you whether a session exists.

Context

client.setContext({'plan': 'pro', 'currency': 'INR', 'locale': 'en-IN'});
client.updateContext({'screen': 'checkout', 'cartValue': 3198});

setContext replaces, updateContext merges. Context is stored with the session and the end user, and reaches the prompt (public keys), trigger conditions and tool templates. Keep it small and flat.

App events

client.track('geofence_entered', {'store': 'Shibuya'});
client.screen('checkout');

Both are silent: nothing appears in the chat unless a trigger rule reacts. They are sent over the socket when connected and queued otherwise. The SDK also tracks kletso.chat_opened (constant KletsoEvents.chatOpened) every time open() shows the chat, with messages (total so far) and userMessages (sent by the user) so a rule can greet only a fresh chat.

Lifecycle

KletsoLauncher and KletsoChat handle the app lifecycle for you (since kletso_flutter 0.2.2): the socket is closed cleanly when the app goes to the background and reconnected, with the missed events replayed, when it returns. A dropped connection is not an error: the client reports KletsoConnectionChanged(reconnecting) and then open; an error event only follows when the reconnect itself fails.

If you drive KletsoClient without those widgets, bind the lifecycle yourself:

final lifecycle = client.bindAppLifecycle();   // pause() in background, resume() in foreground
await client.pause(); await client.resume(); await client.dispose();

bindAppLifecycle (from kletso_flutter) returns an AppLifecycleListener you can dispose with your app state.

Last updated 2026-09-28 · Report an issue with this page