Quick diagnosis
| Symptom | Likely Cause | Solution |
|---|---|---|
| Error screen with retry button | Invalid or expired client token | Generate a fresh clientToken from your server for each session |
| No payment methods shown | Dashboard misconfiguration or unsupported currency/country | Verify Dashboard settings and currencyCode/countryCode in client session |
| Composable views render nothing | .primerCheckoutSession modifier missing above them, or session not yet .ready | Apply .primerCheckoutSession(_:onCompletion:) around the views; they bind once the session reaches .ready |
| Session re-initializes unexpectedly | PrimerCheckoutSession recreated on view updates | Hold the session as a @StateObject, not a let or @State value |
| Theme or settings not applied | PrimerCheckoutTheme/PrimerSettings created inside view body | Define as constants outside the view body |
| Delegate callbacks never fire (UIKit) | PrimerCheckoutPresenterDelegate not set or deallocated | Set delegate on .shared before calling presentCheckout and retain the delegate |
| Apple Pay not available | Simulator, no cards in Wallet, or merchant ID mismatch | Test on a real device with cards in Wallet; verify Apple Developer & Dashboard config |
| Card form shows invalid despite filled fields | Hidden billing fields are also required | Inspect fieldErrors on the PrimerCardFormSession handed to your card-form slot |
| Payment fails after submission | Declined card, network issue, or processor error | Handle the .failure(PrimerError) terminal state and log diagnosticsId |
| Build error on iOS 14 | Minimum deployment target not met | Set deployment target to iOS 15.0+ |
Configuration and initialization
Error screen after initialization
Cause: Invalid, expired, or malformed client token. The SDK shows an error screen with a retry button — not a blank screen. Solution: Generate a freshclientToken from your server for each checkout session. Client tokens are single-use and expire.
If you see
invalid-client-token in the error, your token has expired or was already consumed. Generate a new one from your server.Payment methods not showing
Cause: Multiple possible causes:- No payment methods configured in the Primer Dashboard for the given currency/country
- The SDK only renders payment methods it supports — unsupported types are silently filtered out
- Client session missing required
currencyCodeorcountryCodefields
"Filtering out unregistered payment method: TYPE". Verify your Dashboard configuration matches the currency and country in your client session. When using the composable PrimerPaymentMethods view, read the available methods from session.selection?.state.paymentMethods.
SwiftUI integration
Composable views render nothing
Cause: The composable views —PrimerCardForm, PrimerPaymentMethods, and PrimerVaultedPaymentMethods — resolve their session from the SwiftUI environment. Without the .primerCheckoutSession(_:onCompletion:) modifier above them, they have no session to bind to. They also stay empty until the session reaches .ready.
Solution: Hold a PrimerCheckoutSession as a @StateObject and attach the modifier once around your composable views. The modifier injects the session, the derived PrimerCardFormSession, and the PrimerSelectionSession into the environment, calls start() on appear, and tears the session down on disappear:
PrimerCheckout view instead — it owns its own session and requires no modifier.
Session re-initializes unexpectedly
Cause:PrimerCheckoutSession is recreated whenever SwiftUI re-evaluates the enclosing body. Storing it in a let, a computed property, or @State (initialized inline) causes a fresh session — and a fresh client-token initialization — on every view update.
Solution: Own the session as a @StateObject so SwiftUI keeps a single instance for the lifetime of the view:
.primerCheckoutSession modifier drives the lifecycle for you — you normally never call start() or cancel() yourself. Call session.refresh() only when you need to reload after a client-session update (for example, an amount or currency change).
Theme or settings not applied
Cause: CreatingPrimerCheckoutTheme() or PrimerSettings() inside the SwiftUI body property. SwiftUI re-evaluates body frequently, creating new objects each time.
Solution: Define configuration as constants outside the view body:
UIKit integration
Delegate callbacks never fire
Cause:PrimerCheckoutPresenterDelegate not set on PrimerCheckoutPresenter.shared before calling presentCheckout, or the delegate object was deallocated.
Solution: Set the delegate before presenting and implement all required methods:
Checkout not presented
Cause: CallingpresentCheckout while already presenting — the call is silently ignored with no visible feedback.
Solution: Check PrimerCheckoutPresenter.isPresenting before calling:
Card form
Form shows invalid despite all visible fields being filled
Cause: The form validation considers all configured fields, including billing address fields that may not be visible on screen. Backend configuration (the Dashboard-drivenCardFormConfiguration) controls which billing fields are required.
Solution: Inspect state.fieldErrors on the PrimerCardFormSession to identify which specific fields are failing validation. The session is handed to each PrimerCardForm slot — observe it with @ObservedObject:
session.state.isValid to gate the submit button and session.state.errorMessage(for:) to display a per-field message.
Apple Pay
Apple Pay not available
Cause: Multiple possible causes:- Running on the iOS Simulator (Apple Pay requires a real device)
- No payment cards added to the user’s Wallet
- Apple Pay not configured in the Primer Dashboard
- Merchant identifier mismatch between Apple Developer portal and Primer Dashboard
PrimerSettings(paymentMethodOptions:) with a PrimerApplePayOptions(merchantIdentifier:), Apple Pay surfaces automatically as a CheckoutPaymentMethod (with type == "APPLE_PAY") in PrimerPaymentMethods, or as a managed screen in PrimerCheckout. If it never appears, confirm the method is present in session.selection?.state.paymentMethods. See the Apple Pay integration guide.
Installation
SPM package not found
Cause: Build fails with “No such module ‘PrimerSDK’”. Solution: Re-add the SPM package:- In Xcode, go to File > Add Package Dependencies
- Enter the Primer SDK repository URL
- Select the correct version and add to your target
CocoaPods installation fails
Cause:pod install fails or doesn’t include the Primer SDK.
Solution: Verify your Podfile and reinstall:
Minimum deployment target
Cause: Crash or build error on iOS 14 or earlier. Solution: The Primer Checkout iOS SDK requires iOS 15.0 or later. Update your deployment target:Validation vs payment errors
Understanding the difference helps with proper error handling:| Error Type | When It Occurs | How It’s Handled |
|---|---|---|
| Validation errors | During input (invalid format, missing fields) | Handled automatically by input components; prevents form submission |
| Payment failures | After form submission (declined card, network issues) | Requires explicit handling with error container or custom code |
Debugging tips
Log the terminal state
TheonCompletion closure on PrimerCheckout or the .primerCheckoutSession(_:onCompletion:) modifier fires exactly once with the terminal PrimerCheckoutState:
Inspect available payment methods
Read the available methods from thePrimerSelectionSession once the session is .ready:
Check session readiness
The composable views bind only once the session reaches.ready. Observe session.phase to confirm initialization completed and the child sessions resolved:
Log card form validation errors
ReadfieldErrors from the PrimerCardFormSession handed to a PrimerCardForm slot:
Extract diagnostics for support
Getting help
When contacting Primer support, include:- The
diagnosticsIdfrom any error callbacks - Your iOS version, Xcode version, and SDK version
- Steps to reproduce the issue
See also
Events guide
Event handling patterns
Build a custom card form
Card form tutorial
Best practices
SwiftUI performance tips