Configuration
LoopsAIChatConfig — agent, environment, feature flags, analytics, presentation.
Everything is configured through LoopsAIChatConfig.
val config = LoopsAIChatConfig(
agentId = "YOUR_AGENT_ID",
environment = LoopsEnvironment.Production,
initialContext = LoopsAIChatContext(productContext = mapOf("productCode" to "SKU123")),
features = LoopsFeatureFlags(virtualTryOnEnabled = true),
analytics = LoopsAnalyticsConfig(loopsSinkEndpoint = null),
locale = "en",
showCloseButton = true
)Options
| Parameter | Type | Default | Purpose |
|---|---|---|---|
agentId | String | — | Your Loops agent identifier (required). |
environment | LoopsEnvironment | Production | Which runtime host to load. |
initialContext | LoopsAIChatContext? | null | Product/user context at launch. See Context. |
features | LoopsFeatureFlags | DEFAULT | Per-launch flow-mode flag overrides. |
analytics | LoopsAnalyticsConfig | DEFAULT | Native analytics destinations. See Analytics. |
locale | String? | null | Pins the chat language, overriding the device. Accepts a plain code or a language tag ("tr", "tr-TR", Locale.getDefault().toLanguageTag()) — it is normalized to the base language. Omit to follow the device. |
showCloseButton | Boolean | true | Show the native close affordance (top-right overlay). |
startFresh | Boolean | false | Start a new conversation on load instead of resuming the last one. |
keepAliveEnabled | Boolean | true | Keep the chat runtime warm for an instant reopen (shared WebView pool). |
developmentMode | Boolean | false | Load chat even when the agent's web channel is inactive — for staging / QA builds. |
designMode | Boolean | false | Same override, for design / preview builds. |
Header close-button slot
showCloseButton = true (the default) renders the SDK's own native close button in
the chat header. When it is on, the SDK automatically tells the web widget how much
header space to reserve for that button (headerActionSlotWidthPx), so the native
button never overlaps the widget's own controls. In SDK mode the widget's
favorite / heart control moves to the left side of the header to stay clear of
the reserved area.
You don't lay any of this out yourself — enabling the native close button reserves
aligned header space automatically. Set showCloseButton = false when you present
your own close affordance (e.g. a toolbar) and don't want the SDK's.
Environment
sealed class LoopsEnvironment {
object Production // chat.loopsai.com
data class Custom(val url: String) : LoopsEnvironment() // self-host; host is added to the origin allowlist
}Feature flags
LoopsFeatureFlags lets you override flow-mode availability for a launch. Each flag
is nullable — when left null, the server-resolved agent config decides. Only
set a flag to deliberately override it; the SDK forwards only the flags you set, so
the web keeps server defaults for the rest.
val features = LoopsFeatureFlags(
virtualTryOnEnabled = true,
searchEscalationEnabled = true
)Available flags: virtualTryOnEnabled, searchEscalationEnabled,
productSuggestionEnabled, outfitSuggestionEnabled.
Flags are forwarded to the web runtime over the bridge. Use them to gate which
native entry points you surface in your own UI (e.g. show a "Try on" button only
when virtualTryOnEnabled != false).
Integration patterns
The chat is hosted by a single LoopsAIChatFragment. There are three ways to open it:
// 1. Activity — simplest, standalone full-screen host.
LoopsAIChat.openAsActivity(context, config, listener = myListener)
// 2. Fragment — embed into any container you manage.
LoopsAIChat.open(supportFragmentManager, R.id.container, config, listener = myListener)
val fragment = LoopsAIChat.newFragment(config, listener = myListener) // or build it yourself
// 3. Compose — the composable wrapper.
LoopsAIChatView(config = config, modifier = Modifier.fillMaxSize(), onClose = { /* … */ })LoopsAIChatConfig carries analytics closures and is not Parcelable — it is
passed in-process via an internal token registry, not through an Intent/Bundle.
An Activity-hosted chat is re-launched (not state-restored) after process death;
the Fragment-in-layout and Compose paths re-supply config on recreation. The
native session identity always survives via the session store.
Data & session management
A few static APIs let you control the warm runtime pool and the native session — useful on logout, memory pressure, or a privacy reset:
// Drop the warm WebView pool (logout / memory pressure); cookies & storage are kept.
LoopsAIChat.clearWebCache()
// Full wipe: warm runtimes + native session + web cookies/localStorage/cache.
// The next open cold-loads a brand-new pseudonymous identity.
LoopsAIChat.resetAllData(context)
// Wipe just the native session (anon id + per-agent conversation pointers).
LoopsSessionStore.reset()Enabling & disabling chat (availability)
Chat can be turned on or off per platform from your LoopsAI dashboard — open Channels → Android and use its Active / Passive toggle. This controls the Android agent independently of Web and iOS: turning Android off never affects the web widget or your iOS app, and vice versa. It takes effect without an app update, so you can keep Android off at launch and flip it on later, or disable it for maintenance.
If a platform's toggle has not been set yet, that platform falls back to the Web channel status — so existing integrations keep working until you set the per-platform switch.
Check availability from the app
Before you show your chat entry point (button, tab, etc.), ask the SDK whether the agent is active for this platform and show/hide it accordingly:
LoopsAIChat.fetchAvailability("YOUR_AGENT_ID") { available ->
chatButton.isVisible = available
}It fails open (returns true) on a network error, so a transient blip never
hides a working chat.
Load while inactive (staging / QA / preview)
To keep loading the chat even while the channel is Inactive — e.g. on a staging
build or a design preview — set developmentMode (or designMode) on the config:
val config = LoopsAIChatConfig(
agentId = "YOUR_AGENT_ID",
developmentMode = true, // ignore the Inactive channel status
)Leave developmentMode / designMode off in production — otherwise a
disabled channel would still load. The dashboard toggle + fetchAvailability
check is the intended production path.
Next: Context.