---
title: "iOS SDK"
description: "Install SeatLayer iOS 0.3.4 and use the complete SwiftUI/UIKit picker, branded components, a custom native layout, or the preserved raw SeatLayerView."
---

> Documentation Index
> Fetch the complete documentation index at: https://docs.seatlayer.io/llms.txt
> Use this file to discover all available pages before exploring further.

# iOS SDK

SeatLayer iOS `0.3.4` ships a complete native buyer picker for SwiftUI and
UIKit. Native components own the buyer journey, and the same package preserves
the raw `SeatLayerView` for applications that own every surrounding control.

> **iOS 0.3.4 Swift package**
>
> Pin the `v0.3.4` tag. It supports iOS 15+ and Swift 5.9+.
> `SeatLayerPicker`,
> `SeatLayerPickerViewController`, the customization layers, and the scoped
> SwiftUI/UIKit composition APIs are all part of the tagged release.

## Install with Swift Package Manager

In Xcode, choose **File → Add Package Dependencies** and enter:

```text
https://github.com/seatlayer/seatlayer-ios.git
```

Select exact version `0.3.4`, or declare it in a manifest:

```swift title="Package.swift"
dependencies: [
    .package(
        url: "https://github.com/seatlayer/seatlayer-ios.git",
        exact: "0.3.4"
    )
]
```

Add the `SeatLayer` product to the app target, then `import SeatLayer`.

## SwiftUI quick start

```swift title="TicketPicker.swift"
import SeatLayer
import SwiftUI

struct TicketPicker: View {
    let event: String

    var body: some View {
        SeatLayerPicker(
            configuration: SeatLayerConfiguration(
                event: event,
                publicKey: "<YOUR_PUBLIC_KEY>",
                maxSelection: 8,
                locale: "en",
                currency: "USD"
            ),
            onCheckout: { handoff in
                try await checkoutBackend.begin(holdId: handoff.holdId)
            }
        )
    }
}
```

The ready picker covers loading, live inventory, prices and accessibility,
venue/floor/section navigation, confirmation and ticket tiers, GA/table
quantities, cart and hold state, expiry recovery, 2D/3D and panorama chrome,
and one typed checkout handoff.

## UIKit quick start

UIKit hosts the same component tree:

```swift title="TicketPickerViewController.swift"
let picker = SeatLayerPickerViewController(
    configuration: SeatLayerConfiguration(
        event: "<YOUR_EVENT_KEY>",
        publicKey: "<YOUR_PUBLIC_KEY>",
        currency: "USD"
    ),
    onCheckout: { handoff in
        try await checkoutBackend.begin(holdId: handoff.holdId)
    },
    onClose: {
        navigationController?.popViewController(animated: true)
    }
)
```

Call `picker.handleBack()` before popping the host route. It consumes the
picker's prompt → cart → confirmation → section → venue ladder first.
`updateAppearance(theme:themeMode:strings:styles:)` changes presentation in
place without rebuilding the picker or losing camera, selection, or hold state.

## Public and private inventory

The examples use a publishable key for Public inventory. For login-gated,
presale, partner, channel, or other private inventory, omit `publicKey` and
provide renewable buyer access:

```swift
var configuration = SeatLayerConfiguration(
    event: "ev_private",
    currency: "USD"
)

configuration.buyerAccessTokenProvider = { context in
    try await buyerBackend.mintSeatLayerAccess(reason: context.reason)
}
```

Mint the native buyer-access session on your backend through
[buyer access sessions](/server-api/buyer-access-sessions), return only its
short-lived token to the provider, and treat SDK access details as opaque.
Tokens stay in memory and never belong in the binary, URL, logs, analytics, or
persistent state.

## Choose an integration level

| Path | API | Your application owns |
| --- | --- | --- |
| Ready SwiftUI | `SeatLayerPicker` | Configuration, callbacks, containing route |
| Ready UIKit | `SeatLayerPickerViewController` | Navigation container and dismissal |
| Branded picker | Theme, strings, options, styles, builders | Brand and selected complete parts |
| Custom SwiftUI | `SeatLayerPickerScope` + public views | Entire SwiftUI hierarchy |
| Custom UIKit | `SeatLayerPickerMapView` or `SeatLayerPickerMapViewController` + controller | Entire UIKit hierarchy |
| Raw map | `SeatLayerView` | Every buyer surface and hold transition |

The native-picker paths retain one controller, one presentation model, ordered
inventory actions, supported-feature checks, lifecycle recovery, and the same
secure checkout handoff.

[Explore customization and the component catalogue](/buyer-sdk/ios/native-picker).

## Checkout and hold ownership

The app selects and temporarily holds inventory. Your trusted backend inspects
and books after payment or order validation.

1. `onCheckout` receives one `SeatLayerPickerCheckoutHandoff`.
2. Send only its opaque `holdId` and normal order context to the backend.
3. Inspect the hold and calculate the price from trusted server data.
4. Charge through your existing payment provider.
5. Reuse the same `bookingRef` for safe retries.

Ordinary picker state deliberately omits `holdId`. Before a successful
handoff the picker owns the hold, so a confirmed close may release it. After
your callback accepts the handoff, the host owns booking, rejection/release, or
expiry. If the callback throws, the SDK rejects only that exact handoff and
keeps the buyer in a recoverable picker state.

Read [holds and secure checkout](/buyer-sdk/holds-and-checkout) before wiring
payment.

## Application and SDK ownership

| Native SwiftUI/UIKit owns | SeatLayer SDK owns |
| --- | --- |
| Header, filters, floor/section navigation, confirmation, tiers/quantities, cart, hold state, checkout, loading/errors, Test Mode, required attribution, Back and adaptive presentation | Seats, labels, geometry, hit testing, pan/pinch, venue camera, authored 3D, and panorama pixels |
| Dynamic Type, VoiceOver, safe areas, scene lifecycle, native haptics and presentation | Authoritative inventory state and supported map capabilities |

Changing native presentation never creates a second map. The buyer keeps the
same camera, selection, and hold state.

## Lifecycle and recovery

The ready SwiftUI picker observes `scenePhase`; the UIKit host observes
application notifications. On foreground they report lifecycle state, consume
lost-inventory or hold-lapse truth, optionally refresh availability, and
synchronize before accepting another buyer action.

`SeatLayerPickerOptions(refreshOnResume: false)` skips only the optional
explicit refresh. Authoritative lifecycle state is still reconciled.
`announceHoldLapse: false` keeps reconciliation but leaves the visible message
to the host. A custom host calls `controller.lifecycle`,
`controller.refreshAvailability()`, and `controller.synchronize()`.

`SeatLayerPicker.prewarm()` is an optional API that prepares the picker before
navigation:

```swift
Task { try await SeatLayerPicker.prewarm() }
```

Prewarm contains no event, public key, buyer token, or hold and does not start a
buyer session.

## Layout requirement

Give the picker or map a definite height or a full-screen parent. Do not place
the venue map in a SwiftUI `ScrollView`, `List`, or UIKit `UIScrollView`; the
canvas owns pan, pinch, 3D, and panorama gestures.

## Test Mode and attribution

Test Mode follows authoritative event state and must remain visible. The
three-bar `Powered by SeatLayer` mark appears at the safe bottom-right edge
when required by the SeatLayer account configuration. Client-side options,
styles, and builders cannot override that setting.

## Run the tagged example

```bash
git clone --branch v0.3.4 --depth 1 https://github.com/seatlayer/seatlayer-ios.git
cd seatlayer-ios
xcodebuild -scheme SeatLayer -destination 'generic/platform=iOS'
xcodebuild -project Example/SeatLayerDemo.xcodeproj \
  -scheme SeatLayerDemo -destination 'generic/platform=iOS Simulator'
```

The UIKit example exercises the complete picker. Validate SwiftUI/UIKit,
Dynamic Type, VoiceOver, rotation, foreground recovery, interactive dismissal,
tiers, 3D/panorama, checkout rejection, Test Mode, and attribution on supported
physical devices before rollout.

## Product scope

iOS `0.3.4` accepts one published Event per picker. Native Performance Group
and Season configuration is not part of this release.

## Next steps

- [SwiftUI/UIKit customization and custom layouts](/buyer-sdk/ios/native-picker)
- [Raw-map API](/buyer-sdk/ios/raw-map)
- [Compare all four native SDKs](/buyer-sdk/mobile)
- [Secure checkout](/buyer-sdk/holds-and-checkout)
- [Troubleshooting matrix](/buyer-sdk/mobile#troubleshooting)
- [`v0.3.4` source](https://github.com/seatlayer/seatlayer-ios/tree/v0.3.4)
- [Tagged native picker guide](https://github.com/seatlayer/seatlayer-ios/blob/v0.3.4/Docs/native-picker.md)
- [Tagged example](https://github.com/seatlayer/seatlayer-ios/tree/v0.3.4/Example)
- [Tagged changelog](https://github.com/seatlayer/seatlayer-ios/blob/v0.3.4/CHANGELOG.md)

Source: https://docs.seatlayer.io/buyer-sdk/ios/index.mdx
