Warning
Alpha — early preview. This software is an early preview and is not
production-ready. Stability is not guaranteed, and breaking changes may
occur in any release. Published under the next dist-tag — see
Installation.
Shopify Checkout Kit is a Native Module that enables React Native apps to provide the world’s highest converting, customizable, one-page checkout within the app. The presented experience is a fully-featured checkout that preserves all of the store customizations: Checkout UI extensions, Functions, branding, and more. It also provides platform idiomatic defaults such as support for light and dark mode, and convenient developer APIs to embed, customize, and follow the lifecycle of the checkout experience.
Check out our blog to learn how and why we built the Shopify Checkout Kit.
The React Native SDK is part of Shopify's Mobile Kit which enables developers to delivery best-in-class iOS and Android commerce experiences.
- Platform Requirements
- Version Compatibility
- Getting Started
- Basic Usage
- Programmatic Usage
- Usage with the Shopify Storefront API
- Configuration
- Preloading
- Checkout lifecycle
- Identity & customer accounts
- Offsite Payments
- Pickup points / Pickup in store
- Contributing
- License
- React Native - Minimum version
0.77(v4+) /0.70(v3 and earlier) - iOS - Minimum version iOS 15
- Android - Minimum Java 11, Android SDK version
24, and Kotlin2.0+
Starting with v4.0.0, @shopify/checkout-kit-react-native requires the React Native
New Architecture (TurboModules + Fabric). Apps on the old architecture must
stay on the v3.x line until they migrate.
| Package version | React Native | Architecture |
|---|---|---|
4.x |
>= 0.77 |
New Architecture |
3.x |
>= 0.70 |
Old Architecture |
See the React Native upgrade guide for help enabling the New Architecture in your app.
Shopify Checkout Kit is an open-source NPM package.
Use the following steps to get started with adding it to your React Native application:
Install the Shopify Checkout Kit package dependency:
pnpm add @shopify/checkout-kit-react-native
# or using yarn
yarn add @shopify/checkout-kit-react-native
# or using npm
npm install @shopify/checkout-kit-react-nativeCheck the minSdkVersion property in your android/build.gradle file is at
least 24.
The Android package also requires Kotlin 2.0+. React Native 0.77+ templates
use compatible Kotlin defaults (2.0.21 for React Native 0.77–0.79, and
2.1.20 for React Native 0.80+). If your app defines a Kotlin version, the
package will use rootProject.ext.kotlinVersion, rootProject.ext.kotlin_version,
or matching Gradle properties before falling back to 2.0.21.
// android/build.gradle
buildscript {
ext {
buildToolsVersion = "33.0.0"
- minSdkVersion = 21
+ minSdkVersion = 24
compileSdkVersion = 33
targetSdkVersion = 33
}
// ...
}Check the platform :ios property of your ios/Podfile to ensure that the
minimum version number is at least 15.
# ios/Podfile
- platform :ios, min_ios_version_supported
+ platform :ios, 15Once the SDK has been added as a package dependency and the minimum platform requirements have been checked, you can begin by importing the library in your application code:
import {ShopifyCheckoutProvider} from '@shopify/checkout-kit-react-native';
function AppWithContext() {
return (
<ShopifyCheckoutProvider>
<App />
</ShopifyCheckoutProvider>
);
}Doing so will now allow you to access the Native Module anywhere in your application using React hooks:
import {useShopifyCheckout} from '@shopify/checkout-kit-react-native';
function App() {
const shopifyCheckout = useShopifyCheckout();
// Present the checkout
shopifyCheckout.present(checkoutUrl);
}See usage with the Storefront API below for details on how to obtain a checkout URL to pass to the kit.
Note
The recommended usage of the library is through a
ShopifyCheckoutProvider Context provider, but see
Programmatic usage below for details on how to use the
library without React context.
To use the library without React context, import the ShopifyCheckout
class from the package and instantiate it. We recommend to instantiating the
class at a relatively high level in your application, and exporting it for use
throughout your app.
// shopify.ts
import {ShopifyCheckout} from '@shopify/checkout-kit-react-native';
export const shopifyCheckout = new ShopifyCheckout({
// optional configuration
});Similar to the context approach, you can consume the instance as you would using hooks.
import {shopifyCheckout} from './shopify.ts';
shopifyCheckout.present(checkoutUrl);To present a checkout to the buyer, your application must first obtain a checkout URL. The most common way is to use the Storefront GraphQL API, to create a cart, add line items, and retrieve a checkoutUrl value. Alternatively, a cart permalink can be provided.
You can use any GraphQL client to accomplish this - but as an example, our sample app uses Apollo.
Here's an example of how to get started with Apollo:
import {ApolloClient, gql, ApolloProvider} from '@apollo/client';
import {API_VERSION, STOREFRONT_DOMAIN, STOREFRONT_ACCESS_TOKEN} from '@env';
// Create a new instance of the ApolloClient
const client = new ApolloClient({
uri: `https://${STOREFRONT_DOMAIN}/api/${API_VERSION}/graphql.json`,
headers: {
'X-Shopify-Storefront-Access-Token': STOREFRONT_ACCESS_TOKEN,
},
});
// Create Cart Mutation
const createCartMutation = gql`
mutation CreateCart {
cartCreate {
cart {
id
checkoutUrl
}
}
}
`;
// Add to Cart Mutation
const addToCartMutation = gql`
mutation AddToCart($cartId: ID!, $lines: [CartLineInput!]!) {
cartLinesAdd(cartId: $cartId, lines: $lines) {
cart {
id
checkoutUrl
}
}
}
`;
function YourReactNativeApp() {
return (
<ApolloProvider client={client}>
<App />
</ApolloProvider>
);
}The checkoutUrl object is a standard web checkout URL that can be opened in
any browser. To present a native checkout sheet in your application, provide the
checkoutUrl alongside optional runtime configuration settings to the
present(checkoutUrl) function provided by the SDK:
function App() {
const [createCart] = useMutation(createCartMutation)
const [addToCart] = useMutation(addToCartMutation)
return (
// React native app code
)
}The checkoutUrl value is a standard web checkout URL that can be opened in any
browser. To present a native checkout sheet in your application, provide the
checkoutUrl to the present(checkoutUrl) function provided by the SDK:
function App() {
const shopifyCheckout = useShopifyCheckout()
const checkoutUrl = useRef<string>(null)
const [createCart] = useMutation(createCartMutation)
const [addToCart] = useMutation(addToCartMutation)
const handleAddToCart = useCallback((merchandiseId) => {
// Create a cart
const {data: cartCreateResponse} = await createCart()
// Add an item to the cart
const {data: addToCartResponse} = await addToCart({
variables: {
cartId: cartCreateResponse.cartCreate.cart.id,
lines: [{quantity: 1, merchandiseId}]
}
})
// Retrieve checkoutUrl from the Storefront response
checkoutUrl.current = addToCartResponse.cartLinesAdd.cart.checkoutUrl
// Preload the checkout in the background for faster presentation
shopifyCheckout.preload(checkoutUrl.current)
}, []);
const handleCheckout = useCallback(() => {
if (checkoutURL.current) {
// Present the checkout to the buyer
shopifyCheckout.present(checkoutURL.current)
}
}, [])
return (
<Catalog>
<Product onAddToCart={handleAddToCart} />
<Button onPress={handleCheckout}>
<Text>Checkout</Text>
</Button>
<Catalog>
)
}Tip
To help optimize and deliver the best experience the SDK also provides a preloading API that can be used to initialize the checkout session in the background and ahead of time.
The SDK provides a way to customize the presented checkout experience through a
configuration object in the Context Provider or a setConfig method on an
instance of the ShopifyCheckout class.
| Name | Required | Default | Description |
|---|---|---|---|
title |
Checkout |
Sets the title of the checkout sheet at runtime on both iOS and Android. For per-locale localization, use the platform resource files. See Localization. | |
colorScheme |
automatic |
Sets the color scheme for the checkout. | |
preloading |
true |
Enable/disable preloading. | |
telemetry |
true |
Sends anonymous diagnostic metrics to Shopify on iOS and Android. Set to false to opt out. |
|
colors |
{} |
An object with ios and android properties to override the colors for iOS and Android platforms individually. See colors for more information. |
|
logLevel |
error |
Sets the log level for the native SDK. Use LogLevel.debug for verbose logging during development, or LogLevel.error for production. |
|
allowedMessageOrigins |
[] |
Extra origins trusted to send incoming checkout messages. See Incoming message origin validation. |
Checkout Kit reports limited, anonymous diagnostic metrics, including checkout errors, protocol decoding failures, navigation retries, and checkout navigation timing. These diagnostics never include checkout URLs, message payloads, buyer data, or checkout, order, customer, or shop identifiers. Disabling telemetry stops new collection and discards measurements that have not already been handed to the operating system for delivery.
Here's an example of how a fully customized configuration object might look:
import {
ColorScheme,
Configuration,
LogLevel,
ShopifyCheckoutProvider,
} from '@shopify/checkout-kit-react-native';
const config: Configuration = {
colorScheme: ColorScheme.storefront,
preloading: true,
logLevel: LogLevel.error,
colors: {
ios: {
backgroundColor: '#f0f0e8',
tintColor: '#2d2a38',
},
android: {
backgroundColor: '#f0f0e8',
progressIndicator: '#2d2a38',
headerBackgroundColor: '#f0f0e8',
headerTextColor: '#2d2a38',
},
},
};
// If using React Context
function AppWithContext() {
return (
<ShopifyCheckoutProvider configuration={config}>
<App />
</ShopifyCheckoutProvider>
);
}
// If using ShopifyCheckout directly
const shopifyCheckout = new ShopifyCheckout(config);The SDK defaults to the automatic color scheme option, will switches between
idiomatic light and dark themes depending on the users preference. This
behavior can be customized via the colorScheme property:
| Name | Default | Description |
|---|---|---|
automatic |
✔ | Alternates between an idiomatic light and dark theme - depending on the users device preference. |
light |
Force the idomatic light theme. | |
dark |
Force the idomatic dark theme. | |
storefront |
Force your storefront web checkout branding. |
The colors configuration property can be used to provide overrides for iOS and
Android applications separately.
const config: Configuration = {
colorScheme: ColorScheme.light,
colors: {
ios: {
backgroundColor: '#ffffff',
tintColor: '#000000',
closeButtonColor: '#333333',
},
android: {
backgroundColor: '#ffffff',
progressIndicator: '#2d2a38',
headerBackgroundColor: '#ffffff',
headerTextColor: '#000000',
closeButtonColor: '#333333',
},
},
};Note that when using the automatic option, the colors.android interface is
slightly different, as you can specify different overrides for light and
dark modes:
import {
ColorScheme,
Configuration,
ShopifyCheckoutProvider,
} from '@shopify/checkout-kit-react-native';
const config: Configuration = {
colorScheme: ColorScheme.automatic,
colors: {
// Custom light/dark overrides for Android
android: {
light: {
backgroundColor: '#ffffff',
progressIndicator: '#2d2a38',
headerBackgroundColor: '#ffffff',
headerTextColor: '#000000',
closeButtonColor: '#000000',
},
dark: {
backgroundColor: '#000000',
progressIndicator: '#0087ff',
headerBackgroundColor: '#000000',
headerTextColor: '#ffffff',
closeButtonColor: '#ffffff',
},
},
},
};
function AppWithContext() {
return (
<ShopifyCheckoutProvider configuration={config}>
<App />
</ShopifyCheckoutProvider>
);
}Native checkout accepts messages from every origin by default. To restrict
messages, configure one or more exact origins or wildcard subdomains. The
checkout URL's origin and Shopify-owned shop.app and shop.com domains (including their subdomains) remain trusted automatically.
const config: Configuration = {
allowedMessageOrigins: [
'https://checkout.example.com',
'https://*.example.org',
],
};Entries may be exact origins (https://example.com), wildcard subdomains
(https://*.example.com, matching subdomains but not the apex), or '*' to
explicitly disable origin validation.
Messages dropped by origin validation are never silently discarded: the native SDK logs each rejection as a warning with the message origin and the reason it was dropped. The message body is untrusted and is not logged.
The title configuration attribute sets the checkout sheet title at runtime on
both iOS and Android:
shopify.setConfig({title: 'Checkout'});Use setConfig({title: dynamicTitle}) when you derive or retrieve the value at
runtime, e.g. from an API or based on the cart contents.
For per-locale localization, provide translated values through the platform
resource files below. The runtime title takes precedence when set, so leave it
unset when relying on the resource files for localization.
Use a Localizable.xcstrings file in your app by doing the following:
- Create a
Localizable.xcstringsfile under "ios/{YourApplicationName}" - Add an entry for the key
"shopify_checkout_sheet_title"
Add a string entry for the key "checkout_web_view_title" to the
"android/app/src/main/res/values/strings.xml" file for your application. Add a
values-<locale>/strings.xml file for each additional locale you support.
<resources>
<string name="app_name">Your App Name</string>
+ <string name="checkout_web_view_title">Checkout</string>
</resources>Expo apps that use prebuild do not
commit the native android/ and ios/ directories, so the Android
strings.xml edit above is not persistent. Add the string through a local
config plugin instead so
it is reapplied on every prebuild.
Create plugins/withCheckoutSheetTitle.js:
const {withStringsXml, AndroidConfig} = require('expo/config-plugins');
const {setStringItem} = AndroidConfig.Strings;
module.exports = function withCheckoutSheetTitle(config, title = 'Checkout') {
return withStringsXml(config, (config) => {
config.modResults = setStringItem(
[{$: {name: 'checkout_web_view_title'}, _: title}],
config.modResults,
);
return config;
});
};Then reference it from app.json / app.config.js:
{
"expo": {
"plugins": [["./plugins/withCheckoutSheetTitle", "Checkout"]]
}
}You'll need to run npx expo prebuild to apply it, and re-run your android
build (not just restart metro, as this is a native gradle change).
Note
The config plugin writes the default values/strings.xml. Per-locale titles
require writing values-<locale>/strings.xml for each locale, which the
snippet above does not cover. On iOS, localized titles continue to use the
Localizable.xcstrings step above.
To set an appropriate currency for a given cart, the Storefront API offers an
@inContext(country) directive which will ensure the correct currency is
presented.
const CREATE_CART_MUTATION = gql`
mutation CreateCart($input: CartInput, $country: CountryCode = CA)
@inContext(country: $country) {
cartCreate(input: $input) {
cart {
id
checkoutUrl
}
}
}
`;See Storefront Directives for more information.
Similarly to currency, you can use an @inContext(language) directive to set
the language for your checkout.
const CREATE_CART_MUTATION = gql`
mutation CreateCart($input: CartInput, $language: Language = EN)
@inContext(language: $language) {
cartCreate(input: $input) {
cart {
id
checkoutUrl
}
}
}
`;See Storefront Directives for more information.
Initializing a checkout session requires communicating with Shopify servers,
thus depending on the network quality and bandwidth available to the buyer can
result in undesirable waiting time for the buyer. To help optimize and deliver
the best experience, the SDK provides a preloading "hint" that allows
developers to signal that the checkout session should be initialized in the
background, ahead of time.
Preloading is an advanced feature that can be disabled by setting the
preloading configuration value to false. It is enabled by default.
Once enabled, preloading a checkout is as simple as calling
preload(checkoutUrl) with a valid checkoutUrl.
// using hooks
const shopifyCheckout = useShopifyCheckout();
shopifyCheckout.preload(checkoutUrl);
// using a class instance
const shopifyCheckout = new ShopifyCheckout();
shopifyCheckout.preload(checkoutUrl);Pass onStateChange when the application needs preload diagnostics or wants to
reflect its progress. The callback receives the current native state immediately
and every subsequent transition for that preload.
const preloadSubscription = shopifyCheckout.preload(checkoutUrl, {
onStateChange(state) {
if (state.type === 'ready') {
reportPreloadReady();
}
if (state.type === 'failed') {
reportPreloadFailure(state.reason, state.statusCode);
}
},
});
// Stops state callbacks without invalidating the cached checkout.
preloadSubscription.remove();preloadSubscription.state contains the latest observed state. Calling
preload(...) again replaces the previous preload observer, so repeated calls
do not accumulate native or JavaScript event subscriptions. A previous
subscription retains its last state but receives no further callbacks.
| State | Meaning |
|---|---|
idle |
No checkout is currently being preloaded. |
loading |
Checkout is loading in the background. |
ready |
The matching checkout is ready for presentation. |
expired |
The cached checkout reached its lifetime and was discarded. |
failed |
Preload could not retain usable checkout content. Inspect reason and the optional HTTP statusCode. |
Preload state is not presentation lifecycle state. Do not disable checkout while
waiting for ready, and do not automatically retry from failed or expired.
Calling present(checkoutUrl) still loads checkout normally when a preload is
unavailable or incomplete.
Applications should preload when buyer intent is strong and after successful cart mutations, using the cart returned by the Storefront API mutation. A typical integration calls the same helper when the buyer enters the cart, changes an item quantity, or removes an item:
let preloadSubscription: CheckoutPreloadSubscription | undefined;
function preloadCart(cart: Cart) {
if (!cart.checkoutUrl || cart.totalQuantity === 0) {
shopifyCheckout.invalidate();
return;
}
preloadSubscription = shopifyCheckout.preload(cart.checkoutUrl, {
onStateChange(state) {
reportPreloadState(state);
},
});
}
function onCartScreenEntered(cart: Cart) {
preloadCart(cart);
}
async function changeQuantity(lineId: string, quantity: number) {
const updatedCart = await updateCartLine(lineId, quantity);
preloadCart(updatedCart);
}
async function removeItem(lineId: string) {
const updatedCart = await removeCartLine(lineId);
preloadCart(updatedCart);
}
function onCartScreenDisposed() {
preloadSubscription?.remove();
}Each explicit preload(...) call refreshes the cached checkout, even when the
checkoutUrl is unchanged. No separate invalidate() call is needed after a
successful cart mutation.
Removing the subscription only stops observation. It intentionally leaves the
preloaded checkout available so navigation from the cart to checkout can reuse
it. Use invalidate() when the cart becomes empty or the cached checkout is no
longer applicable.
- Initiating preload results in background network requests and additional CPU/memory utilization for the client, and should be used when there is a high likelihood that the buyer will soon request to checkout—e.g. when the buyer navigates to the cart overview or a similar app-specific experience.
- A preloaded checkout session reflects the cart contents at the time when
preloadis called. If the cart is updated afterpreloadis called, the application needs to callpreloadagain to reflect the updated checkout session. - Calling
preload(checkoutUrl)is a hint, not a guarantee: the library may debounce or ignore calls to this API depending on various conditions; the preload may not complete beforepresent(checkoutUrl)is called, in which case the buyer may still see a spinner while the checkout session is finalized.
It is important to note that during Flash Sales or periods of high amounts of traffic, buyers may be entered into a queue system.
Calls to preload which result in a buyer being enqueued will be rejected. This means that a buyer will never enter the queue without their knowledge.
Calling preload() each time an item is added to a buyer's cart can put significant strain on Shopify systems, which in return can result in rejected requests. Rejected requests will not result in a visual error shown to users, but will degrade the experience since they will need to load checkout from scratch.
Instead, a better approach is to call preload() when you have a strong enough signal that the buyer intends to check out. In some cases this might mean a buyer has navigated to a "cart" screen.
Should you wish to manually clear the preload cache, call invalidate() on your ShopifyCheckout instance or the value returned by useShopifyCheckout().
Lifecycle callbacks are passed per-call to present(). The bridge holds the
handles for the duration of that one presentation and releases them on
terminal events; nothing needs to be subscribed or torn down explicitly.
shopify.present(checkoutUrl, {
onClose: () => {
// The sheet was dismissed without a terminal error
},
onFail: (error: CheckoutException) => {
// A terminal error occurred — inspect `error.code`, `error.message`, etc.
},
});| Name | Callback | Fires |
|---|---|---|
onClose |
() => void |
Once, when the buyer dismisses the sheet without a terminal error. |
onFail |
(error: CheckoutException) => void |
Once, when the checkout terminates with an error. |
onGeolocationRequest |
(event: GeolocationRequestEvent) => void |
Android only. Fired each time the webview requests geolocation permissions. See Opting out of the default behavior. |
onClose and onFail are mutually exclusive — exactly one of them fires
per present(...) call, after which both handles are released.
Buyer-aware checkout experience reduces friction and increases conversion. Depending on the context of the buyer (guest or signed-in), knowledge of buyer preferences, or account/identity system, the application can use one of the following methods to initialize a personalized and contextualized buyer experience.
In addition to specifying the line items, the Cart can include buyer identity (name, email, address, etc.), and delivery and payment preferences: see guide. Included information will be used to present pre-filled and pre-selected choices to the buyer within checkout.
Shopify Plus merchants that already use Multipass can keep using it to integrate an external identity system and initialize a buyer-aware checkout session.
Note
Multipass is still supported for stores that already use it. New integrations should connect a third-party identity provider.
{
"email": "<Customer's email address>",
"created_at": "<Current timestamp in ISO8601 encoding>",
"remote_ip": "<Client IP address>",
"return_to": "<Checkout URL obtained from Storefront API>"
}- Follow the Multipass documentation
to create a Multipass URL and set
return_toto be the obtainedcheckoutUrl - Provide the Multipass URL to
present(checkoutUrl)
Important
The above JSON omits useful customer attributes that should be provided where possible and encryption and signing should be done server-side to ensure Multipass keys are kept secret.
To initialize accelerated Shop Pay checkout, the cart can set a walletPreference to 'shop_pay'. The sign-in state of the buyer is app-local. The buyer will be prompted to sign in to their Shop account on their first checkout, and their sign-in state will be remembered for future checkout sessions.
We are working on a library to provide buyer sign-in and authentication powered by the new Customer Account API—stay tuned.
Certain payment providers finalize transactions by redirecting customers to external banking apps. To enhance the user experience for your buyers, you can set up your storefront to support Universal Links on iOS and App links on Android, allowing customers to be redirected back to your app once the payment is completed.
See the Universal Links guide for information on how to get started with adding support for Offsite Payments in your app.
Checkout Kit opens delegated web links in SFSafariViewController on iOS and
Android Custom Tabs on Android by default. Non-web links open through the
platform's native app opener.
Geolocation permission requests are handled out of the box by iOS, provided you've added the required location usage description to your Info.plist file:
<key>NSLocationWhenInUseUsageDescription</key>
<string>Your location is required to locate pickup points near you.</string>Tip
Consider also adding NSLocationAlwaysAndWhenInUseUsageDescription if your app needs background location access for other features.
Android differs to iOS in that permission requests must be handled in two places:
(1) in your AndroidManifest.xml and (2) at runtime.
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />When the webview requests geolocation information, the Checkout Kit native module surfaces it to JS so the app can respond. By default, the kit handles the request itself and asks for both coarse and fine access on the buyer's behalf.
The geolocation request flow follows this sequence:
- When checkout needs location data (e.g., to show nearby pickup points), it triggers a geolocation request.
- If you've passed an
onGeolocationRequestcallback topresent(), that callback is invoked. Request or check Android permissions, then callevent.respond(allow). - Otherwise, with
features.handleGeolocationRequests: true(the default), the module automatically handles the Android runtime permission request. - The response is passed back to checkout, which then proceeds to show relevant pickup points if permission was granted.
Note
If the user denies location permissions, the checkout will still function but will not be able to show nearby pickup points. Users can manually enter their location instead.
Note
This section is only applicable for Android.
There are two ways to customize Android geolocation handling, depending on whether you want to override the behavior for one presentation or disable the fallback globally.
Per-call override. Pass an onGeolocationRequest callback to
present(). When set, the callback fires instead of the default handler
for that one presentation; the consumer is responsible for resolving
permissions and calling event.respond(allow):
shopify.present(checkoutUrl, {
onGeolocationRequest: async (event: GeolocationRequestEvent) => {
const coarse = 'android.permission.ACCESS_COARSE_LOCATION';
const fine = 'android.permission.ACCESS_FINE_LOCATION';
const results = await PermissionsAndroid.requestMultiple([coarse, fine]);
const granted =
results[coarse] === 'granted' || results[fine] === 'granted';
event.respond(granted);
},
});event.respond(...) resolves checkout's pending WebView geolocation request.
It does not request OS permissions by itself.
Process-wide default-handler opt-out. Set
features.handleGeolocationRequests to false when you instantiate the
ShopifyCheckout class to disable the default handler entirely. When this is
set, pass onGeolocationRequest to any present() call that may need
geolocation; otherwise the checkout geolocation request will not be resolved.
const shopifyCheckout = new ShopifyCheckout(config, {handleGeolocationRequests: false});If you're using the context provider, pass the same features object as a prop:
<ShopifyCheckoutProvider configuration={config} features={{handleGeolocationRequests: false}}>
{children}
</ShopifyCheckoutProvider>Custom permission handling lets you:
- Customize the permission request UI/UX
- Coordinate location permissions with other app features
- Implement custom fallback behavior when permissions are denied
Accelerated checkout buttons surface Apple Pay and Shop Pay options earlier in the buyer journey so more orders complete without leaving your app.
- iOS 16 or later
- The
write_cart_wallet_paymentsaccess scope (request access) - Apple Pay payment processing certificates (setup guide)
- A device configured for Apple Pay (Apple setup instructions)
Pass an acceleratedCheckouts configuration when setting up the provider or ShopifyCheckout instance. This connects the accelerated checkout buttons to your storefront.
import {ShopifyCheckoutProvider} from '@shopify/checkout-kit-react-native';
const config = {
acceleratedCheckouts: {
storefrontDomain: 'your-shop.myshopify.com',
storefrontAccessToken: 'your-storefront-access-token',
// Identify the buyer using exactly one of the supported modes:
customer: {
// For buyers authenticated with Shopify Customer Accounts
accessToken: 'customer-access-token',
},
// OR, for buyers identified by contact fields:
// customer: {
// email: 'customer@example.com',
// phoneNumber: '0123456789',
// },
wallets: {
applePay: {
merchantIdentifier: 'merchant.com.yourcompany',
contactFields: ['email', 'phone'],
// Optionally restrict shipping countries (ISO 3166-1 alpha-2)
// supportedShippingCountries: ['US', 'CA'],
},
},
},
};
function App() {
return (
<ShopifyCheckoutProvider configuration={config}>
<YourApp />
</ShopifyCheckoutProvider>
);
}customer accepts either {accessToken} for authenticated Customer Account buyers, or {email, phoneNumber} for contact-field identification. These modes are mutually exclusive.
Use AcceleratedCheckoutButtons to attach accelerated checkout calls-to-action to product or cart surfaces once you have a valid cart ID or product variant ID from the Storefront API.
import {
AcceleratedCheckoutButtons,
AcceleratedCheckoutWallet,
} from '@shopify/checkout-kit-react-native';
function CartFooter({cartId}: {cartId: string}) {
return (
<AcceleratedCheckoutButtons
cartId={cartId}
wallets={[AcceleratedCheckoutWallet.shopPay, AcceleratedCheckoutWallet.applePay]}
/>
);
}You can also render buttons for a single product variant:
<AcceleratedCheckoutButtons
variantId={variantId}
quantity={1}
wallets={[AcceleratedCheckoutWallet.applePay]}
/>Accelerated checkout buttons display every available wallet by default. Use wallets to show a subset or adjust the order.
// Display only Shop Pay
<AcceleratedCheckoutButtons
cartId={cartId}
wallets={[AcceleratedCheckoutWallet.shopPay]}
/>
// Display Shop Pay first, then Apple Pay
<AcceleratedCheckoutButtons
cartId={cartId}
wallets={[AcceleratedCheckoutWallet.shopPay, AcceleratedCheckoutWallet.applePay]}
/>Use applePayLabel to map to the native PayWithApplePayButtonLabel values. The default is plain.
import {ApplePayLabel} from '@shopify/checkout-kit-react-native';
<AcceleratedCheckoutButtons
cartId={cartId}
applePayLabel={ApplePayLabel.buy}
/>Use applePayStyle to set the color style of the Apple Pay button. The default is automatic, which adapts to the current appearance (light/dark mode).
import {ApplePayStyle} from '@shopify/checkout-kit-react-native';
<AcceleratedCheckoutButtons
cartId={cartId}
applePayStyle={ApplePayStyle.whiteOutline}
/>Available styles: automatic, black, white, whiteOutline.
The cornerRadius prop lets you match the buttons to other calls-to-action in your app. Buttons default to an 8pt radius.
// Pill-shaped buttons
<AcceleratedCheckoutButtons cartId={cartId} cornerRadius={16} />
// Square buttons
<AcceleratedCheckoutButtons cartId={cartId} cornerRadius={0} />Attach lifecycle handlers to respond when buyers finish, cancel, or encounter an error.
<AcceleratedCheckoutButtons
cartId={cartId}
onComplete={(event) => {
// Clear cart after successful checkout
clearCart();
}}
onFail={(error) => {
console.error('Accelerated checkout failed:', error);
}}
onCancel={() => {
analytics.track('accelerated_checkout_cancelled');
}}
onRenderStateChange={(event) => {
// event.state: 'loading' | 'rendered' | 'error'
setRenderState(event.state);
}}
onClickLink={(url) => {
Linking.openURL(url);
}}
/>See the contributing documentation for details on how to get started.
Shopify's Checkout Kit is provided under an MIT License.