Skip to main content
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

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

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:
// 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

PrimerCheckoutPresenter.dismiss(animated: true) {
  print("Checkout dismissed")
}

Check availability

// 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)

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

SwiftUI navigation

SwiftUI presentation patterns

Common objects

PrimerCheckoutPresenter API