šŸ“ Sign Up | šŸ” Log In

← Root | ↑ Up

ā”Œā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā” │ šŸ“„ shadcn/directory/clerk/clerk-docs/reference/hooks/use-checkout │ ā””ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”€ā”˜

╔══════════════════════════════════════════════════════════════════════════════════════════════╗
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘

title: 'useCheckout()' description: Clerk's useCheckout() hook provides state and methods to manage a subscription checkout flow. sdk: nextjs, react

<Include src="_partials/billing/billing-experimental" />

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():

  1. 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.
  2. 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

useCheckout() accepts a single object with the following properties:

<Properties> - `options?` - [`UseCheckoutOptions`](#use-checkout-options)

An object containing the configuration for the checkout flow.

Required if the hook is used without a <CheckoutProvider /> wrapping the component tree. </Properties>

UseCheckoutOptions

<Include src="_partials/billing/use-checkout-options" />

Returns

useCheckout() returns a { checkout } object. The checkout object contains the following properties. They are null until the checkout process is started by calling the start() method.

<Properties> - `id` - `string | null`

The unique identifier for the checkout session.


  • externalClientSecret
  • string | null

The client secret from an external payment provider (such as Stripe) used to complete the payment on the client-side.


  • externalGatewayId
  • string | null

The identifier for the external payment gateway used for the checkout session.


The payment source being used for the checkout.


The subscription plan details for the checkout.


  • planPeriod
  • 'month' | 'annual' | null

The billing period for the plan.


  • planPeriodStart
  • number | undefined

The start date of the plan period, represented as a Unix timestamp.


  • status
  • 'needs_initialization' | 'needs_confirmation' | 'completed'

The current status of the checkout session. The following statuses are possible:

  • needs_initialization: The checkout hasn't started but the hook is mounted. Call start() to continue.
  • needs_confirmation: The checkout has been initialized and is awaiting confirmation. Call confirm() to continue.
  • completed: The checkout has been successfully confirmed. Call finalize() to complete the checkout.

The total costs, taxes, and other pricing details.


  • isImmediatePlanChange
  • boolean

A boolean that indicates if the plan change will take effect immediately.


  • isStarting
  • boolean

A boolean that indicates if the start() method is in progress.


  • isConfirming
  • boolean

A boolean that indicates if the confirm() method is in progress.


Returns an error object if any part of the checkout process fails.


  • fetchStatus
  • 'idle' | 'fetching' | 'error'

The data fetching status.


  • start()
  • () => Promise<{ data: BillingCheckoutResource; error: null; } | { data: null; error: ClerkAPIResponseError; }>

A function that initializes the checkout process by creating a checkout resource on the server.


  • confirm()
  • (params: ConfirmCheckoutParams) => Promise<{ data: BillingCheckoutResource; error: null; } | { data: null; error: ClerkAPIResponseError; }>

A function that confirms and finalizes the checkout process, usually after the user has provided and validated payment information.


  • finalize()
  • (params?: { navigate?: SetActiveNavigate }) => void

A function that finalizes the checkout process. Can optionally accept a navigate() function to redirect the user after completion.


  • clear()
  • () => void

A function that clears the current checkout state from the cache. </Properties>

<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

<Include src="_partials/billing/use-checkout-options" />

Usage

For the best user experience and to prevent potential errors, always wrap components using useCheckout() with both <ClerkLoaded> and <SignedIn> components. This ensures that the user is properly authenticated and Clerk is fully initialized before accessing checkout functionality.

function CheckoutPage() {
  return (
    <ClerkLoaded>
      <SignedIn>
        <YourCheckoutComponent />
      </SignedIn>
    </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.

<Tabs items={["With <CheckoutProvider />", "Standalone Hook"]}> <Tab> 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.

<Tabs items={["<SubscriptionPage />", "<CheckoutFlow />"]}>
  <Tab>
    ```tsx {{ filename: 'src/components/SubscriptionPage.tsx', collapsible: true }}
    import { CheckoutProvider } from '@clerk/nextjs/experimental'
    import { ClerkLoaded } from '@clerk/nextjs'
    import { CheckoutFlow } from './CheckoutFlow'

    export function SubscriptionPage() {
      // `<CheckoutProvider />` sets the context for the checkout flow.
      // Any child component can now call `useCheckout()` to access this context.
      return (
        <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>
      )
    }
    ```
  </Tab>

  <Tab>
    ```tsx {{ filename: 'src/components/CheckoutFlow.tsx', collapsible: true }}
    'use client'

    import { useCheckout } from '@clerk/nextjs/experimental'
    import { useRouter } from 'next/navigation'

    export function CheckoutFlow() {
      const { checkout } = useCheckout()
      const { status } = checkout

      if (status === 'needs_initialization') {
        return <CheckoutInitialization />
      }

      return (
        <div className="checkout-container">
          <CheckoutSummary />
          <PaymentSection />
        </div>
      )
    }

    function CheckoutInitialization() {
      const { checkout } = useCheckout()
      const { start, fetchStatus } = checkout

      return (
        <button onClick={start} disabled={fetchStatus === 'fetching'} className="start-checkout-button">
          {fetchStatus === 'fetching' ? 'Initializing...' : 'Start Checkout'}
        </button>
      )
    }

    function PaymentSection() {
      const { checkout } = useCheckout()

      const { isConfirming, confirm, finalize, error } = checkout

      const [isProcessing, setIsProcessing] = useState(false)
      const [paymentMethodId, setPaymentMethodId] = useState<string | null>(null)

      const router = useRouter()

      const submitSelectedMethod = async () => {
        if (isProcessing || !paymentMethodId) return
        setIsProcessing(true)

        try {
          // Confirm checkout with payment method
          await confirm({
            paymentSourceId: paymentMethodId,
          })
          // 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 finalize({
            navigate: () => router.push('/dashboard'),
          })
        } catch (error) {
          console.error('Payment failed:', error)
        } finally {
          setIsProcessing(false)
        }
      }

      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} />

          {error && <div>{error.message}</div>}

          <button type="button" disabled={isProcessing || isConfirming} onClick={submitSelectedMethod}>
            {isProcessing || isConfirming ? 'Processing...' : 'Complete Purchase'}
          </button>
        </>
      )
    }

    function CheckoutSummary() {
      const { checkout } = useCheckout()
      const { plan, totals } = checkout

      return (
        <div>
          <h2>Order Summary</h2>
          <span>{plan?.name}</span>
          <span>
            {totals?.totalDueNow.currencySymbol}
            {totals?.totalDueNow.amountFormatted}
          </span>
        </div>
      )
    }
    ```
  </Tab>
</Tabs>
</Tab> <Tab> 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.

```tsx {{ filename: 'src/components/UpgradeButton.tsx' }}
'use client'

import { useCheckout } from '@clerk/nextjs/experimental'

export function UpgradeButton({
  planId,
  planPeriod,
}: {
  planId: string
  planPeriod: 'month' | 'annual'
}) {
  // 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>
  )
}
```
</Tab> </Tabs>

Related guides

<Cards> - [Checkout flow with a new payment method](/docs/guides/development/custom-flows/billing/checkout-new-payment-method) - Prompt users to add a new payment method during checkout
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•‘
ā•šā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•ā•

← Root | ↑ Up