Skip to main content

Quick Start: iOS

Embed the Lovina chat widget in your iOS app using a Swift WKWebView wrapper. Minimum deployment target: iOS 15.0.

Step 1: Install from the Nexus registry

Point Swift Package Manager at Lovina's private Swift registry and authenticate (see the full installation guide for credential details):

swift package-registry set https://packages.ailovina.com/repository/swift-releases/
swift package-registry login https://packages.ailovina.com/repository/swift-releases/login \
--username "your-nexus-username" --password "your-nexus-password"

Then add the package by its identity in Package.swift:

dependencies: [
.package(id: "lovina.lovina-chat-sdk", from: "{version}")
],
targets: [
.target(name: "YourApp", dependencies: [
.product(name: "LovinaChatSDK", package: "lovina.lovina-chat-sdk")
])
]

In Xcode, use File → Add Package Dependencies… and enter the identity lovina.lovina-chat-sdk. Prefer to vendor the prebuilt binary instead? See manual XCFramework install.

Step 2: UIKit Integration

import UIKit
import LovinaChatSDK

class ChatViewController: UIViewController {

private let chatWidget = LovinaChatWidget()

override func viewDidLoad() {
super.viewDidLoad()

view.addSubview(chatWidget)
chatWidget.frame = view.bounds
chatWidget.autoresizingMask = [.flexibleWidth, .flexibleHeight]

chatWidget.onEvent = { event in
switch event {
case .loaded(let authToken):
print("Widget loaded, token: \(authToken ?? "none")")
case .messageReceived(let message):
print("New message: \(message)")
case .unreadCountChanged(let count):
self.updateBadge(count)
case .closed:
self.dismiss(animated: true)
case .error(let code, let message):
print("Error [\(code)]: \(message)")
}
}

chatWidget.configure(LovinaChatConfig(
websiteToken: "your-website-token",
baseUrl: "https://chat-prod.ailovina.com"
))
}

deinit {
chatWidget.destroy()
}
}

Step 3: SwiftUI Integration

import SwiftUI
import LovinaChatSDK

struct ChatScreen: View {
var body: some View {
LovinaChatView(
config: LovinaChatConfig(
websiteToken: "your-website-token",
baseUrl: "https://chat-prod.ailovina.com"
),
onEvent: { event in
switch event {
case .messageReceived(let message):
print("New message: \(message)")
default:
break
}
}
)
.edgesIgnoringSafeArea(.all)
}
}

Configuration Options

ParameterTypeDefaultDescription
websiteTokenStringrequiredWebsite token for this agent, from your Lovina dashboard
baseUrlStringrequiredBase URL of your Lovina instance
localeString"id"Widget locale code (3 languages supported)
colorSchemeString"auto""light", "dark", or "auto"
userLovinaChatUser?nilPre-identified user
themeLovinaThemeConfig?nilTheme color and layout overrides (hex String colors, not UIColor)
brandingLovinaBrandingConfig?nilWhite-label branding overrides
texts[String: Any]?nilUI string overrides, keyed by translation key
featuresLovinaFeatureFlags?nilFeature-flag overrides
displayModeString"fullscreen""popup", "sidebar", or "fullscreen"

Pre-identified Users

Associate chat sessions with known users:

let config = LovinaChatConfig(
websiteToken: "your-token",
baseUrl: "https://chat-prod.ailovina.com",
user: LovinaChatUser(
identifier: "user-12345",
name: "Jane Doe",
email: "jane@example.com",
identifierHash: "hmac-hash-for-verification",
phoneNumber: "+6281234567890",
customAttributes: [
"plan": "premium",
"signup_date": "2025-01-15"
]
)
)

Theming and White-Label Branding

Apply a custom brand color (hex string, not UIColor) and branding:

let config = LovinaChatConfig(
websiteToken: "your-token",
baseUrl: "https://chat-prod.ailovina.com",
theme: LovinaThemeConfig(primaryColor: "#6366F1"),
branding: LovinaBrandingConfig(brandName: "Acme Support", poweredBy: false)
)

See the Configuration page for the full set of theme, branding, texts, and features options.

Event Handling

EventDescription
.loaded(authToken)Widget finished loading. authToken is available if the user has a session.
.messageReceived(message)New message received. message is a dictionary with the payload.
.unreadCountChanged(count)Unread count changed. Use count to update a badge.
.closed(reason)Chat was closed by user or agent.
.error(code, message)An error occurred.

Session Management

Sessions are persisted automatically in the Keychain. To clear a session:

chatWidget.clearSession()
chatWidget.reload()

Lifecycle

The widget cleans up automatically in deinit. You may also call destroy() explicitly:

deinit {
chatWidget.destroy()
}

Network connectivity is monitored via NWPathMonitor. The widget handles offline/online transitions automatically.

Development Setup

To test against your local dev server:

  1. Run pnpm dev in the SDK repo
  2. Add packages/ios/ as a local Swift Package in Xcode
  3. Set baseUrl = "http://localhost:3001"
  4. Run on the iOS Simulator

Next Steps