Overview
If you do not decommission your app versions that include the older SDK versions or force upgrade your app with the updated certificates by the expiration date, 100% of your customer traffic will fail.
App Switch enables buyers with the PayPal app installed to start checkout or vaulting in a merchant app or website and seamlessly complete the flow in the PayPal app. This provides a low-friction authentication experience using native PayPal app login methods such as Face ID, biometrics, or passkeys.
When App Switch is enabled, the Braintree iOS SDK attempts to switch to the PayPal app after tokenize is called, provided the PayPal app is installed and the buyer meets eligibility requirements. If App Switch is unavailable, the SDK automatically falls back to the PayPal web experience using ASWebAuthenticationSession.
This guide applies to merchants using the Braintree iOS SDK with the following PayPal flows:
- Vault flow: Vaulting without purchase
- One-time Checkout: One-time Payments "Pay Now"
- App Switch is not supported for One-time “Continue” flow or Vaulting with Purchase flow.
- App Switch is currently supported only for US merchants.
Understand the buyer flow
The following steps describe the buyer experience when App Switch is available and used during checkout or vaulting.
- The buyer initiates PayPal checkout or vaulting from the merchant’s native mobile app.
- If the PayPal app is installed and the buyer is eligible, the SDK switches context from the merchant app to the PayPal app.
- The buyer is authenticated in the PayPal app using low-friction login methods such as Face ID, biometrics, passkeys, or an existing PayPal app session.
- The buyer reviews the transaction or vaulting details and approves the action in the PayPal app.
- The buyer is redirected back to the merchant app.
- The merchant app completes the transaction or successfully vaults PayPal as a payment method.
One-time payments with Pay Now

Vaulted payments without purchase

Before you begin
- Get the SDK.
The PayPal App Switch is part of theBraintreePayPalmodule in the Braintree SDK. This module can be integrated into your app through all currently supported package managers. - Register for universal links.
- Register universal link in Control Panel.
- Set universal link in SDK.
Use the followingBTPayPalClientinitializer to set your Universal Link:let apiClient = BTAPIClient(authorization: <#CLIENT_AUTHORIZATION#>) let payPalClient = BTPayPalClient( apiClient: apiClient, // required universalLink: URL(string: "https://my-universal-link.com/braintree-payments")! // required ) - Handle App context switching.
Integrate App Switch
This section outlines the required iOS configuration and SDK usage needed to enable PayPal App Switch when tokenizing PayPal checkout or vault requests using the Braintree iOS SDK.
- To allow your app to detect and switch to the PayPal app, add the PayPal URL scheme to the
LSApplicationQueriesSchemesallowlist in your app’sInfo.plist: - When creating a PayPal request, set
enablePayPalAppSwitchto true. App Switch is triggered during tokenization if the PayPal app is installed and the buyer meets eligibility requirements. Include the buyer’s email address and phone number when available to personalize buyer’s experience and improve authentication and approval success rates. Use the request withBTPayPalClient.tokenize(_:completion:).
For One-time flow
- Swift
let request = BTPayPalCheckoutRequest(
enablePayPalAppSwitch: true, // to enable App Switch
userAuthenticationEmail: "buyer@example.com",
userPhoneNumber: BTPayPalPhoneNumber(
countryCode: "1",
nationalNumber: "2223334444"
)
)For Vaulting flow
- Swift
let request = BTPayPalVaultRequest(
enablePayPalAppSwitch: true, // to enable App Switch
userAuthenticationEmail: "buyer@example.com",
userPhoneNumber: BTPayPalPhoneNumber(
countryCode: "1",
nationalNumber: "2223334444"
)
)Code Sample
One-time Payments
- Kotlin
import UIKit
import BraintreePayPal
class MyViewController: UIViewController {
var apiClient: BTAPIClient!
var payPalClient: BTPayPalClient!
let payPalButton = UIButton(type: .system)
override func viewDidLoad() {
super.viewDidLoad()
apiClient = BTAPIClient(authorization: <#CLIENT_AUTHORIZATION#>)
payPalClient = BTPayPalClient(
apiClient: apiClient,
universalLink: URL(string: "https://my-universal-link.com/braintree-payments")! // required for this flow
)
setUpButton()
}
private func setUpButton() {
payPalButton.translatesAutoresizingMaskIntoConstraints = false
payPalButton.setTitle("PayPal Checkout", for: .normal)
payPalButton.setTitleColor(.blue, for: .normal)
payPalButton.addTarget(self, action: #selector(payPalButtonTapped), for: .touchUpInside)
view.addSubview(payPalButton)
}
@objc func payPalButtonTapped(_ sender: UIButton) {
sender.isEnabled = false
// one time checkout flows
let amount = "10.00" // or whatever you need
let request = BTPayPalCheckoutRequest(
amount: amount,
enablePayPalAppSwitch: true,
userAuthenticationEmail: "buyer@example.com",
userPhoneNumber: BTPayPalPhoneNumber(
countryCode: "1",
nationalNumber: "2223334444"
)
)
// enablePayPalAppSwitch is required for this flow
// Configure other values on 'request' as needed.
payPalClient.tokenize(request) { payPalNonce, error in
sender.isEnabled = true
if let payPalNonce {
// send payPalNonce.nonce to server
} else {
// handle error
}
}
}
}Vaulted Payments
- Kotlin
import UIKit
import BraintreePayPal
class VaultedPaymentViewController: UIViewController {
var apiClient: BTAPIClient!
var payPalClient: BTPayPalClient!
override func viewDidLoad() {
super.viewDidLoad()
apiClient = BTAPIClient(authorization: "<#CLIENT_AUTHORIZATION#>")
payPalClient = BTPayPalClient(
apiClient: apiClient,
universalLink: URL(string: "https://my-universal-link.com/braintree-payments")!
)
}
private func payPalButtonTapped() {
// vault flows
let request = BTPayPalVaultRequest(
enablePayPalAppSwitch: true,
userAuthenticationEmail: "buyer@email.com",
userPhoneNumber: BTPayPalPhoneNumber(
countryCode: "1",
nationalNumber: "2223334444"
)
)
// enablePayPalAppSwitch are required for this flow
// Configure other values on 'request' as needed.
payPalClient.tokenize(request) { payPalNonce, error in
if let payPalNonce {
// send payPalNonce.nonce to server
} else {
// handle error
}
}
}
}Best practices
These best practices are important to ensure optimal user experience and improved conversion
- Show a loading indicator after PayPal button click When the user taps the PayPal button:
- Immediately disable the PayPal button to prevent duplicate submissions.
- Show a loading indicator while the network request is in progress. This prevents accidental double taps and clearly communicates that the checkout flow is in progress.
- Provide buyer email and phone number Although optional, providing the buyer’s email address and phone number whenever available is strongly recommended. Passing this information allows PayPal to:
- Personalize the buyer experience.
- Improve risk assessment.
- Optimize approval rates.
- countryCode must contain numeric digits only (do not include a + prefix).
- nationalNumber must include digits only.
- Remove spaces, hyphens, parentheses, and other formatting characters.
- Do not include the country code in the national number.
- Do not include leading zeros unless they are part of the actual national number. Example:
- Handling return to your app When the buyer returns to your app (either automatically or manually):
- Remove the loading indicator immediately when your app returns to the foreground.
- Allow the buyer to continue from where they left off, especially if they exited the PayPal app without approving or canceling the transaction (for example, by backgrounding the PayPal app). When the SDK callback returns a nonce (indicating the buyer approved the transaction):
- Disable the PayPal button again.
- Display a loading indicator or overlay while finalizing the vault or transaction.
- Continue processing until completion.
- Redirection to mobile browser In some cases, after approving the transaction in the PayPal app, the OS may redirect the buyer to your website in the default mobile browser instead of returning to your app, even when return and cancel URLs are configured. This typically occurs when:
- The universal link configuration on the device does not match the registered domain, or
- The app cannot properly claim the universal link.
- Ensure universal links are correctly configured and associated with the domain.
- (Optional but recommended) Implement fallback logic on your website to:
- Detect redirected buyers.
- Retrieve or confirm the final token or payment status.
- Guide the buyer back to the correct in-app flow when possible.
Phone number formatting requirements
When passing a phone number, ensure it is sanitized into its canonical format:
userPhoneNumber: BTPayPalPhoneNumber(
countryCode: "1",
nationalNumber: "2223334444"
)You may optionally implement a timeout (for example, 10 seconds) for the loading indicator in case processing takes longer than expected.
This ensures UI consistency and prevents unintended user interactions during payment finalization.
Recommended mitigations:
Testing and Go Live
For detailed testing procedures and production deployment guidance, see the Testing and Go Live section.