Skip to main content

Flyreel iOS SDK

Swift 5.7 Supported iOS 13

Installation

Cocoapods

Add pod Flyreel to your Podfile:

pod 'Flyreel'

Swift Package Manager

  1. Follow the Apple guide to add the package dependency to your app.
  2. Enter the package URL: https://github.com/Flyreel/flyreel-sdk-ios

Initialization

To use the Flyreel SDK, you must provide a configuration with the following parameters:

-settingsVersion: Identifier of your remote SDK settings. -organizationId: Identifier of your organization.

let configuration = FlyreelConfiguration(
settingsVersion: "1",
organizationId: "7d3899f1421a7650241516475"
)

FlyreelSDK.shared.set(configuration: configuration)

Setting up the configuration is mandatory. Attempting to open the SDK flow without it will result in a fatal error.

Permissions

Since the SDK actively uses some functionalities of the iOS system you need to provide a few permission settings

<key>NSCameraUsageDescription</key>
<string>We need access to the camera.</string>
<key>NSMicrophoneUsageDescription</key>
<string>We need access to the microphone.</string>
<key>NSLocationWhenInUseUsageDescription</key>
<string>We need access to your location data</string>

How to present UI

SwiftUI

For SwiftUI, use our custom modifier similar to a regular sheet presentation:

@State private var isFlowPresented = false

var body: some View {
Button("Open Flyreel flow") {
isFlowPresented = true
}
.presentFlyreel(isPresented: $isFlowPresented)
}

UIKIt

For UIKit, present the Flyreel flow on any UIViewController:

FlyreelSDK.shared.presentFlyreel(on: self)

Deep Linking

If you're launching the Flyreel flow from a deep link, push notification, or a custom solution where user details can be provided automatically, use:

// SwiftUI
func presentFlyreel(
isPresented: Binding<Bool>,
zipCode: String,
accessCode: String,
shouldSkipLoginPage: Bool = true
)

func presentFlyreel(
isPresented: Binding<Bool>,
deepLinkURL: URL,
shouldSkipLoginPage: Bool = true
)

// UIKit
func presentFlyreel(
on rootViewController: UIViewController,
zipCode: String,
accessCode: String,
shouldSkipLoginPage: Bool = true,
animated: Bool = true
)

func presentFlyreel(
on rootViewController: UIViewController,
deepLinkURL: URL,
shouldSkipLoginPage: Bool = true,
animated: Bool = true
)

Debug Logs

Enable debug logging for troubleshooting purposes:

FlyreelSDK.shared.enableLogs()

Flyreel Status Check

Manually check Flyreel status:

// Makes a network request to retrieve the status of Flyreel for the specified zip code and access code
func fetchFlyreelStatus(
zipCode: String,
accessCode: String,
completion: @escaping (Result<FlyreelStatus, FlyreelError>) -> Void
)

// Async version
func fetchFlyreelStatus(
zipCode: String, accessCode: String
) async throws -> FlyreelStatus

Events

The Flyreel SDK emits events throughout the conversation flow that you can observe and integrate with your analytics platform (e.g., Firebase Analytics, Mixpanel, Segment). This allows you to track user behavior, measure engagement, and gain insights into how users interact with the Flyreel flow.

FlyreelEvent Data Structure

struct FlyreelEvent {
let timestamp: Date // Date of the event
let trigger: Trigger // The specific event type and associated data (enum)
let user: FlyreelAnalyticUser? // User and session information (optional)
var name: String // String representation of the event name (e.g. "user_logged_in", "sdk_closed")
}

Event Trigger Enum

The trigger property defines the event type and holds the relevant context (such as active time, location, or message details) as associated values.

enum Trigger {
// User successfully authenticated
case userLoggedIn(status: String, deviceData: FlyreelDeviceData, location: FlyreelCoordinate?, isDeeplink: Bool)

// Flyreel bot asks a question
case questionAsked(activeTime: TimeInterval, message: EventMessageDetails)

// User responds to a question
case questionAnswered(activeTime: TimeInterval, location: FlyreelCoordinate?, message: EventMessageDetails)

// User completes the Flyreel flow successfully
case flyreelCompleted(activeTime: TimeInterval)

// User exits the SDK (via close button or completion)
case sdkClosed(activeTime: TimeInterval)
}

Supporting Structures

struct FlyreelAnalyticUser {
let flyreelID: String // Unique Flyreel ID
let name: String // User's name
let email: String // User's email
let botId: String // Bot configuration ID
let botName: String // Bot name
let organizationId: String // Organization ID
let status: String // User's status
}

struct EventMessageDetails {
let message: String // Question or answer text
let messageType: String // e.g., "text", "image"
let moduleKey: String // e.g., "intro", "wrap_up"
let messageKey: String // Unique message ID
let phase: String // e.g., "beginning"
}

struct FlyreelDeviceData {
let phoneModel: String? // Device model
let appVersion: String? // Version of App that SDK is embeded in
let appName: String? // Name of App that SDK is embeded in
}

struct FlyreelCoordinate {
let lat: Double // Latitude
let lng: Double // Longitude
}

Event Types

The SDK emits the following event types (identified by event.trigger):

Event NameDescriptionWhen It's Triggered
.userLoggedInUser successfully authenticatedAfter user enters valid credentials
.questionAskedFlyreel bot asks a questionWhen a new question is presented to the user
.questionAnsweredUser responds to a questionAfter user submits an answer
.flyreelCompletedUser completes the Flyreel flowWhen user finishes & successfully submits a Flyreel
.sdkClosedUser exits the SDKWhen user closes the SDK

Observing Events

Subscribe to the event stream to receive all Flyreel events in real-time. Because trigger is an enum, you should use a switch statement to extract the specific data you need.

FlyreelSDK.shared.observeFlyreelEvents { event in
// Extract data based on the event type
switch event.trigger {
case .flyreelCompleted(let activeTime):
YourAnalyticsProvider.trackEvent("flyreel_completed", properties: [
"user_id": event.user?.flyreelID,
"active_time": activeTime
])
case .sdkClosed(let activeTime):
print("SDK Closed after \(activeTime) seconds")
default:
break
}
}

Usage Example

Here is a comprehensive example of how to log these events in your application:

class AnalyticsManager {

init() {
// Subscribe to Flyreel events
FlyreelSDK.shared.observeFlyreelEvents { [weak self] event in
self?.handleFlyreelEvent(event)
}
}

private func handleFlyreelEvent(_ event: FlyreelEvent) {
let baseParams: [String: Any] = [
"user_id": event.user?.flyreelID,
"bot_name": event.user?.botName,
"timestamp": event.timestamp
]

switch event.trigger {
case .userLoggedIn(let status, let device, _, let isDeeplink):
print("Analytics: User Logged In (Method: \(isDeeplink ? "DeepLink" : "Manual"))")

case .questionAsked(_, let details):
print("Analytics: Question Asked - \(details.message) (Phase: \(details.phase))")

case .questionAnswered(let time, _, let details):
print("Analytics: Answered in \(time)s - \(details.message)")

case .flyreelCompleted(let time):
print("Analytics: Flow Completed! Total Active Time: \(time)s")

case .sdkClosed(let time):
print("Analytics: SDK Closed. Total Session Time: \(time)s")
}
}
}

Sandbox

Verify your implementation in the sandbox mode. Switch the environment with the configuration:

let configuration = FlyreelConfiguration(
settingsVersion: "1",
organizationId: "7d3899f1421a7650241516475",
environment: .sandbox
)

FlyreelSDK.shared.set(configuration: configuration)

Firewall whitelisting

Here is a list of Flyreel's hosts in case you need to whitelist URLs.

api3.flyreel.co
sandbox.api3.flyreel.co