You are viewing v3.0.0 of the docs. The latest is v3.1.2.
Docs/Mobile SDK/Getting Started

iOS Quick Start

Install the SDK, start it, and get a first verdict on an iOS device.

Note

Work through Prerequisites first. You will need a registered app (or a sandbox token for local development) and the two Info.plist keys.


1. Add the SDK

In Xcode: File → Add Packages… and enter:

https://github.com/octetproof/octet-sdk-ios

Pin to a version rather than tracking main. Or in Package.swift:

dependencies: [
    .package(url: "https://github.com/octetproof/octet-sdk-ios", exact: "3.0.0")
]

Pin 3.0.0 or later. 3.0 is a major release. If you are on 2.x, read Upgrading from 2.x first. If you are on 1.x, read Migrating from 1.x as well.

Then import:

import OctetSDK

Carthage

Carthage does not propagate SwiftPM transitive dependencies, but OctetSDK declares none. Add one line to your Cartfile:

binary "https://raw.githubusercontent.com/octetproof/octet-sdk-ios/main/OctetSDK.json" >= 3.0.0

The module name is OctetSDK.


2. Add Info.plist keys

<key>NSLocationWhenInUseUsageDescription</key>
<string>This app uses your location to verify and prove your location
to services that request it.</string>

<key>NSMotionUsageDescription</key>
<string>This app uses motion data to detect when you're stationary or
moving, which improves the confidence of location proofs.</string>

Without these, the app crashes on first launch.

The xcframework also bundles a privacy manifest (PrivacyInfo.xcprivacy) declaring the data types it handles (location, device identifier, aggregate usage counters and the daily usage record) and its required-reason API use. Xcode folds this into your app's privacy report at build time. See Data collection.


3. Request location permission

The SDK refuses to start until the user grants location authorization. Request it before calling Octet.start(...):

import CoreLocation

let locationManager = CLLocationManager()
locationManager.requestWhenInUseAuthorization()

Wait for the authorization status callback (locationManagerDidChangeAuthorization) before continuing.


4. Start the SDK

Octet.start(...) bootstraps the license by attesting the app with Apple App Attest, then brings up the proof pipeline. On a real device with the App Attest capability enabled (see Prerequisites), no key or token is needed.

import OctetSDK

let config = OctetConfig(licenseKey: "")   // required by the type, ignored by start
let sdk = try await Octet.start(config: config)

On a simulator or a locally built debug build, there is no hardware attestation. Mint a sandbox bypass token (see Prerequisites) and pass it:

let config = OctetConfig(licenseKey: "", sandboxBypassToken: "octet_sbx_…")

Octet.start(...) is async throws. Any license or bootstrap problem throws a typed LicenseError. See License Types for the case list, and Attested bootstrap for the handshake.


5. Query a region

let verdict = await sdk.loc.isWithin(
    region: .country(isoCode: "US"),
    atTime: Date()
)

switch verdict.result {
case .yes:
    print("YES, proof attached: \(verdict.proof != nil)")
case .no:
    print("NO, provable negative")
case .indeterminate:
    print("INDETERMINATE, reason: \(verdict.reason)")
}

The predicate returns an OctetVerdict. Never treat INDETERMINATE as NO.


6. Close when done

When your proof flow ends, release the session and stop background work:

await sdk.close()

See Session Lifecycle for why this matters.


7. What to expect

  • On a real device, outdoors, with cellular and GPS available, isWithin(.country(isoCode: ...)) typically returns YES with an attached proof.
  • On the iOS Simulator the verdict is always INDETERMINATE / NO_FIX with the message running on simulator — location proofs are unavailable in this environment. Run on hardware to see the full flow.
  • On a real device, indoors, the first proof may take longer. A country query can often answer. See Concepts: Verdicts.

8. Next steps

TermsPrivacy© 2026 Understone, Inc. d/b/a Octet