Version 2025-07 is the last API version to support React-based UI components. Later versions use web components, native UI elements with built-in accessibility, better performance, and consistent styling with Shopify's design system. Check out the migration guide to upgrade your extension.
Buyer Journey API
The API for interacting with the buyer journey.
Anchor to standardapiStandardApi
The base API object provided to purchase extension targets.
- Anchor to buyerJourneybuyerJourneybuyerJourneyBuyerJourneyBuyerJourneyrequiredrequired
Provides details on the buyer's progression through the checkout.
Refer to buyer journey examples for more information.
BuyerJourney
Provides details on the buyer's progression through the checkout.
- activeStep
What step of checkout the buyer is currently on.
StatefulRemoteSubscribable<BuyerJourneyStepReference | undefined> - completed
This subscribable value will be true if the buyer completed submitting their order. For example, when viewing the **Order status** page after submitting payment, the buyer will have completed their order.
StatefulRemoteSubscribable<boolean> - intercept
Installs a function for intercepting and preventing progress on checkout. This returns a promise that resolves to a teardown function. Calling the teardown function will remove the interceptor. To block checkout progress, you must set the [block_progress](/docs/api/checkout-ui-extensions/configuration#block-progress) capability in your extension's configuration. If you do, then you're expected to inform the buyer why navigation was blocked, either by passing validation errors to the checkout UI or rendering the errors in your extension. It is good practice to show a warning in the checkout editor when the merchant has not given permission for your extension to block checkout progress.
(interceptor: Interceptor) => Promise<() => void> - steps
All possible steps a buyer can take to complete the checkout. These steps may vary depending on the type of checkout or the shop's configuration.
StatefulRemoteSubscribable<BuyerJourneyStep[]>
BuyerJourneyStepReference
What step of checkout the buyer is currently on.
- handle
The handle that uniquely identifies the buyer journey step.
BuyerJourneyStepHandle
BuyerJourneyStepHandle
| handle | Description | |---|---| | `cart` | The cart page. | | `checkout` | A one-page checkout, including Shop Pay. | | `information` | The contact information step of a three-page checkout. | | `shipping` | The shipping step of a three-page checkout. | | `payment` | The payment step of a three-page checkout. | | `review` | The step after payment where the buyer confirms the purchase. Not all shops are configured to have a review step. | | `thank-you` | The page displayed after the purchase, thanking the buyer. | | `unknown` | An unknown step in the buyer journey. |
'cart' | 'checkout' | 'information' | 'shipping' | 'payment' | 'review' | 'thank-you' | 'unknown'Interceptor
A function for intercepting and preventing navigation on checkout. You can block navigation by returning an object with `{behavior: 'block', reason: InvalidResultReason.InvalidExtensionState, errors?: ValidationErrors[]}`. If you do, then you're expected to also update some part of your UI to reflect the reason why navigation was blocked, either by targeting checkout UI fields, passing errors to the page level or rendering the errors in your extension.
- interceptorProps
InterceptorProps
InterceptorRequest | Promise<InterceptorRequest>InterceptorProps
- canBlockProgress
Whether the interceptor has the capability to block a buyer's progress through checkout. This ability might be granted by a merchant in differing checkout contexts.
boolean
InterceptorRequest
InterceptorRequestAllow | InterceptorRequestBlockInterceptorRequestAllow
- behavior
Indicates that the interceptor will allow the buyer's journey to continue.
'allow' - perform
This callback is called when all interceptors finish. We recommend setting errors or reasons for blocking at this stage, so that all the errors in the UI show up at once.
(result: InterceptorResult) => void | Promise<void>
InterceptorResult
InterceptorResultAllow | InterceptorResultBlockInterceptorResultAllow
- behavior
Indicates that the buyer was allowed to progress through checkout.
'allow'
InterceptorResultBlock
- behavior
Indicates that some part of the checkout UI intercepted and prevented the buyer’s progress. The buyer typically needs to take some action to resolve this issue and to move on to the next step.
'block'
InterceptorRequestBlock
- behavior
Indicates that the interceptor will block the buyer's journey from continuing.
'block' - errors
Used to pass errors to the checkout UI, outside your extension's UI boundaries.
ValidationError[] - perform
This callback is called when all interceptors finish. We recommend setting errors or reasons for blocking at this stage, so that all the errors in the UI show up at once.
(result: InterceptorResult) => void | Promise<void> - reason
The reason for blocking the interceptor request. This value isn't presented to the buyer, so it doesn't need to be localized. The value is used only for Shopify’s own internal debugging and metrics.
string
ValidationError
- message
Error message to be displayed to the buyer.
string - target
The checkout UI field that the error is associated with. Example: `$.cart.deliveryGroups[0].deliveryAddress.countryCode` See the [supported targets](/docs/api/functions/reference/cart-checkout-validation/graphql#supported-targets) for more information.
string
BuyerJourneyStep
- disabled
The disabled state of the buyer journey step. This value will be true if the buyer has not reached the step yet. For example, if the buyer has not reached the `shipping` step yet, `shipping` would be disabled.
boolean - handle
The handle that uniquely identifies the buyer journey step.
BuyerJourneyStepHandle - label
The localized label of the buyer journey step.
string - to
The url of the buyer journey step. This property leverages the `shopify:` protocol E.g. `shopify:cart` or `shopify:checkout/information`.
string
Anchor to useBuyerJourneyuse Buyer Journey()
Returns the buyerJourney details on buyer progression in checkout.
- activeStepactiveStepStatefulRemoteSubscribable<BuyerJourneyStepReference | undefined>StatefulRemoteSubscribable<BuyerJourneyStepReference | undefined>
What step of checkout the buyer is currently on.
- completedcompletedStatefulRemoteSubscribable<boolean>StatefulRemoteSubscribable<boolean>
This subscribable value will be true if the buyer completed submitting their order.
For example, when viewing the Order status page after submitting payment, the buyer will have completed their order.
- interceptintercept(interceptor: Interceptor) => Promise<() => void>(interceptor: Interceptor) => Promise<() => void>
Installs a function for intercepting and preventing progress on checkout.
This returns a promise that resolves to a teardown function. Calling the teardown function will remove the interceptor.
To block checkout progress, you must set the block_progress capability in your extension's configuration.
If you do, then you're expected to inform the buyer why navigation was blocked, either by passing validation errors to the checkout UI or rendering the errors in your extension.
It is good practice to show a warning in the checkout editor when the merchant has not given permission for your extension to block checkout progress.
- stepsstepsStatefulRemoteSubscribable<BuyerJourneyStep[]>StatefulRemoteSubscribable<BuyerJourneyStep[]>
All possible steps a buyer can take to complete the checkout. These steps may vary depending on the type of checkout or the shop's configuration.
BuyerJourney
Provides details on the buyer's progression through the checkout.
BuyerJourney
Provides details on the buyer's progression through the checkout.
- activeStep
What step of checkout the buyer is currently on.
StatefulRemoteSubscribable<BuyerJourneyStepReference | undefined> - completed
This subscribable value will be true if the buyer completed submitting their order. For example, when viewing the **Order status** page after submitting payment, the buyer will have completed their order.
StatefulRemoteSubscribable<boolean> - intercept
Installs a function for intercepting and preventing progress on checkout. This returns a promise that resolves to a teardown function. Calling the teardown function will remove the interceptor. To block checkout progress, you must set the [block_progress](/docs/api/checkout-ui-extensions/configuration#block-progress) capability in your extension's configuration. If you do, then you're expected to inform the buyer why navigation was blocked, either by passing validation errors to the checkout UI or rendering the errors in your extension. It is good practice to show a warning in the checkout editor when the merchant has not given permission for your extension to block checkout progress.
(interceptor: Interceptor) => Promise<() => void> - steps
All possible steps a buyer can take to complete the checkout. These steps may vary depending on the type of checkout or the shop's configuration.
StatefulRemoteSubscribable<BuyerJourneyStep[]>
BuyerJourneyStepReference
What step of checkout the buyer is currently on.
- handle
The handle that uniquely identifies the buyer journey step.
BuyerJourneyStepHandle
BuyerJourneyStepHandle
| handle | Description | |---|---| | `cart` | The cart page. | | `checkout` | A one-page checkout, including Shop Pay. | | `information` | The contact information step of a three-page checkout. | | `shipping` | The shipping step of a three-page checkout. | | `payment` | The payment step of a three-page checkout. | | `review` | The step after payment where the buyer confirms the purchase. Not all shops are configured to have a review step. | | `thank-you` | The page displayed after the purchase, thanking the buyer. | | `unknown` | An unknown step in the buyer journey. |
'cart' | 'checkout' | 'information' | 'shipping' | 'payment' | 'review' | 'thank-you' | 'unknown'Interceptor
A function for intercepting and preventing navigation on checkout. You can block navigation by returning an object with `{behavior: 'block', reason: InvalidResultReason.InvalidExtensionState, errors?: ValidationErrors[]}`. If you do, then you're expected to also update some part of your UI to reflect the reason why navigation was blocked, either by targeting checkout UI fields, passing errors to the page level or rendering the errors in your extension.
- interceptorProps
InterceptorProps
InterceptorRequest | Promise<InterceptorRequest>InterceptorProps
- canBlockProgress
Whether the interceptor has the capability to block a buyer's progress through checkout. This ability might be granted by a merchant in differing checkout contexts.
boolean
InterceptorRequest
InterceptorRequestAllow | InterceptorRequestBlockInterceptorRequestAllow
- behavior
Indicates that the interceptor will allow the buyer's journey to continue.
'allow' - perform
This callback is called when all interceptors finish. We recommend setting errors or reasons for blocking at this stage, so that all the errors in the UI show up at once.
(result: InterceptorResult) => void | Promise<void>
InterceptorResult
InterceptorResultAllow | InterceptorResultBlockInterceptorResultAllow
- behavior
Indicates that the buyer was allowed to progress through checkout.
'allow'
InterceptorResultBlock
- behavior
Indicates that some part of the checkout UI intercepted and prevented the buyer’s progress. The buyer typically needs to take some action to resolve this issue and to move on to the next step.
'block'
InterceptorRequestBlock
- behavior
Indicates that the interceptor will block the buyer's journey from continuing.
'block' - errors
Used to pass errors to the checkout UI, outside your extension's UI boundaries.
ValidationError[] - perform
This callback is called when all interceptors finish. We recommend setting errors or reasons for blocking at this stage, so that all the errors in the UI show up at once.
(result: InterceptorResult) => void | Promise<void> - reason
The reason for blocking the interceptor request. This value isn't presented to the buyer, so it doesn't need to be localized. The value is used only for Shopify’s own internal debugging and metrics.
string
ValidationError
- message
Error message to be displayed to the buyer.
string - target
The checkout UI field that the error is associated with. Example: `$.cart.deliveryGroups[0].deliveryAddress.countryCode` See the [supported targets](/docs/api/functions/reference/cart-checkout-validation/graphql#supported-targets) for more information.
string
BuyerJourneyStep
- disabled
The disabled state of the buyer journey step. This value will be true if the buyer has not reached the step yet. For example, if the buyer has not reached the `shipping` step yet, `shipping` would be disabled.
boolean - handle
The handle that uniquely identifies the buyer journey step.
BuyerJourneyStepHandle - label
The localized label of the buyer journey step.
string - to
The url of the buyer journey step. This property leverages the `shopify:` protocol E.g. `shopify:cart` or `shopify:checkout/information`.
string
Anchor to useBuyerJourneyCompleteduse Buyer Journey Completed()
Returns true if the buyer completed submitting their order.
For example, when viewing the Order status page after submitting payment, the buyer will have completed their order.
Installs a function for intercepting and preventing progress on checkout.
To block checkout progress, you must set the block_progress capability in your extension's configuration.
If you do, then you're expected to inform the buyer why navigation was blocked, either by passing validation errors to the checkout UI or rendering the errors in your extension.
should be called at the top level of the extension, not within an embedded or child component, to avoid errors should the child component get destroyed.
It is good practice to show a warning in the checkout editor when the merchant has not given permission for your extension to block checkout progress.
- Anchor to interceptorinterceptorinterceptorInterceptorInterceptorrequiredrequired
Anchor to useBuyerJourneyIntercept-returnsReturnsvoidvoid
Interceptor
A function for intercepting and preventing navigation on checkout. You can block navigation by returning an object with `{behavior: 'block', reason: InvalidResultReason.InvalidExtensionState, errors?: ValidationErrors[]}`. If you do, then you're expected to also update some part of your UI to reflect the reason why navigation was blocked, either by targeting checkout UI fields, passing errors to the page level or rendering the errors in your extension.
- interceptorProps
InterceptorProps
InterceptorRequest | Promise<InterceptorRequest>InterceptorProps
- canBlockProgress
Whether the interceptor has the capability to block a buyer's progress through checkout. This ability might be granted by a merchant in differing checkout contexts.
boolean
InterceptorRequest
InterceptorRequestAllow | InterceptorRequestBlockInterceptorRequestAllow
- behavior
Indicates that the interceptor will allow the buyer's journey to continue.
'allow' - perform
This callback is called when all interceptors finish. We recommend setting errors or reasons for blocking at this stage, so that all the errors in the UI show up at once.
(result: InterceptorResult) => void | Promise<void>
InterceptorResult
InterceptorResultAllow | InterceptorResultBlockInterceptorResultAllow
- behavior
Indicates that the buyer was allowed to progress through checkout.
'allow'
InterceptorResultBlock
- behavior
Indicates that some part of the checkout UI intercepted and prevented the buyer’s progress. The buyer typically needs to take some action to resolve this issue and to move on to the next step.
'block'
InterceptorRequestBlock
- behavior
Indicates that the interceptor will block the buyer's journey from continuing.
'block' - errors
Used to pass errors to the checkout UI, outside your extension's UI boundaries.
ValidationError[] - perform
This callback is called when all interceptors finish. We recommend setting errors or reasons for blocking at this stage, so that all the errors in the UI show up at once.
(result: InterceptorResult) => void | Promise<void> - reason
The reason for blocking the interceptor request. This value isn't presented to the buyer, so it doesn't need to be localized. The value is used only for Shopify’s own internal debugging and metrics.
string
ValidationError
- message
Error message to be displayed to the buyer.
string - target
The checkout UI field that the error is associated with. Example: `$.cart.deliveryGroups[0].deliveryAddress.countryCode` See the [supported targets](/docs/api/functions/reference/cart-checkout-validation/graphql#supported-targets) for more information.
string
Anchor to useBuyerJourneyStepsuse Buyer Journey Steps()
Returns all possible steps a buyer can take to complete the checkout. These steps may vary depending on the type of checkout or the shop's configuration.
BuyerJourneyStep
- disabled
The disabled state of the buyer journey step. This value will be true if the buyer has not reached the step yet. For example, if the buyer has not reached the `shipping` step yet, `shipping` would be disabled.
boolean - handle
The handle that uniquely identifies the buyer journey step.
BuyerJourneyStepHandle - label
The localized label of the buyer journey step.
string - to
The url of the buyer journey step. This property leverages the `shopify:` protocol E.g. `shopify:cart` or `shopify:checkout/information`.
string
BuyerJourneyStepHandle
| handle | Description | |---|---| | `cart` | The cart page. | | `checkout` | A one-page checkout, including Shop Pay. | | `information` | The contact information step of a three-page checkout. | | `shipping` | The shipping step of a three-page checkout. | | `payment` | The payment step of a three-page checkout. | | `review` | The step after payment where the buyer confirms the purchase. Not all shops are configured to have a review step. | | `thank-you` | The page displayed after the purchase, thanking the buyer. | | `unknown` | An unknown step in the buyer journey. |
'cart' | 'checkout' | 'information' | 'shipping' | 'payment' | 'review' | 'thank-you' | 'unknown'Anchor to useBuyerJourneyActiveStepuse Buyer Journey Active Step()
Returns the buyer journey step that the buyer is currently on.
BuyerJourneyStep
- disabled
The disabled state of the buyer journey step. This value will be true if the buyer has not reached the step yet. For example, if the buyer has not reached the `shipping` step yet, `shipping` would be disabled.
boolean - handle
The handle that uniquely identifies the buyer journey step.
BuyerJourneyStepHandle - label
The localized label of the buyer journey step.
string - to
The url of the buyer journey step. This property leverages the `shopify:` protocol E.g. `shopify:cart` or `shopify:checkout/information`.
string
BuyerJourneyStepHandle
| handle | Description | |---|---| | `cart` | The cart page. | | `checkout` | A one-page checkout, including Shop Pay. | | `information` | The contact information step of a three-page checkout. | | `shipping` | The shipping step of a three-page checkout. | | `payment` | The payment step of a three-page checkout. | | `review` | The step after payment where the buyer confirms the purchase. Not all shops are configured to have a review step. | | `thank-you` | The page displayed after the purchase, thanking the buyer. | | `unknown` | An unknown step in the buyer journey. |
'cart' | 'checkout' | 'information' | 'shipping' | 'payment' | 'review' | 'thank-you' | 'unknown'Examples
Block progress and show error for a checkout UI field
Description
Intercept and prevent a buyer's progress through checkout while targeting a specific checkout UI field. See the [validation tutorial](/docs/apps/checkout/validation) for more examples and best practices.
React
import { reactExtension, Banner, useBuyerJourneyIntercept, useExtensionCapability, useExtensionEditor, useShippingAddress, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.delivery-address.render-before', () => <Extension />, ); function Extension() { const address = useShippingAddress(); const editorType = useExtensionEditor()?.type; const blockProgressGranted = useExtensionCapability('block_progress'); useBuyerJourneyIntercept( ({canBlockProgress}) => { return canBlockProgress && address?.countryCode && address.countryCode !== 'CA' ? { behavior: 'block', reason: 'Invalid shipping country', errors: [ { message: 'Sorry, we can only ship to Canada', // Show an error underneath the country code field target: '$.cart.deliveryGroups[0].deliveryAddress.countryCode', }, { // In addition, show an error at the page level message: 'Please use a different address.', }, ], } : { behavior: 'allow', }; }, ); return editorType === 'checkout' && !blockProgressGranted ? ( <Banner status="warning" title="This app may be misconfigured" > To allow this app to block checkout, enable this behavior in "Checkout behavior" settings. </Banner> ) : null; }JavaScript
import { extension, Banner, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.delivery-address.render-before', ( root, {buyerJourney, extension, shippingAddress}, ) => { const banner = root.createComponent( Banner, { status: 'warning', title: 'This app may be misconfigured', }, `To allow this app to block checkout, enable this behavior in "Checkout behavior" settings.`, ); const editorType = extension.editor.type; let address = shippingAddress?.current; shippingAddress?.subscribe((newAddress) => { address = newAddress; }); let blockProgressGranted = extension.capabilities.current.find( (capability) => capability === 'block_progress', ); extension.capabilities.subscribe( (newCapabilities) => { blockProgressGranted = newCapabilities.find( (capability) => capability === 'block_progress', ); if ( editorType === 'checkout' && !blockProgressGranted ) { root.appendChild(banner); } else { root.removeChild(banner); } }, ); buyerJourney.intercept( ({canBlockProgress}) => { return canBlockProgress && address?.countryCode && address.countryCode !== 'CA' ? { behavior: 'block', reason: 'Invalid shipping country', errors: [ { message: 'Sorry, we can only ship to Canada', // Show an error underneath the country code field target: '$.cart.deliveryGroups[0].deliveryAddress.countryCode', }, { // In addition, show an error at the page level message: 'Please use a different address.', }, ], } : { behavior: 'allow', }; }, ); }, );Block progress and show error at page level
Description
Intercept and prevent a buyer's progress through checkout while displaying an error message at the page level. See the [validation tutorial](/docs/apps/checkout/validation) for more examples and best practices.
React
import { reactExtension, Banner, useBuyerJourneyIntercept, useExtensionCapability, useExtensionEditor, useShippingAddress, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.delivery-address.render-before', () => <Extension />, ); function Extension() { const address = useShippingAddress(); const editorType = useExtensionEditor()?.type; const blockProgressGranted = useExtensionCapability('block_progress'); useBuyerJourneyIntercept( ({canBlockProgress}) => { return canBlockProgress && address?.countryCode && address.countryCode !== 'CA' ? { behavior: 'block', reason: 'Invalid shipping country', errors: [ { // An error without a `target` property is shown at page level message: 'Sorry, we can only ship to Canada', }, ], } : { behavior: 'allow', }; }, ); return editorType === 'checkout' && !blockProgressGranted ? ( <Banner status="warning" title="This app may be misconfigured" > To allow this app to block checkout, enable this behavior in "Checkout behavior" settings. </Banner> ) : null; }JavaScript
import { extension, Banner, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.delivery-address.render-before', ( root, {buyerJourney, extension, shippingAddress}, ) => { const banner = root.createComponent( Banner, { status: 'warning', title: 'This app may be misconfigured', }, `To allow this app to block checkout, enable this behavior in "Checkout behavior" settings.`, ); const editorType = extension.editor.type; let address = shippingAddress?.current; shippingAddress?.subscribe((newAddress) => { address = newAddress; }); let blockProgressGranted = extension.capabilities.current.find( (capability) => capability === 'block_progress', ); extension.capabilities.subscribe( (newCapabilities) => { blockProgressGranted = newCapabilities.find( (capability) => capability === 'block_progress', ); if ( editorType === 'checkout' && !blockProgressGranted ) { root.appendChild(banner); } else { root.removeChild(banner); } }, ); buyerJourney.intercept( ({canBlockProgress}) => { return canBlockProgress && address?.countryCode && address.countryCode !== 'CA' ? { behavior: 'block', reason: 'Invalid shipping country', errors: [ { // An error without a `target` property is shown at page level message: 'Sorry, we can only ship to Canada', }, ], } : { behavior: 'allow', }; }, ); }, );Block progress and show error in your extension
Description
Intercept and prevent a buyer's progress through checkout while displaying an error message in your extension. See the [validation tutorial](/docs/apps/checkout/validation) for more examples and best practices.
React
import {useState} from 'react'; import { reactExtension, Banner, useBuyerJourneyIntercept, useCartLineTarget, useExtensionCapability, useExtensionEditor, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.cart-line-item.render-after', () => <Extension />, ); function Extension() { const [showError, setShowError] = useState(false); const {quantity} = useCartLineTarget(); const editorType = useExtensionEditor()?.type; const blockProgressGranted = useExtensionCapability('block_progress'); useBuyerJourneyIntercept( ({canBlockProgress}) => { return canBlockProgress && quantity > 1 ? { behavior: 'block', reason: 'limited stock', perform: (result) => { if (result.behavior === 'block') { setShowError(true); } }, } : { behavior: 'allow', perform: () => { setShowError(false); }, }; }, ); return ( <> {editorType === 'checkout' && !blockProgressGranted ? ( <Banner status="warning" title="This app may be misconfigured" > To allow this app to block checkout, enable this behavior in "Checkout behavior" settings. </Banner> ) : null} {showError ? ( <Banner> This item has a limit of one per customer. </Banner> ) : null} </> ); }JavaScript
import { extension, Banner, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.cart-line-item.render-after', (root, {buyerJourney, extension, target}) => { const orderLimitBanner = root.createComponent(Banner); const configBanner = root.createComponent( Banner, { status: 'warning', title: 'This app may be misconfigured', }, `To allow this app to block checkout, enable this behavior in "Checkout behavior" settings.`, ); let quantity = target.current.quantity; let blockProgressGranted = extension.capabilities.current.find( (capability) => capability === 'block_progress', ); const editorType = extension.editor.type; target?.subscribe((newTarget) => { quantity = newTarget.quantity; }); extension.capabilities.subscribe( (newCapabilities) => { blockProgressGranted = newCapabilities.find( (capability) => capability === 'block_progress', ); if ( editorType === 'checkout' && !blockProgressGranted ) { root.appendChild(configBanner); } else { root.removeChild(configBanner); } }, ); buyerJourney.intercept( ({canBlockProgress}) => { return canBlockProgress && quantity > 1 ? { behavior: 'block', reason: 'limited stock', perform: (result) => { if (result.behavior === 'block') { orderLimitBanner.appendChild( 'This item has a limit of one per customer.', ); root.appendChild( orderLimitBanner, ); } }, } : { behavior: 'allow', perform: () => { root.removeChild( orderLimitBanner, ); }, }; }, ); }, );