getSession() when the user performs a sensitive action, and POST the sealed token to your backend for verification.
Requirements
- iOS 14+ for the public binary SwiftPM package
- Swift 5.9+
- Xcode 15+
- A Foil publishable key created with the iOS client, starting with
pk_live_orpk_test_
Create a publishable key for iOS
In the Foil dashboard, open API Keys, choose New publishable key, and set Client to iOS. Foil admits native sessions only when the publishable key’s client matches the SDK’s platform. A key created with the Web or Android client is rejected, and the SDK reportsconfig.invalid_publishable_key. In the other direction, the browser SDK doesn’t accept a key created with the iOS client.
Install
Add Foil with Swift Package Manager:Foil product to your app target. In Xcode, choose
File > Add Package Dependencies…, enter
https://github.com/abxy-labs/foil-ios, choose version 1.2.2 or newer,
and add the Foil product to the target that configures the SDK.
Configure on startup
Configure once at app launch - typically from yourApp initializer - so signal collection is running by the time the first screen appears.
FoilConfiguration
Runtime integrity and anti-tamper collection is always enabled. It is part of
the baseline SDK behavior, not an integration option.
Get a session at action time
CallgetSession() from an async context right before the sensitive action - not on app launch.
SessionHandoff is a small value type:
sessionIdis stable for the life of the client.getSession()posts the native snapshot, performs a bounded best-effort behavioral flush, and returns the handoff your backend should verify.- The SDK never surfaces verdicts, scores, or visitor IDs to the device - verify on your server.
getSession() returns the same sessionId and sealedToken pair as the browser SDK, so you verify the sealedToken with your Foil server SDK and your secret key. See Server verification for the verification methods and examples in each server language.
Behavioral capture
WhenenableBehavioralSignals is true, the SDK starts zero-config UIKit capture automatically. It records the native equivalents of the browser’s behavioral events: app lifecycle, hashed screen navigation, viewport and scroll, form focus and input, selection and clipboard, and motion.
No raw form text, raw placeholders, or raw field identifiers are sent. Field identity is hashed, and geometry is rounded to the field’s window coordinates so the dashboard can show timing and replay context without collecting user-entered values.
Touch-stroke dynamics are still opt-in per screen for higher-fidelity gesture data. Call observeTouches(on:) once the view is mounted.
UIViewRepresentable wrapper to expose the underlying UIView.
WebView correlation
If your app hosts Foil-protected web content in aWKWebView, attach it so the web SDK reuses the native session.
window.__FOIL_NATIVE__, which the browser SDK picks up when loaded inside the WebView.
Native identity and attestation
Native visitor continuity is resolved server-side from the SDK’s encrypted observations.install_id tracks the app install, device_id tracks the device continuity layer, and native visitor_id represents the same device within your organization. None of those identifiers are exposed to the app.
Apple App Attest is optional and positive-only by default. When App Attest is supported, Foil can use SDK-managed App Attest keys to strengthen native identity. When it is unsupported, unavailable, unconfigured, or fails verification, Foil falls back to the other native continuity signals unless your organization explicitly enables strict attestation.
To verify App Attest in production, add your iOS app identity on the Native Attestation card of the dashboard’s Settings page. Baseline native continuity still works without this setup, but App Attest doesn’t upgrade identity confidence until the app identity is configured.
Add your app identity
Only organization owners and admins can change attestation settings. On the Native Attestation card, under Add app identity:- Set Platform to iOS.
- Enter your Apple App ID, which is your Apple Team ID and your bundle ID joined by a period, such as
TEAMID.com.example.app. - Select Add identity.
Diagnostics
dispatchHealth() returns per-channel counters of successful and failed batch posts since the last configure(_:). Use it to confirm signals are reaching the server when you don’t have server-side visibility - for example, to spot a TLS-pinning, proxy, or quota issue from the client.
consecutiveFailures rising without a matching rise in consecutiveSuccesses typically means a sustained network outage or a server-side rejection that retries can’t recover from. Counters reset on configure(_:), destroy(), or resetLocalState().
API reference
Error handling
FoilError is a Sendable struct carrying a stable code, a human-readable message, an optional underlying error, and a retryable flag.
The
code values are stable. Category prefixes (config.*, transport.*) are safe to branch on with a wildcard - new codes within a category keep the same retry semantics.
Fallback policy
If Foil fails, log the error and continue without a handoff, then decide on your server how to treat a request that has no Foil signal. For low-risk actions you can fail open. For sensitive actions such as signup, payment, or account recovery, fail closed or step up verification.Best practices
- Configure once at launch so signals are collecting before any screen opens.
- Call
getSession()late - right before the sensitive action, from an async context. - Set a fallback policy per action - when the SDK can’t produce a handoff, fail open on low-risk actions and fail closed on sensitive ones.
- Reuse the shared client -
FoilClient.sharedis a process-wide singleton.
What’s next
Server verification
Verify the sealed token on your backend
Browser SDK
Equivalent guide for the web surface
Android SDK
Native Android integration
Going to production
Rollout checklist and monitoring