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

# UIKit integration

> Use Primer Checkout in UIKit apps with PrimerCheckoutPresenter

For UIKit-based apps, use `PrimerCheckoutPresenter` to present the checkout as a modal sheet. It wraps `PrimerCheckout` in a `UIHostingController` and handles presentation lifecycle.

## Present checkout

```swift theme={"dark"}
class CheckoutViewController: UIViewController, PrimerCheckoutPresenterDelegate {

  func showCheckout() {
    PrimerCheckoutPresenter.shared.delegate = self

    PrimerCheckoutPresenter.presentCheckout(
      clientToken: clientToken,
      from: self,
      primerSettings: PrimerSettings(paymentHandling: .auto),
      primerTheme: PrimerCheckoutTheme()
    )
  }

  // MARK: - PrimerCheckoutPresenterDelegate

  func primerCheckoutPresenterDidCompleteWithSuccess(_ result: PaymentResult) {
    // Navigate to confirmation
    let confirmationVC = ConfirmationViewController(result: result)
    navigationController?.pushViewController(confirmationVC, animated: true)
  }

  func primerCheckoutPresenterDidFailWithError(_ error: PrimerError) {
    print("Payment failed: \(error.errorId)")
  }

  func primerCheckoutPresenterDidDismiss() {
    print("Checkout dismissed")
  }
}
```

## With scope customization

```swift theme={"dark"}
PrimerCheckoutPresenter.shared.delegate = self

PrimerCheckoutPresenter.presentCheckout(
  clientToken: clientToken,
  from: self,
  primerSettings: PrimerSettings(),
  primerTheme: PrimerCheckoutTheme(
    colors: ColorOverrides(primerColorBrand: .systemBlue)
  ),
  scope: { checkoutScope in
    checkoutScope.splashScreen = {
      AnyView(
        VStack {
          ProgressView()
          Text("Loading...")
        }
      )
    }
  }
)
```

## Convenience methods

For quick integration without full customization:

```swift theme={"dark"}
// Minimal — uses default settings and theme
PrimerCheckoutPresenter.presentCheckout(clientToken: clientToken)

// With view controller
PrimerCheckoutPresenter.presentCheckout(clientToken: clientToken, from: self)

// With settings
PrimerCheckoutPresenter.presentCheckout(
  clientToken: clientToken,
  from: self,
  primerSettings: PrimerSettings(paymentHandling: .manual)
)
```

## Dismiss programmatically

```swift theme={"dark"}
PrimerCheckoutPresenter.dismiss(animated: true) {
  print("Checkout dismissed")
}
```

## Check availability

```swift theme={"dark"}
// Check if checkout can be presented
if PrimerCheckoutPresenter.isAvailable {
  PrimerCheckoutPresenter.presentCheckout(clientToken: clientToken, from: self)
}

// Check if already presenting
if PrimerCheckoutPresenter.isPresenting {
  print("Checkout is already visible")
}
```

## 3DS delegate methods (optional)

```swift theme={"dark"}
extension CheckoutViewController: PrimerCheckoutPresenterDelegate {
  func primerCheckoutPresenterWillPresent3DSChallenge(_ paymentMethodTokenData: PrimerPaymentMethodTokenData) {
    print("3DS challenge starting")
  }

  func primerCheckoutPresenterDidDismiss3DSChallenge() {
    print("3DS challenge dismissed")
  }

  func primerCheckoutPresenterDidComplete3DSChallenge(success: Bool, resumeToken: String?, error: Error?) {
    print("3DS result: \(success)")
  }
}
```

## See also

<CardGroup cols={2}>
  <Card title="SwiftUI navigation" icon="arrow-right" href="/sdk/ios-checkout/v3.0.0-beta/integration-patterns/swiftui-navigation">
    SwiftUI presentation patterns
  </Card>

  <Card title="Common objects" icon="cube" href="/sdk/ios-checkout/v3.0.0-beta/api-reference/common-objects">
    PrimerCheckoutPresenter API
  </Card>
</CardGroup>
