This page covers the official Dodo Payments React Native checkout SDK,
@dodopayments/react-native-checkout. It opens Dodo Payments hosted checkout in a native browser view and returns a typed result. An older package, dodopayments-react-native-sdk (unscoped), has a different API. This page documents only the scoped package.Checkout Sessions API
Create the
checkout_url that this SDK opens, from your backend.Mobile Integration Guide
See how this SDK fits into the full mobile payment flow.
SFSafariViewController on iOS and a Custom Tab on Android. It holds no API key and has no checkout logic of its own, so it never calls the Dodo Payments API. Checkout runs in the browser view. The SDK presents and dismisses that view and reads the result from the return URL.
Installation
1
Install the Package
- Android
- iOS
- Expo
The package is autolinked and pulls The native dependency resolves automatically, so no other install step is needed.
com.dodopayments.api:checkout-android from Maven Central.2
Register a Callback URL Scheme
Register a URL scheme so that the operating system routes the checkout’s return URL back to your app.On every platform, set the same URL as the checkout session’s
- Android (Gradle)
- iOS (Info.plist)
- Expo (both platforms)
Set the scheme as a manifest placeholder in Replace
android/app/build.gradle:android/app/build.gradle
"myapp" with your app’s scheme.return_url when your backend creates the session. The SDK matches the return URL on scheme, host, and path. The URL doesn’t need to load a real page.Usage
CallDodoCheckout.start with the checkout_url from your backend:
onEvent receives events with a type of checkout.opened, checkout.return_received, or checkout.closed. Use them for logging only, never to decide the outcome.
Forwarding the Return URL
iOS needs theLinking listener to handle the return URL, because SFSafariViewController can’t catch its own return URL. On Android, handleOpenURL does nothing and resolves false, because the Android SDK catches its redirect natively. You can register the listener on both platforms.
handleOpenURL resolves true when the URL belongs to the checkout in progress, and false for any other URL.
What the Result Means
The SDK builds the result from the query parameters on the return URL.CheckoutStatus
required
One of five values:
succeeded: the return URL hasstatus=succeeded(one-time payment) orstatus=active(subscription).failed: the payment was declined (status=failed).cancelled: the customer closed the browser view before the return URL arrived. The SDK doesn’t know the outcome, and the payment may have succeeded, so don’t show a failure screen. Reconcile the abandoned session instead.pending: the payment settles later (status=processingor anyrequires_*value), or thestatusparameter was missing or unrecognized. Reconcile it likecancelled.expired: the checkout session expired (status=expired).
string
The
payment_id query parameter, when the return URL includes one. Show it in your UI, but don’t use it to grant access. See Verify the Payment.string
The
subscription_id query parameter. Set for subscription checkouts.string[]
The
license_key query parameter. Set when the checkout includes license key products.string
The
email query parameter. Set when checkout captures an email address.Record<string, string>
Every query parameter from the return URL, verbatim.
Verify the Payment
Webhooks
Dodo Payments calls your backend when a payment succeeds or a subscription activates.
Get Payment Detail
Look up
paymentId with your secret key to check its status.result.status alone.
Appearance Customization
To change the checkout browser’s toolbar, buttons, and color scheme, passcustomization to start(...). Android Custom Tabs and iOS SFSafariViewController expose different native controls, so the options are grouped into an android object and an ios object. Each platform reads only its own object. Every field is optional. When you omit a field, the platform applies its own default.
Android — Custom Tab
Android — Custom Tab
string
Toolbar background color, as a hex string:
"#RRGGBB" or "#AARRGGBB".Navigation bar color, as a hex string.
Color of the divider above the navigation bar, as a hex string.
'default' | 'back'
default shows the system “X” icon. back shows a back arrow that the SDK draws.'start' | 'end'
The side of the toolbar where the close button appears.
Shows the toolbar’s share icon.
false hides it.boolean
Shows the page title under the URL in the toolbar.
boolean
Hides the toolbar automatically as the page scrolls.
boolean
Shows “Bookmark this page” in the overflow menu.
boolean
Shows “Download page” in the overflow menu.
'system' | 'light' | 'dark'
light or dark forces that appearance regardless of the device’s system setting. system follows the system setting.iOS — SFSafariViewController
iOS — SFSafariViewController
'done' | 'close' | 'cancel'
Style of the dismiss button. iOS decides whether it renders as a label or an icon.
'pageSheet' | 'fullScreen'
pageSheet (the default) presents a card that the customer can swipe down to dismiss. fullScreen covers the whole screen.boolean
Lets the toolbar collapse as the page scrolls. It has a visible effect only when
presentationStyle is fullScreen. With pageSheet, the bars stay pinned regardless of this setting.'system' | 'light' | 'dark'
light or dark forces that appearance regardless of the device’s system setting. system follows the system setting.SFSafariViewController tint properties are deprecated as of iOS 26.
Errors
start rejects with a CheckoutError only for misuse or a platform failure. Read the reason from error.code. A customer who cancels, or a declined payment, is always a result, never a rejection.
INVALID_CHECKOUT_URL:checkoutUrlisn’t anhttpscheckout session URL (path starting with/session/) oncheckout.dodopayments.comortest.checkout.dodopayments.com.INVALID_RETURN_URL:returnUrlisn’t an absolute URL with a scheme and a host.ALREADY_IN_PROGRESS: another checkout is running. Only one checkout can run at a time.PLATFORM_ERROR: an unexpected platform failure. The SDK also reports any unrecognized native error with this code.
Abandoned Sessions
The native SDK records the checkout session when checkout starts, and clears the record only when checkout ends withsucceeded, failed, or expired. The record stays when the app or the JavaScript bundle is killed during checkout, which loses the start promise, and after a cancelled or pending result. Check for it on the next mount and after every cancelled or pending result:
abandoned.sessionId is the checkout session ID, which starts with cks_. abandoned.createdAt is the Date checkout started. Your backend can look up the session with Get Checkout Session, which returns its payment_id and payment_status. Until the payment reaches a final status, treat it as pending, not failed.
Related
Mobile Integration Guide
The same contract for Android, iOS, and Flutter.
Expo Boilerplate
A complete Expo example with checkout integration.