> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.getunleash.io/sdks/ios/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.getunleash.io/_mcp/server. # iOS SDK > Set up the Unleash iOS SDK to evaluate feature flags in Swift apps with context, variants, bootstrap, events, and headers. The Unleash iOS SDK is a Swift client that lets you evaluate feature flags in iOS and macOS applications. It connects to Unleash or [Unleash Edge](/unleash-edge) to fetch evaluated flags for a given [Unleash context](/concepts/unleash-context). You can use this SDK with [Unleash Enterprise](https://www.getunleash.io/pricing) or [Unleash Open Source](https://github.com/Unleash/unleash). For an overview of how Unleash SDKs work, including offline behavior, feature compatibility across SDKs, and default refresh and metrics intervals, refer to the [SDK overview](/sdks). ## Requirements * MacOS: 12.15 * iOS: 12 ## Installation #### Swift Package Manager In your `Package.swift` dependencies: ```swift .package(url: "https://github.com/Unleash/unleash-ios-sdk.git", from: "0.0.0") ``` #### Xcode **File > Add Package Dependencies**, enter `https://github.com/Unleash/unleash-ios-sdk`. ## Usage To get started, import the SDK and initialize the Unleash client: ### iOS >= 13 ```swift import SwiftUI import UnleashProxyClientSwift // Setup Unleash in the context where it makes most sense var unleash = UnleashProxyClientSwift.UnleashClient( unleashUrl: "https:///api/frontend", clientKey: "", refreshInterval: 15, appName: "test", context: ["userId": "c3b155b0-5ebe-4a20-8386-e0cab160051e"] ) unleash.start() ``` ### iOS >= 12 ```swift import SwiftUI import UnleashProxyClientSwift // Setup Unleash in the context where it makes most sense var unleash = UnleashProxyClientSwift.UnleashClientBase( unleashUrl: "https:///api/frontend", clientKey: "", refreshInterval: 15, appName: "test", context: ["userId": "c3b155b0-5ebe-4a20-8386-e0cab160051e"] ) unleash.start() ``` In the example above we import the UnleashProxyClientSwift and instantiate the client. You need to provide the following parameters: * `unleashUrl`: The full URL to either the [Unleash Frontend API](/api#frontend-api) or an [Unleash Edge instance](/unleash-edge) \[String] * `clientKey`: A [frontend API token](/concepts/api-tokens-and-client-keys#frontend-tokens) for authenticating with the Frontend API or Unleash Edge \[String] * `refreshInterval`: The polling interval in seconds, set to `0` to only poll once and disable a periodic polling \[Int] * `appName`: The application name identifier \[String] * `context`: Initial Unleash context fields (like `userId`, `sessionId`, etc.), excluding `appName` and `environment` which are configured separately. \[String: String] Calling `unleash.start()` makes the initial request to retrieve the feature flag configuration and starts the background polling interval (if `refreshInterval > 0`). > **Note** > > Until the client fetches the initial configuration (signaled by the `ready` event), checking a feature flag might return the default value (often `false`). To ensure the configuration is loaded before checking flags, subscribe to the ready event. See the [Events](#events) section for details. Once the configuration is loaded, you can check if a feature flag is enabled: ```swift if unleash.isEnabled(name: "ios") { // do something } else { // do something else } ``` You can also set up [variants](/concepts/feature-flag-variants): ```swift var variant = unleash.getVariant(name: "ios") if variant.enabled { // do something } else { // do something else } ``` ### Configuration options The Unleash SDK accepts the following initialization options: | option | required | default | description | | | --------------------- | -------- | ------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | - | | unleashUrl | yes | n/a | The Unleash Edge URL to connect to. | | | clientKey | yes | n/a | The frontend token to use for authenticating with the Frontend API or Unleash Edge. | | | appName | no | unleash-swift-client | The name of the application using this SDK. Sent with metrics to Unleash Edge and included in the Unleash context. | | | environment | no | default | The name of the environment. Sent with metrics to Unleash Edge and included in the Unleash context. | | | refreshInterval | no | 15 | How often (in seconds) the SDK checks for updated flag configurations. Set to 0 to disable polling after initial fetch. | | | metricsInterval | no | 30 | How often (in seconds) the SDK sends usage metrics back to Unleash Edge. | | | disableMetrics | no | false | Set this to `true` to disable usage metrics. | | | context | no | \[:] | The initial context parameters excluding `appName` and `environment` which are specified as top level fields. | | | poller | no | nil | A custom poller instance. If provided, the client ignores its own `refreshInterval`, `customHeaders`, `customHeadersProvider`, and `bootstrap` options. Use for advanced control or mocking. | | | pollerSession | no | `URLSession.shared` | Session object used for performing HTTP requests. You can provide a custom `PollerSession` for custom `URLSession` configuration or `URLRequest` interception. | | | customHeaders | no | `[:]` | Additional headers to use when making HTTP requests to Unleash Edge. In case of name collisions with the default headers, the `customHeaders` value will be used. | | | customHeadersProvider | no | `DefaultCustomHeadersProvider` | Custom header provider for additional headers. In case of name collisions with the `customHeaders`, the `customHeadersProvider` value will be used. | | | bootstrap | no | empty list of feature flags | Initial flag configurations provided to the Unleash client SDK. Can be a list of `Toggle` objects or the path to a JSON file matching the [Frontend API response format](/api/get-frontend-features#response). Available immediately on init, before the first fetch. | | ### Bootstrap You can bootstrap the SDK with flag configuration to evaluate flags before connecting to Unleash. Provide the bootstrap as a list of `Toggle` objects or from a JSON file matching the [Frontend API](/api#frontend-api) response format. #### Inline data ```swift let bootstrapList = Bootstrap .toggles( [ Toggle(name: "Foo", enabled: true), Toggle( name: "Bar", enabled: false, variant: Variant( name: "bar", enabled: true, featureEnabled: true, payload: Payload(type: "string", value: "baz") ) ) ] ) ``` #### JSON file Create a JSON file matching the Frontend API response format: ```json { "toggles": [ { "name": "no-variant", "enabled": true }, { "name": "enabled-with-variant-enabled-and-payload", "enabled": true, "variant": { "name": "bar", "enabled": true, "feature_enabled": true, "payload": { "type": "string", "value": "baz" } } } ] } ``` Then load it in your app: ```swift guard let filePath = Bundle.main.path(forResource: "FeatureResponseFile", ofType: "json") else { // Handle missing file } let bootstrapFile = Bootstrap.jsonFile(path: filePath) ``` You can inject the bootstrap at initialization or when calling `start`: ```swift import SwiftUI import UnleashProxyClientSwift let unleash = UnleashClient( unleashUrl: "https:///api/frontend", clientKey: "", bootstrap: .toggles([Toggle(name: "Foo", enabled: true)]) ) // Flags are available immediately let isFooEnabled = unleash.isEnabled(name: "Foo") // true // Or provide when starting unleash.start(bootstrap: .jsonFile("path/to/json/file")) // Or using async-await (iOS 13+) await unleash.start(bootstrap: .jsonFile("path/to/json/file")) ``` > **Note** > > * If you initialize the client with a `Poller`, inject the bootstrap directly into the poller. Any bootstrap data injected into the client options will be ignored when a custom poller is also provided. > * Bootstrapped flag configurations are replaced entirely after the first successful fetch. > * If bootstrap flags are provided when calling start, the first fetch occurs after the configured `refreshInterval` (default 15 seconds). > * Calling `updateContext(...)` before the first fetch removes any bootstrapped flags. ### Update context To update the context, use the following method: ```swift var context: [String: String] = [:] context["userId"] = "c3b155b0-5ebe-4a20-8386-e0cab160051e" unleash.updateContext(context: context) ``` This will stop and start the polling interval in order to renew polling with new context values. You can use any of the [predefined fields](/concepts/unleash-context#structure). If you need to support [custom properties](/concepts/unleash-context#the-properties-field) pass them as the second argument: ```swift var context: [String: String] = [:] context["userId"] = "c3b155b0-5ebe-4a20-8386-e0cab160051e" var properties: [String: String] = [:] properties["customKey"] = "customValue"; unleash.updateContext(context: context, properties: properties) ``` ### Custom PollerSession If you want to use a custom `URLSession` or intercept `URLRequest` you can provide a custom `PollerSession` to the client. ```swift class CustomPollerSession: PollerSession { func perform(_ request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) { // Custom URLSession configuration let configuration = URLSessionConfiguration.default configuration.timeoutIntervalForRequest = 30 // Modify URLRequest if needed var modifiedRequest = request modifiedRequest.setValue("foo", forHTTPHeaderField: "bar") let session = URLSession(configuration: configuration) session.dataTask(with: modifiedRequest, completionHandler: completionHandler).resume() } } // Use when initializing Unleash client var unleash = UnleashProxyClientSwift.UnleashClient( unleashUrl: unleashUrl, clientKey: clientKey, pollerSession: CustomPollerSession() ) ``` ### Custom HTTP headers If you want the client to send custom HTTP headers with all requests to the Unleash API you can define that by setting them via the `UnleashClientBase`. Custom and dynamic custom headers does not apply to sensitive headers. * `Content-Type` * `If-None-Match` * anything starting with `unleash-` (`unleash-appname`, `unleash-connection-id`, `unleash-sdk`, ...) ```swift var unleash = UnleashProxyClientSwift.UnleashClientBase( unleashUrl: unleashUrl, clientKey: clientKey, refreshInterval: 15, appName: "test", context: ["userId": "c3b155b0-5ebe-4a20-8386-e0cab160051e"], customHeaders: ["X-Custom-Header": "CustomValue", "X-Another-Header": "AnotherValue"] ) ``` ### Dynamic custom HTTP headers If you need custom HTTP headers that change during the lifetime of the client, a provider can be defined via the `UnleashClientBase`. ```swift public class MyCustomHeadersProvider: CustomHeadersProvider { public init() {} public func getCustomHeaders() -> [String: String] { let token = "Acquire or refresh token"; return ["Authorization": token] } } ``` ```swift let myCustomHeadersProvider: CustomHeadersProvider = MyCustomHeadersProvider() var unleash = UnleashProxyClientSwift.UnleashClientBase( unleashUrl: unleashUrl, clientKey: clientKey, refreshInterval: 15, appName: "test", context: ["userId": "c3b155b0-5ebe-4a20-8386-e0cab160051e"], customHeadersProvider: myCustomHeadersProvider ) ``` ## Events The client emits events that you can subscribe to using the `subscribe(name:callback:)` method or the `UnleashEvent` enum. The client emits the following events: * `ready` (`UnleashEvent.ready`): Emitted once the client has successfully fetched and cached the initial feature flag configurations. * `update` (`UnleashEvent.update`): Emitted when a subsequent fetch results in a change to the feature flag configurations. * `sent` (`UnleashEvent.sent`): Emitted when usage metrics have been successfully sent to the server. * `error` (`UnleashEvent.error`): Emitted if an error occurs when trying to send metrics. * `impression` (`UnleashEvent.impression`): Emitted when `isEnabled(name:)` or `getVariant(name:)` is called for a flag with [impression data](/concepts/impression-data) enabled. Subscribe using the `subscribe(name:callback:)` method or the `UnleashEvent` enum: ```swift func handleReady() { // do this when unleash is ready } unleash.subscribe(name: "ready", callback: handleReady) // Or using the enum: unleash.subscribe(.ready, callback: handleReady) ``` ### Impression events To track feature exposures, [enable impression data](/concepts/impression-data#enabling-impression-data) for the flags you want to track, then subscribe to the `impression` event: ```swift import UnleashProxyClientSwift func handleImpressionEvent(_ payload: Any?) { guard let impressionEvent = payload as? UnleashProxyClientSwift.ImpressionEvent else { return } // Send impression data to your analytics tool } unleash.subscribe(.impression, callback: handleImpressionEvent) ``` ## Migrating to v2 In v2, the `StorageProvider` interface [was changed](https://github.com/Unleash/unleash-ios-sdk/pull/113) to accept all flags at once: ```swift func set(values: [String: Toggle]) ``` If you have a custom `StorageProvider` implementation, you'll need to update it. > Set up the Unleash iOS SDK to evaluate feature flags in Swift apps with context, variants, bootstrap, events, and headers.