useCheckout()
The useCheckout()
hook is used to create, manage, and confirm a checkout session for a user or an organization's subscription plan. The hook 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 useuseCheckout()
to access or update the same checkout state. - Using
useCheckout()
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.
- Name
options?
- Type
UseCheckoutOptions
- Description
An object containing the configuration for the checkout flow. This is required if the hook is used without a
<CheckoutProvider />
wrapping the component tree.
- Name
for?
- Type
'organization'
- Description
Specifies if the checkout is for an organization. If omitted, the checkout defaults to the current user.
- Name
planId
- Type
string
- Description
The ID of the subscription plan to check out (e.g.,
cplan_xxxx
).
- Name
planPeriod
- Type
'monthly' | 'yearly'
- Description
The billing period for the plan.
- Name
checkout
- Type
object
- Description
Specify the checkout resource properties, state helpers, and methods.
The checkout
object contains the following:
Resource properties
These properties describe the checkout resource itself. They are null
until the checkout process is started by calling the start()
method.
- Name
id
- Type
string | null
- Description
The unique identifier for the checkout resource.
- Name
paymentSource
- Type
object | null
- Description
The payment source being used for the checkout.
- Name
plan
- Type
object | null
- Description
The subscription plan details for the checkout.
- Name
externalClientSecret
- Type
string | null
- Description
The client secret from an external payment provider, like Stripe, used to complete the payment on the client-side.
- Name
planPeriod
- Type
'monthly' | 'yearly' | null
- Description
The billing period for the plan.
- Name
planPeriodStart
- Type
Date | null
- Description
The start date of the plan period.
- Name
totals
- Type
object | null
- Description
The total costs, taxes, and other pricing details.
- Name
isImmediatePlanChange
- Type
boolean | null
- Description
Indicates if the plan change will take effect immediately.
State helpers
These properties provide information about the current state of the hook's operations.
- Name
status
- Type
'idle' | 'starting' | 'confirming' | 'complete' | 'error'
- Description
The current status of the checkout flow.
- Name
isStarting
- Type
boolean
- Description
Returns
true
when thestart()
method is in progress.
- Name
isConfirming
- Type
boolean
- Description
Returns
true
when theconfirm()
method is in progress.
- Name
error
- Type
ClerkAPIResponseError | null
- Description
Returns an error object if any part of the checkout process fails.
- Name
fetchStatus
- Type
'idle' | 'fetching' | 'error'
- Description
The data fetching status for the checkout resource.
Methods
These methods are used to control the checkout flow.
- Name
start()
- Type
() => Promise<CommerceCheckoutResource>
- Description
Initializes the checkout process by creating a checkout resource on the server.
- Name
confirm()
- Type
(params: ConfirmCheckoutParams) => Promise<CommerceCheckoutResource>
- Description
Confirms the checkout, typically after the user has entered payment details.
- Name
complete()
- Type
(params?: { redirectUrl: string }) => void
- Description
Finalizes the checkout process. Can optionally accept a
redirectUrl
to navigate the user to upon completion.
- Name
clear()
- Type
() => void
- Description
Clears the current checkout state from the cache.
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.
Using the <CheckoutProvider />
is the recommended approach when checkout state needs to be shared across multiple components. The provider is configured once, and any child component can access the checkout context by calling useCheckout()
.
The following example shows a <SubscriptionPage />
that sets up the provider and a <CheckoutFlow />
component that consumes the context to manage the checkout UI.
import { CheckoutProvider } from '@clerk/clerk-react' // Fictional import path
import { CheckoutFlow } from './CheckoutFlow'
export function SubscriptionPage() {
// The provider sets the context for the checkout flow.
// Any child component can now call `useCheckout()` to access this context.
return (
<CheckoutProvider for="user" planId="cplan_123abc" planPeriod="monthly">
<div>
<h1>Upgrade Your Plan</h1>
<p>You are about to subscribe to our monthly plan.</p>
<CheckoutFlow />
</div>
</CheckoutProvider>
)
}
import { useCheckout } from '@clerk/clerk-react' // Fictional import path
export function CheckoutFlow() {
// `useCheckout` reads context from the nearest `<CheckoutProvider />`
const { checkout } = useCheckout()
const { start, status, isStarting, error } = checkout
const handleStartCheckout = async () => {
try {
// This will create the checkout session on the backend
await start()
// Next steps would involve using a payment element (e.g., Stripe)
// and then calling `checkout.confirm()` and `checkout.complete()`.
} catch (e) {
console.error('Error starting checkout:', e)
}
}
return (
<div>
<p>Current status: {status}</p>
<button onClick={handleStartCheckout} disabled={isStarting}>
{isStarting ? 'Starting...' : 'Proceed to Payment'}
</button>
{error && <p style={{ color: 'red' }}>Error: {error.errors[0].message}</p>}
{status === 'starting' && <p>Redirecting to payment...</p>}
</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/clerk-react' // Fictional import path
export function UpgradeButton({ planId, planPeriod }) {
// Pass options directly to the hook when not using a provider.
const { checkout } = useCheckout({
planId,
planPeriod,
for: 'user',
})
const { start, status, isStarting, error } = checkout
const handleStartCheckout = async () => {
try {
await start()
// 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>
{error && <p style={{ color: 'red' }}>Error: {error.errors[0].message}</p>}
</div>
)
}
Checkout flow with a new payment method
Prompt users to add a new payment method during checkout
Checkout flow for returning users
Prompt users to select an existing payment method during checkout
Feedback
Last updated on