Loops AI Docs

Architecture

How the native container, the typed bridge, and native session ownership work.

The SDK is a native container around the Loops web runtime loaded in mode=sdk. The web owns the conversation UI; native owns the session, routing, and analytics. Understanding this helps you reason about callbacks and security.

The container

LoopsAIChatViewController
  └─ WKWebView  → chat.loopsai.com/<agentId>?mode=sdk&platform=ios…
        ↕ loopsAIBridge (typed message bridge)

The bridge

Native and web talk over a typed message envelope on the native channel:

{ "protocolVersion": 1, "type": "nativeAction", "name": "productQuoteChanged",
  "requestId": "req_123", "payload": { /* … */ } }
  • Web → native actions drive the host callbacks (ready, message, responding, product quote, conversation active, analytics passthrough, open URL, close).
  • Native → web actions are the methods you call (context updates, search, try-on, size). See Flow modes.
  • Unknown action names are ignored. protocolVersion lets a shipped binary evolve without breaking older app versions.

Native session ownership

iOS WebKit can wipe partitioned third-party storage on app kill, which would lose the anonymous session. The SDK fixes this natively:

  • It bootstraps the session against the runtime and persists the anon session in UserDefaults.
  • It re-injects the session (_lsuid / _lscid) on every WebView load, and applies persistSession updates the runtime emits.
  • Bootstrap retries transient failures with exponential backoff.

The result: the session survives app relaunch with no extra work on your side.

Security

  • Origin allowlist — only chat.loopsai.com and your custom environment host can drive the bridge; messages from other frames are ignored, and only the main frame is trusted.
  • Foreign links open in the system browser, never inside the WebView.

Authenticated (non-anonymous) sessions via a token provider are on the roadmap; v1 is anonymous-session based. Today the bridge accepts a token-refresh request but it is a no-op until the auth provider ships.

Host callbacks reference

CallbackFires when
loopsAIChatDidBecomeReadyThe runtime is live; safe to push context.
loopsAIChat(_:isResponding:)The assistant starts/stops responding.
loopsAIChat(_:didChangeProductQuote:)The active product quote changes (nil = cleared).
loopsAIChat(_:didEmitAnalyticsEvent:)A canonical analytics event crossed the bridge.
loopsAIChatDidBecomeConversationActiveA conversation becomes active.
loopsAIChat(_:didReceiveMessageEvent:)A message / new-chat / overlay event.
loopsAIChatDidRequestCloseThe runtime asked to close (default: dismiss/pop).
loopsAIChat(_:didRequestOpenURL:)A foreign link should open externally.
loopsAIChat(_:didFailWith:)A load / bridge / session error occurred.

On this page