useCheckout()
The useCheckout() hook is used to create, manage, and confirm a checkout session for a user or an Organization's Subscription Plan. It provides the state of the current checkout process, such as its status and any errors, along with methods to initiate and complete the checkout.
There are two ways to use useCheckout():
- In conjunction with <CheckoutProvider /> to create a shared checkout context. All child components inside the provider can then use
useCheckout()to access or update the same checkout state. - On its own by passing configuration options directly to it. This is ideal for self-contained components that handle their own checkout flow without needing a shared context.
Parameters
- Name
options?- Type
PropsWithChildren<UseCheckoutOptions>- Description
An object containing the configuration for the checkout flow. Required if the hook is used without a
<CheckoutProvider />wrapping the component tree.
Returns
useCheckout() returns an object with checkout, errors, and fetchStatus.
checkoutincludes the checkout state and methods.errorscontains any global or raw errors from the latest checkout request.fetchStatusindicates whether the checkout request is currently in progress.
Checkout data properties are null until the checkout process is started by calling the start() method.
- Name
-
checkout - Type
- CheckoutFlowResource
- Description
An instance representing the currently active
Checkout.
- Name
-
confirm - Type
(params: ConfirmCheckoutParams) => Promise<{ error: null | ClerkError; }>- Description
A function to confirm and finalize the checkout process, usually after payment information has been provided and validated. Learn more.
- Name
-
finalize - Type
(params?: CheckoutFlowFinalizeParams) => Promise<{ error: null | ClerkError; }>- Description
Used to convert a checkout with
status === 'completed'into an active subscription. Will cause anything observing the subscription state (such as theuseSubscription()hook) to update automatically.
- Name
-
payer - Type
null | { createdAt?: Date; email?: null | string; firstName?: null | string; id: string; imageUrl?: string; lastName?: null | string; organizationId: null | string; organizationName?: null | string; pathRoot: string; updatedAt?: Date; userId: null | string; }- Description
Example:
<ClerkProvider clerkJsVersion="x.x.x" />.
- Name
payer.createdAt?- Type
Date- Description
The date and time when the payer was created.
- Name
payer.email?- Type
null | string- Description
The email address of the payer.
- Name
payer.firstName?- Type
null | string- Description
The first name of the payer.
- Name
payer.id- Type
string- Description
The unique identifier for the payer.
- Name
payer.imageUrl?- Type
string- Description
The URL of the payer's avatar image.
- Name
payer.lastName?- Type
null | string- Description
The last name of the payer.
- Name
payer.organizationId- Type
null | string- Description
The unique identifier for the Organization that the payer belongs to.
- Name
payer.organizationName?- Type
null | string- Description
The name of the Organization that the payer belongs to.
- Name
payer.pathRoot- Type
string- Description
-
- Name
payer.updatedAt?- Type
Date- Description
The date and time when the payer was last updated.
- Name
payer.userId- Type
null | string- Description
The unique identifier for the payer.
- Name
-
paymentMethod - Type
null | { cardType: null | string; createdAt?: null | Date; expiryMonth?: null | number; expiryYear?: null | number; id: string; isDefault?: boolean; isRemovable?: boolean; last4: null | string; pathRoot: string; paymentType?: "card"; status: "active" | "expired" | "disconnected"; updatedAt?: null | Date; walletType?: null | string; }- Description
The payment source being used for the checkout, such as a credit card or bank account.
- Name
paymentMethod.cardType- Type
null | string- Description
The brand or type of card. For example,
'visa'or'mastercard'.
- Name
paymentMethod.createdAt?- Type
null | Date- Description
The date the payment method was created, if available.
- Name
paymentMethod.expiryMonth?- Type
null | number- Description
The card expiration month, if available.
- Name
paymentMethod.expiryYear?- Type
null | number- Description
The card expiration year, if available.
- Name
paymentMethod.id- Type
string- Description
The unique identifier for the payment method.
- Name
paymentMethod.isDefault?- Type
boolean- Description
Whether the payment method is set as the default for the account.
- Name
paymentMethod.isRemovable?- Type
boolean- Description
Whether the payment method can be removed by the user.
- Name
paymentMethod.last4- Type
null | string- Description
The last four digits of the payment method.
- Name
paymentMethod.pathRoot- Type
string- Description
-
- Name
paymentMethod.paymentType?- Type
"card"- Description
The type of payment method. For example,
'card'.
- Name
paymentMethod.status- Type
"active" | "expired" | "disconnected"- Description
The current status of the payment method.
- Name
paymentMethod.updatedAt?- Type
null | Date- Description
The date the payment method was last updated, if available.
- Name
paymentMethod.walletType?- Type
null | string- Description
The type of digital wallet, if applicable. For example,
'apple_pay', or'google_pay'.
- Name
-
plan - Type
null | { annualFee: null | BillingMoneyAmount; annualMonthlyFee: null | BillingMoneyAmount; availablePrices?: BillingPlanPrice[]; avatarUrl: null | string; description: null | string; features: FeatureResource[]; fee: null | BillingMoneyAmount; forPayerType: "org" | "user"; freeTrialDays: null | number; freeTrialEnabled: boolean; hasBaseFee: boolean; id: string; isDefault: boolean; isRecurring: boolean; name: string; pathRoot: string; publiclyVisible: boolean; slug: string; unitPrices?: BillingPlanUnitPrice[]; }- Description
The subscription plan details for the checkout.
- Name
plan.annualFee- Type
null | BillingMoneyAmount- Description
The annual price of the Plan or
nullif the Plan is not annual.
- Name
plan.annualMonthlyFee- Type
null | BillingMoneyAmount- Description
The effective monthly price when billed annually or
nullif the Plan is not annual.
- Name
plan.availablePrices?- Type
BillingPlanPrice[]- Description
The prices that are available to be used to checkout for the associated plan. Can be used to select non-default prices.
- Name
plan.avatarUrl- Type
null | string- Description
The URL of the Plan's avatar image, or
nullif not set.
- Name
plan.description- Type
null | string- Description
A short description of what the Plan offers, or
nullif no description is provided.
- Name
plan.features- Type
FeatureResource[]- Description
The Features the Plan offers.
- Name
plan.fee- Type
null | BillingMoneyAmount- Description
The monthly price of the Plan.
- Name
plan.forPayerType- Type
"org" | "user"- Description
Specifies the subscriber type this Plan is designed for. Each Plan is exclusively created for either individual users or Organizations, and cannot be used interchangeably.
- Name
plan.freeTrialDays- Type
null | number- Description
The number of days of the free trial for the Plan.
nullif the Plan does not have a free trial.
- Name
plan.freeTrialEnabled- Type
boolean- Description
Whether the Plan has a free trial.
- Name
plan.hasBaseFee- Type
boolean- Description
Whether the Plan has a base fee.
- Name
plan.id- Type
string- Description
The unique identifier for the Plan.
- Name
plan.isDefault- Type
boolean- Description
Whether the Plan is the default Plan.
- Name
plan.isRecurring- Type
boolean- Description
Whether the Plan is recurring.
- Name
plan.name- Type
string- Description
The name of the Plan.
- Name
plan.pathRoot- Type
string- Description
-
- Name
plan.publiclyVisible- Type
boolean- Description
Whether the Plan is visible to the public.
- Name
plan.slug- Type
string- Description
The URL-friendly identifier of the Plan.
- Name
plan.unitPrices?- Type
BillingPlanUnitPrice[]- Description
Per-unit pricing tiers for this Plan (for example, seats).
- Name
-
totals - Type
null | BillingTotals- Description
The total costs, taxes, and other pricing details for the checkout.
<CheckoutProvider />
The <CheckoutProvider /> component is a wrapper that provides a checkout context to its children, allowing checkout state to be shared across multiple components. Child components can access the checkout context by calling useCheckout().
Properties
The <CheckoutProvider /> component accepts the following props:
Usage
For the best user experience and to prevent potential errors, always wrap components using useCheckout() with both <ClerkLoaded> and <Show when="signed-in"> components. This ensures that the user is properly authenticated and Clerk is fully initialized before accessing checkout functionality.
function CheckoutPage() {
return (
<ClerkLoaded>
<Show when="signed-in">
<YourCheckoutComponent />
</Show>
</ClerkLoaded>
)
}Examples
The useCheckout() hook can be used with a context provider for managing state across multiple components or as a standalone hook for more isolated use cases.
The following example shows the basic structure for a checkout flow. A parent component, <SubscriptionPage />, sets up the <CheckoutProvider /> and renders the checkout flow. A child component, <CheckoutFlow />, uses the useCheckout() hook to access the checkout state.
import { CheckoutProvider } from '@clerk/react/experimental'
import { ClerkLoaded } from '@clerk/react'
import { CheckoutFlow } from './CheckoutFlow'
export default function SubscriptionPage() {
// `<CheckoutProvider />` sets the context for the checkout flow.
// Any child component can now call `useCheckout()` to access this context.
return (
// Update with your Plan ID and Plan Period
<CheckoutProvider for="user" planId="cplan_xxx" planPeriod="month">
<div>
<h1>Upgrade Your Plan</h1>
<p>You are about to subscribe to our monthly plan</p>
<ClerkLoaded>
<CheckoutFlow />
</ClerkLoaded>
</div>
</CheckoutProvider>
)
}import { useCheckout } from '@clerk/react/experimental'
import { useState } from 'react'
import { useNavigate } from 'react-router-dom'
export function CheckoutFlow() {
const { checkout } = useCheckout()
if (checkout.status === 'needs_initialization') {
return <CheckoutInitialization />
}
return (
<div className="checkout-container">
<CheckoutSummary />
<PaymentSection />
</div>
)
}
function CheckoutInitialization() {
const { checkout, fetchStatus } = useCheckout()
return (
<button onClick={() => checkout.start()} disabled={fetchStatus === 'fetching'}>
{fetchStatus === 'fetching' ? 'Initializing...' : 'Start Checkout'}
</button>
)
}
function PaymentSection() {
const { checkout, errors, fetchStatus } = useCheckout()
const [paymentMethodId, setPaymentMethodId] = useState<string | null>(null)
const navigate = useNavigate()
const submitSelectedMethod = async () => {
if (fetchStatus === 'fetching' || !paymentMethodId) return
try {
// Confirm checkout with payment method
const { error } = await checkout.confirm({
paymentMethodId,
})
if (error) {
console.error(JSON.stringify(error, null, 2))
return
}
// Calling `.finalize` enables you to sync the client-side state with the server-side state of your users.
// It revalidates all authorization checks computed within server components.
await checkout.finalize({
navigate: ({ decorateUrl }) => {
const url = decorateUrl('/')
if (url.startsWith('http')) {
window.location.href = url
} else {
navigate(url)
}
},
})
} catch (error) {
console.error('Payment failed:', error)
}
}
return (
<>
{/* A component that lists a user's payment methods and allows them to select one. See an example: https://clerk.com/docs/reference/hooks/use-payment-methods#examples */}
<PaymentMethods onChange={setPaymentMethodId} />
{errors.global && (
<ul>
{errors.global.map((error, index) => (
<li key={index}>{error.longMessage || error.message}</li>
))}
</ul>
)}
<button type="button" disabled={fetchStatus === 'fetching'} onClick={submitSelectedMethod}>
{fetchStatus === 'fetching' ? 'Processing...' : 'Complete Purchase'}
</button>
</>
)
}
function CheckoutSummary() {
const { checkout } = useCheckout()
return (
<div>
<h2>Order Summary</h2>
<span>{checkout.plan?.name}</span>
<span>
{checkout.totals?.totalDueNow.currencySymbol}
{checkout.totals?.totalDueNow.amountFormatted}
</span>
</div>
)
}For simple, self-contained components, you can use useCheckout() by passing the configuration options directly to the hook. This avoids the need to wrap the component in a provider.
The following example shows an <UpgradeButton /> component that manages its own checkout flow.
import { useCheckout } from '@clerk/react/experimental'
export function UpgradeButton({
planId,
planPeriod,
}: {
planId: string
planPeriod: 'month' | 'annual'
}) {
// Pass options directly to the hook when not using a provider.
const { checkout, errors, fetchStatus } = useCheckout({
planId,
planPeriod,
for: 'user',
})
const isStarting = fetchStatus === 'fetching'
const handleStartCheckout = async () => {
try {
const { error } = await checkout.start()
if (error) {
console.error(JSON.stringify(error, null, 2))
return
}
// In a real app, you would now use the `externalClientSecret`
// from the checkout object to render a payment form.
console.log('Checkout started! Status:', checkout.status)
} catch (e) {
console.error('Error starting checkout:', e)
}
}
return (
<div>
<button onClick={handleStartCheckout} disabled={isStarting}>
{isStarting ? 'Initializing...' : `Upgrade to ${planPeriod} plan`}
</button>
{errors.global && (
<ul>
{errors.global.map((error, index) => (
<li key={index}>{error.longMessage || error.message}</li>
))}
</ul>
)}
</div>
)
}Checkout flow with a new payment method
Build a custom checkout flow that allows users to add a new payment method during checkout.
Checkout flow for returning users
Build a custom checkout flow that allows users to select an existing payment method during checkout.
Feedback
Last updated on