Docs/Getting Started/iOS Quick Start

iOS Quick Start

From zero to a YES verdict on an iOS device in ten minutes.

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: "2.0.0")
]

Pin 2.0.0 or later. 2.0 is a major release. If you are on 1.x, read Migrating from 1.x first.

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" >= 2.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 its required-reason API use. Xcode folds this into your app's privacy report at build time.


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. Ask your first question

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 will always be INDETERMINATE / NO_FIX with the message running on simulator — location proofs are unavailable in this environment. This is by design. Run on hardware to see the full flow.
  • On a real device, indoors, the first proof may take longer or come back at MEDIUM confidence. See Concepts: Verdicts.

8. From here