Integration¶
Step 1: Add SDK and Configure Permissions¶
Add the SDK Dependency:
Option A: Swift Package Manager
- File > Add Package Dependencies
- Enter the package URL (to be published)
Option B: XCFramework
Download the XCFramework and add it to your project's Frameworks, Libraries, and Embedded Content.
Configure Info.plist:
<key>NSCameraUsageDescription</key>
<string>Camera access is needed to capture your photo for virtual try-on</string>
<key>NSPhotoLibraryUsageDescription</key>
<string>Photo library access is needed to select photos for virtual try-on</string>
Step 2: Add Config and Initialize SDK¶
Create GlanceConfig.swift in Xcode: File > New > File > Swift File
import Foundation
import GlanceChatSDK
struct GlanceConfig {
// Partner credentials (provided by Glance)
static let partnerId = "provided-by-glance"
static let storeHandle = "provided-by-glance"
static let tenantId = "provided-by-glance"
static let environment = GlanceChatConfig.Environment.development
// Firebase Configuration (provided by Glance)
static let firebaseProjectId = "provided-by-glance"
static let firebaseApiKey = "provided-by-glance"
static let firebaseAuthDomain = "provided-by-glance"
static let firebaseStorageBucket = "provided-by-glance"
static let firebaseMessagingSenderId = "provided-by-glance"
static let firebaseAppId = "provided-by-glance"
// API Endpoints (provided by Glance)
static let emberEndpoint = "provided-by-glance"
static let bifrostEndpoint = "provided-by-glance"
static let embedCdnEndpoint = "provided-by-glance"
static let glanceAccountEndpoint = "provided-by-glance"
static let webAuthUrl = "provided-by-glance"
static let googleSsoClientId = "provided-by-glance"
// Shopify Configuration (provided by Glance)
static let shopifyBaseUrl = "provided-by-glance"
static let defaultCollectionId = "provided-by-glance"
// Branding (your values)
static let brandName = "YOUR BRAND NAME"
static let brandLogoUrl = "https://your-cdn.com/logo.png"
}
Important
Add GlanceConfig.swift to your .gitignore to avoid committing credentials.
Never inline config values
Always keep credentials in GlanceConfig.swift and reference them.
Do NOT copy config values directly into your App entry point.
Initialize in your App struct:
import SwiftUI
import GlanceChatSDK
@main
struct YourApp: App {
init() {
initializeSDK()
}
private func initializeSDK() {
do {
let config = try GlanceChatConfig.Builder()
.firebaseProjectId(GlanceConfig.firebaseProjectId)
.firebaseApiKey(GlanceConfig.firebaseApiKey)
.firebaseAuthDomain(GlanceConfig.firebaseAuthDomain)
.firebaseStorageBucket(GlanceConfig.firebaseStorageBucket)
.firebaseMessagingSenderId(GlanceConfig.firebaseMessagingSenderId)
.firebaseAppId(GlanceConfig.firebaseAppId)
.emberEndpoint(GlanceConfig.emberEndpoint)
.bifrostEndpoint(GlanceConfig.bifrostEndpoint)
.embedCdnEndpoint(GlanceConfig.embedCdnEndpoint)
.environment(GlanceConfig.environment)
.glanceAccountEndpoint(GlanceConfig.glanceAccountEndpoint)
.googleSsoClientId(GlanceConfig.googleSsoClientId)
.storeHandle(GlanceConfig.storeHandle)
.webAuthUrl(GlanceConfig.webAuthUrl)
.brandName(GlanceConfig.brandName)
.brandLogoUrl(GlanceConfig.brandLogoUrl)
.build()
GlanceChatSDK.shared.initialize(partnerId: GlanceConfig.partnerId, config: config)
} catch {
print("SDK initialization failed: \(error)")
}
}
var body: some Scene {
WindowGroup {
ZStack {
ContentView()
// SDK overlay — render last so it floats on top
if GlanceChatSDK.shared.isInitialized {
GlanceChatOverlay()
.ignoresSafeArea()
}
}
.onOpenURL { url in
_ = GlanceChatSDK.shared.handleDeepLink(url)
}
}
}
}
Note
The SDK creates its own Firebase instance. It will not conflict with your existing Firebase setup.
Step 3: Set Page Context¶
Call setPageContext() when users navigate to key screens so the AI can provide relevant responses.
| Page Type | When to Set | Required Metadata |
|---|---|---|
"PLP" |
Product listing / category page | page_identifier, current_url, tenant_id |
"PDP" |
Product detail page | page_identifier, product_id, current_url, tenant_id |
// Product List View
struct ProductListView: View {
let collectionId: String
var body: some View {
ScrollView { /* content */ }
.onAppear {
GlanceChatSDK.shared.setPageContext("PLP", metadata: [
"page_identifier": collectionId,
"current_url": "\(GlanceConfig.shopifyBaseUrl)/collections/\(collectionId)",
"tenant_id": GlanceConfig.tenantId
])
}
}
}
// Product Detail View
struct ProductDetailView: View {
let product: Product
var body: some View {
ScrollView { /* content */ }
.onAppear {
GlanceChatSDK.shared.setPageContext("PDP", metadata: [
"page_identifier": product.variantId,
"product_id": product.variantId,
"current_url": "\(GlanceConfig.shopifyBaseUrl)/products/\(product.handle)",
"tenant_id": GlanceConfig.tenantId
])
}
}
}
Step 4: Handle Product Navigation (Optional)¶
Set up callbacks to handle product clicks from the chat interface:
// In your App init or after SDK initialization
GlanceChatSDK.shared.onProductClick = { product in
// Navigate to product detail page
print("Product clicked: \(product.id)")
}
GlanceChatSDK.shared.onDeeplinkClick = { deeplinkUrl in
if let url = URL(string: deeplinkUrl) {
UIApplication.shared.open(url)
}
}
Step 5: Add Try-On Widget (Optional)¶
Add a "Try On" button to product cards that triggers the virtual try-on experience.
struct TryOnWidget: View {
let onClick: () -> Void
@State private var isExpanded = false
var body: some View {
HStack(spacing: 0) {
Image(systemName: "sparkles")
.font(.system(size: isExpanded ? 14 : 16, weight: .medium))
.foregroundColor(.white)
if isExpanded {
Text("Try On")
.font(.system(size: 12, weight: .semibold))
.foregroundColor(.white)
.padding(.leading, 6)
}
}
.padding(.horizontal, isExpanded ? 12 : 8)
.padding(.vertical, 6)
.frame(minWidth: 36, minHeight: 36)
.background(
LinearGradient(
colors: [Color(red: 0.58, green: 0.42, blue: 0.85).opacity(0.85),
Color(red: 0.48, green: 0.32, blue: 0.75).opacity(0.85)],
startPoint: .topLeading, endPoint: .bottomTrailing
)
)
.clipShape(Capsule())
.shadow(color: Color.purple.opacity(0.3), radius: 4)
.onTapGesture { onClick() }
.animation(.spring(response: 0.3), value: isExpanded)
.onAppear {
Timer.scheduledTimer(withTimeInterval: 3.0, repeats: true) { _ in
withAnimation { isExpanded.toggle() }
}
}
}
}
// Trigger try-on from product card
func triggerTryOn(for product: Product) {
GlanceChatSDK.shared.setPageContext("PDP", metadata: [
"page_identifier": product.id,
"product_id": product.variantId,
"product_name": product.name,
"product_image": product.imageUrl,
"product_price": product.price,
"current_url": "\(GlanceConfig.shopifyBaseUrl)/products/\(product.handle)",
"tenant_id": GlanceConfig.tenantId,
"action": "try_on",
"from_widget": "true"
])
}
Step 6: Session Management and Cleanup¶
// Handle session expiry (401 errors)
GlanceChatSDK.shared.setSessionExpiredCallback {
print("Session expired")
}
// Programmatic control
GlanceChatSDK.shared.closeChat()
GlanceChatSDK.shared.clearPageContext()
// Clean up when done (e.g., user logs out)
GlanceChatSDK.shared.destroy()