iOS Quick Start
From zero to a YES verdict on an iOS device in ten minutes.
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
Swift Package Manager (recommended)
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 returnsYESwith an attached proof. - On the iOS Simulator the verdict will always be
INDETERMINATE / NO_FIXwith the messagerunning 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
MEDIUMconfidence. See Concepts: Verdicts.
8. From here
- The OctetSample sample app exercises this whole flow.
- On-device Verification checks a proof with
Octet.verify, offline. - Proof Binding ties a proof to a login or a decision, and
forceFreshmints one on demand. - Verifying Proofs and the Verifier Quick Start show independent verification.
- What's new in 2.0 lists the full release.