# Buyer Journey The API for interacting with the buyer journey. ```jsx import { reactExtension, useBuyerJourneyIntercept, useShippingAddress, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.delivery-address.render-before', () => <Extension />, ); function Extension() { const address = useShippingAddress(); 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 null; } ``` ```js import {extension} from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.delivery-address.render-before', (root, {buyerJourney, shippingAddress}) => { let address = shippingAddress?.current; shippingAddress?.subscribe((newAddress) => { address = newAddress; }); 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', }; }, ); }, ); ``` ## StandardApi The base API object provided to `purchase` extension targets. ### Docs_Standard_BuyerJourneyApi ### buyerJourney value: `BuyerJourney` Provides details on the buyer's progression through the checkout. Refer to [buyer journey](https://shopify.dev/docs/api/checkout-ui-extensions/apis/buyer-journey#examples) examples for more information. ### BuyerJourney Provides details on the buyer's progression through the checkout. ### activeStep value: `StatefulRemoteSubscribable<BuyerJourneyStepReference | undefined>` What step of checkout the buyer is currently on. ### completed value: `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. ### intercept value: `(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](https://shopify.dev/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. ### steps value: `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. ### BuyerJourneyStepReference What step of checkout the buyer is currently on. ### handle value: `BuyerJourneyStepHandle` The handle that uniquely identifies the buyer journey step. ### 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. #### Returns: InterceptorRequest | Promise<InterceptorRequest> #### Params: - interceptorProps: InterceptorProps export type Interceptor = ( interceptorProps: InterceptorProps, ) => InterceptorRequest | Promise<InterceptorRequest>; ### InterceptorProps ### canBlockProgress value: `boolean` 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. ### InterceptorRequestAllow ### behavior value: `"allow"` Indicates that the interceptor will allow the buyer's journey to continue. ### perform value: `(result: InterceptorResult) => void | Promise<void>` 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. ### InterceptorResultAllow ### behavior value: `"allow"` Indicates that the buyer was allowed to progress through checkout. ### InterceptorResultBlock ### behavior value: `"block"` 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. ### InterceptorRequestBlock ### behavior value: `"block"` Indicates that the interceptor will block the buyer's journey from continuing. ### errors value: `ValidationError[]` Used to pass errors to the checkout UI, outside your extension's UI boundaries. ### perform value: `(result: InterceptorResult) => void | Promise<void>` 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. ### reason value: `string` 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. ### ValidationError ### message value: `string` Error message to be displayed to the buyer. ### target value: `string` The checkout UI field that the error is associated with. Example: `$.cart.deliveryGroups[0].deliveryAddress.countryCode` See the [supported targets](https://shopify.dev/docs/api/functions/reference/cart-checkout-validation/graphql#supported-targets) for more information. ### BuyerJourneyStep ### disabled value: `boolean` 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. ### handle value: `BuyerJourneyStepHandle` The handle that uniquely identifies the buyer journey step. ### label value: `string` The localized label of the buyer journey step. ### to value: `string` The url of the buyer journey step. This property leverages the `shopify:` protocol E.g. `shopify:cart` or `shopify:checkout/information`. ## Related - [Validating fields at checkout](https://shopify.dev/docs/apps/checkout/validation/fields) - [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets) - [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components) - [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration) - [Tutorials](/apps/checkout) ## Examples The API for interacting with the buyer journey. Intercept and prevent a buyer's progress through checkout while displaying an error message at the page level. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import { reactExtension, useBuyerJourneyIntercept, useShippingAddress, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.delivery-address.render-before', () => <Extension />, ); function Extension() { const address = useShippingAddress(); 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 null; } ``` ```js import {extension} from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.delivery-address.render-before', (root, {buyerJourney, shippingAddress}) => { let address = shippingAddress?.current; shippingAddress?.subscribe((newAddress) => { address = newAddress; }); 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', }; }, ); }, ); ``` Intercept and prevent a buyer's progress through checkout while displaying an error message in your extension. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import {useState} from 'react'; import { reactExtension, Banner, useBuyerJourneyIntercept, useCartLineTarget, } 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(); 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 showError ? ( <Banner> This item has a limit of one per customer. </Banner> ) : null; } ``` ```js import { extension, Banner, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.cart-line-item.render-after', (root, {buyerJourney, target}) => { const banner = root.createComponent(Banner); let quantity = target.current.quantity; target?.subscribe((newTarget) => { quantity = newTarget.quantity; }); buyerJourney.intercept( ({canBlockProgress}) => { return canBlockProgress && quantity > 1 ? { behavior: 'block', reason: 'limited stock', perform: (result) => { if (result.behavior === 'block') { banner.appendChild( 'This item has a limit of one per customer.', ); root.appendChild(banner); } }, } : { behavior: 'allow', perform: () => { root.removeChild(banner); }, }; }, ); }, ); ``` ## useBuyerJourney Returns the buyerJourney details on buyer progression in checkout. ### UseBuyerJourneyGeneratedType Returns the `buyerJourney` details on buyer progression in checkout. #### Returns: BuyerJourney export function useBuyerJourney< Target extends RenderExtensionTarget = RenderExtensionTarget, >(): BuyerJourney { const api = useApi<Target>(); return api.buyerJourney; } ### BuyerJourney Provides details on the buyer's progression through the checkout. ### activeStep value: `StatefulRemoteSubscribable<BuyerJourneyStepReference | undefined>` What step of checkout the buyer is currently on. ### completed value: `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. ### intercept value: `(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](https://shopify.dev/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. ### steps value: `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. ### BuyerJourneyStepReference What step of checkout the buyer is currently on. ### handle value: `BuyerJourneyStepHandle` The handle that uniquely identifies the buyer journey step. ### 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. #### Returns: InterceptorRequest | Promise<InterceptorRequest> #### Params: - interceptorProps: InterceptorProps export type Interceptor = ( interceptorProps: InterceptorProps, ) => InterceptorRequest | Promise<InterceptorRequest>; ### InterceptorProps ### canBlockProgress value: `boolean` 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. ### InterceptorRequestAllow ### behavior value: `"allow"` Indicates that the interceptor will allow the buyer's journey to continue. ### perform value: `(result: InterceptorResult) => void | Promise<void>` 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. ### InterceptorResultAllow ### behavior value: `"allow"` Indicates that the buyer was allowed to progress through checkout. ### InterceptorResultBlock ### behavior value: `"block"` 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. ### InterceptorRequestBlock ### behavior value: `"block"` Indicates that the interceptor will block the buyer's journey from continuing. ### errors value: `ValidationError[]` Used to pass errors to the checkout UI, outside your extension's UI boundaries. ### perform value: `(result: InterceptorResult) => void | Promise<void>` 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. ### reason value: `string` 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. ### ValidationError ### message value: `string` Error message to be displayed to the buyer. ### target value: `string` The checkout UI field that the error is associated with. Example: `$.cart.deliveryGroups[0].deliveryAddress.countryCode` See the [supported targets](https://shopify.dev/docs/api/functions/reference/cart-checkout-validation/graphql#supported-targets) for more information. ### BuyerJourneyStep ### disabled value: `boolean` 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. ### handle value: `BuyerJourneyStepHandle` The handle that uniquely identifies the buyer journey step. ### label value: `string` The localized label of the buyer journey step. ### to value: `string` The url of the buyer journey step. This property leverages the `shopify:` protocol E.g. `shopify:cart` or `shopify:checkout/information`. ## Related - [Validating fields at checkout](https://shopify.dev/docs/apps/checkout/validation/fields) - [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets) - [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components) - [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration) - [Tutorials](/apps/checkout) ## Examples The API for interacting with the buyer journey. Intercept and prevent a buyer's progress through checkout while displaying an error message at the page level. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import { reactExtension, useBuyerJourneyIntercept, useShippingAddress, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.delivery-address.render-before', () => <Extension />, ); function Extension() { const address = useShippingAddress(); 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 null; } ``` ```js import {extension} from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.delivery-address.render-before', (root, {buyerJourney, shippingAddress}) => { let address = shippingAddress?.current; shippingAddress?.subscribe((newAddress) => { address = newAddress; }); 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', }; }, ); }, ); ``` Intercept and prevent a buyer's progress through checkout while displaying an error message in your extension. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import {useState} from 'react'; import { reactExtension, Banner, useBuyerJourneyIntercept, useCartLineTarget, } 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(); 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 showError ? ( <Banner> This item has a limit of one per customer. </Banner> ) : null; } ``` ```js import { extension, Banner, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.cart-line-item.render-after', (root, {buyerJourney, target}) => { const banner = root.createComponent(Banner); let quantity = target.current.quantity; target?.subscribe((newTarget) => { quantity = newTarget.quantity; }); buyerJourney.intercept( ({canBlockProgress}) => { return canBlockProgress && quantity > 1 ? { behavior: 'block', reason: 'limited stock', perform: (result) => { if (result.behavior === 'block') { banner.appendChild( 'This item has a limit of one per customer.', ); root.appendChild(banner); } }, } : { behavior: 'allow', perform: () => { root.removeChild(banner); }, }; }, ); }, ); ``` ## useBuyerJourneyCompleted 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. ### UseBuyerJourneyCompletedGeneratedType 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. #### Returns: false | true export function useBuyerJourneyCompleted< Target extends RenderExtensionTarget = RenderExtensionTarget, >(): boolean { const api = useApi<Target>(); return useSubscription(api.buyerJourney.completed); } ## Related - [Validating fields at checkout](https://shopify.dev/docs/apps/checkout/validation/fields) - [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets) - [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components) - [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration) - [Tutorials](/apps/checkout) ## Examples The API for interacting with the buyer journey. Intercept and prevent a buyer's progress through checkout while displaying an error message at the page level. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import { reactExtension, useBuyerJourneyIntercept, useShippingAddress, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.delivery-address.render-before', () => <Extension />, ); function Extension() { const address = useShippingAddress(); 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 null; } ``` ```js import {extension} from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.delivery-address.render-before', (root, {buyerJourney, shippingAddress}) => { let address = shippingAddress?.current; shippingAddress?.subscribe((newAddress) => { address = newAddress; }); 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', }; }, ); }, ); ``` Intercept and prevent a buyer's progress through checkout while displaying an error message in your extension. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import {useState} from 'react'; import { reactExtension, Banner, useBuyerJourneyIntercept, useCartLineTarget, } 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(); 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 showError ? ( <Banner> This item has a limit of one per customer. </Banner> ) : null; } ``` ```js import { extension, Banner, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.cart-line-item.render-after', (root, {buyerJourney, target}) => { const banner = root.createComponent(Banner); let quantity = target.current.quantity; target?.subscribe((newTarget) => { quantity = newTarget.quantity; }); buyerJourney.intercept( ({canBlockProgress}) => { return canBlockProgress && quantity > 1 ? { behavior: 'block', reason: 'limited stock', perform: (result) => { if (result.behavior === 'block') { banner.appendChild( 'This item has a limit of one per customer.', ); root.appendChild(banner); } }, } : { behavior: 'allow', perform: () => { root.removeChild(banner); }, }; }, ); }, ); ``` ## useBuyerJourneyIntercept Installs a function for intercepting and preventing progress on checkout. To block checkout progress, you must set the [block_progress](https://shopify.dev/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. `useBuyerJourneyIntercept()` 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. ### UseBuyerJourneyInterceptGeneratedType Installs a function for intercepting and preventing progress on checkout. To block checkout progress, you must set the [block_progress](https://shopify.dev/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. `useBuyerJourneyIntercept()` 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. #### Returns: void #### Params: - interceptor: Interceptor export function useBuyerJourneyIntercept< Target extends RenderExtensionTarget = RenderExtensionTarget, >(interceptor: Interceptor): void { const api = useApi<Target>(); const interceptorRef = useRef(interceptor); interceptorRef.current = interceptor; return useEffect(() => { const teardownPromise = api.buyerJourney.intercept((interceptorProps) => interceptorRef.current(interceptorProps), ); return () => { teardownPromise.then((teardown) => teardown()).catch(() => {}); }; }, [api.buyerJourney]); } ### 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. #### Returns: InterceptorRequest | Promise<InterceptorRequest> #### Params: - interceptorProps: InterceptorProps export type Interceptor = ( interceptorProps: InterceptorProps, ) => InterceptorRequest | Promise<InterceptorRequest>; ### InterceptorProps ### canBlockProgress value: `boolean` 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. ### InterceptorRequestAllow ### behavior value: `"allow"` Indicates that the interceptor will allow the buyer's journey to continue. ### perform value: `(result: InterceptorResult) => void | Promise<void>` 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. ### InterceptorResultAllow ### behavior value: `"allow"` Indicates that the buyer was allowed to progress through checkout. ### InterceptorResultBlock ### behavior value: `"block"` 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. ### InterceptorRequestBlock ### behavior value: `"block"` Indicates that the interceptor will block the buyer's journey from continuing. ### errors value: `ValidationError[]` Used to pass errors to the checkout UI, outside your extension's UI boundaries. ### perform value: `(result: InterceptorResult) => void | Promise<void>` 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. ### reason value: `string` 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. ### ValidationError ### message value: `string` Error message to be displayed to the buyer. ### target value: `string` The checkout UI field that the error is associated with. Example: `$.cart.deliveryGroups[0].deliveryAddress.countryCode` See the [supported targets](https://shopify.dev/docs/api/functions/reference/cart-checkout-validation/graphql#supported-targets) for more information. ## Related - [Validating fields at checkout](https://shopify.dev/docs/apps/checkout/validation/fields) - [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets) - [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components) - [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration) - [Tutorials](/apps/checkout) ## Examples The API for interacting with the buyer journey. Intercept and prevent a buyer's progress through checkout while displaying an error message at the page level. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import { reactExtension, useBuyerJourneyIntercept, useShippingAddress, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.delivery-address.render-before', () => <Extension />, ); function Extension() { const address = useShippingAddress(); 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 null; } ``` ```js import {extension} from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.delivery-address.render-before', (root, {buyerJourney, shippingAddress}) => { let address = shippingAddress?.current; shippingAddress?.subscribe((newAddress) => { address = newAddress; }); 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', }; }, ); }, ); ``` Intercept and prevent a buyer's progress through checkout while displaying an error message in your extension. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import {useState} from 'react'; import { reactExtension, Banner, useBuyerJourneyIntercept, useCartLineTarget, } 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(); 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 showError ? ( <Banner> This item has a limit of one per customer. </Banner> ) : null; } ``` ```js import { extension, Banner, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.cart-line-item.render-after', (root, {buyerJourney, target}) => { const banner = root.createComponent(Banner); let quantity = target.current.quantity; target?.subscribe((newTarget) => { quantity = newTarget.quantity; }); buyerJourney.intercept( ({canBlockProgress}) => { return canBlockProgress && quantity > 1 ? { behavior: 'block', reason: 'limited stock', perform: (result) => { if (result.behavior === 'block') { banner.appendChild( 'This item has a limit of one per customer.', ); root.appendChild(banner); } }, } : { behavior: 'allow', perform: () => { root.removeChild(banner); }, }; }, ); }, ); ``` ## useBuyerJourneySteps 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. ### UseBuyerJourneyStepsGeneratedType 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. #### Returns: BuyerJourneyStep[] export function useBuyerJourneySteps< Target extends RenderExtensionTarget = RenderExtensionTarget, >(): BuyerJourneyStep[] { const api = useApi<Target>(); if (!('buyerJourney' in api) || !api.buyerJourney) { throw new ExtensionHasNoMethodError('buyerJourney', api.extension.target); } return useSubscription(api.buyerJourney.steps); } ### BuyerJourneyStep ### disabled value: `boolean` 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. ### handle value: `BuyerJourneyStepHandle` The handle that uniquely identifies the buyer journey step. ### label value: `string` The localized label of the buyer journey step. ### to value: `string` The url of the buyer journey step. This property leverages the `shopify:` protocol E.g. `shopify:cart` or `shopify:checkout/information`. ## Related - [Validating fields at checkout](https://shopify.dev/docs/apps/checkout/validation/fields) - [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets) - [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components) - [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration) - [Tutorials](/apps/checkout) ## Examples The API for interacting with the buyer journey. Intercept and prevent a buyer's progress through checkout while displaying an error message at the page level. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import { reactExtension, useBuyerJourneyIntercept, useShippingAddress, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.delivery-address.render-before', () => <Extension />, ); function Extension() { const address = useShippingAddress(); 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 null; } ``` ```js import {extension} from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.delivery-address.render-before', (root, {buyerJourney, shippingAddress}) => { let address = shippingAddress?.current; shippingAddress?.subscribe((newAddress) => { address = newAddress; }); 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', }; }, ); }, ); ``` Intercept and prevent a buyer's progress through checkout while displaying an error message in your extension. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import {useState} from 'react'; import { reactExtension, Banner, useBuyerJourneyIntercept, useCartLineTarget, } 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(); 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 showError ? ( <Banner> This item has a limit of one per customer. </Banner> ) : null; } ``` ```js import { extension, Banner, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.cart-line-item.render-after', (root, {buyerJourney, target}) => { const banner = root.createComponent(Banner); let quantity = target.current.quantity; target?.subscribe((newTarget) => { quantity = newTarget.quantity; }); buyerJourney.intercept( ({canBlockProgress}) => { return canBlockProgress && quantity > 1 ? { behavior: 'block', reason: 'limited stock', perform: (result) => { if (result.behavior === 'block') { banner.appendChild( 'This item has a limit of one per customer.', ); root.appendChild(banner); } }, } : { behavior: 'allow', perform: () => { root.removeChild(banner); }, }; }, ); }, ); ``` ## useBuyerJourneyActiveStep Returns the buyer journey step that the buyer is currently on. ### UseBuyerJourneyActiveStepGeneratedType Returns the buyer journey step that the buyer is currently on. #### Returns: BuyerJourneyStep | undefined export function useBuyerJourneyActiveStep< Target extends RenderExtensionTarget = RenderExtensionTarget, >(): BuyerJourneyStep | undefined { const api = useApi<Target>(); if (!('buyerJourney' in api) || !api.buyerJourney) { throw new ExtensionHasNoMethodError('buyerJourney', api.extension.target); } const steps = useSubscription(api.buyerJourney.steps); const activeStep = useSubscription(api.buyerJourney.activeStep); return activeStep ? steps.find(({handle}) => handle === activeStep.handle) : undefined; } ### BuyerJourneyStep ### disabled value: `boolean` 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. ### handle value: `BuyerJourneyStepHandle` The handle that uniquely identifies the buyer journey step. ### label value: `string` The localized label of the buyer journey step. ### to value: `string` The url of the buyer journey step. This property leverages the `shopify:` protocol E.g. `shopify:cart` or `shopify:checkout/information`. ## Related - [Validating fields at checkout](https://shopify.dev/docs/apps/checkout/validation/fields) - [Targets](https://shopify.dev/docs/api/checkout-ui-extensions/targets) - [Components](https://shopify.dev/docs/api/checkout-ui-extensions/components) - [Configuration](https://shopify.dev/docs/api/checkout-ui-extensions/configuration) - [Tutorials](/apps/checkout) ## Examples The API for interacting with the buyer journey. Intercept and prevent a buyer's progress through checkout while displaying an error message at the page level. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import { reactExtension, useBuyerJourneyIntercept, useShippingAddress, } from '@shopify/ui-extensions-react/checkout'; export default reactExtension( 'purchase.checkout.delivery-address.render-before', () => <Extension />, ); function Extension() { const address = useShippingAddress(); 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 null; } ``` ```js import {extension} from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.delivery-address.render-before', (root, {buyerJourney, shippingAddress}) => { let address = shippingAddress?.current; shippingAddress?.subscribe((newAddress) => { address = newAddress; }); 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', }; }, ); }, ); ``` Intercept and prevent a buyer's progress through checkout while displaying an error message in your extension. See the [validation tutorial](https://shopify.dev/docs/apps/checkout/validation) for more examples and best practices. ```jsx import {useState} from 'react'; import { reactExtension, Banner, useBuyerJourneyIntercept, useCartLineTarget, } 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(); 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 showError ? ( <Banner> This item has a limit of one per customer. </Banner> ) : null; } ``` ```js import { extension, Banner, } from '@shopify/ui-extensions/checkout'; export default extension( 'purchase.checkout.cart-line-item.render-after', (root, {buyerJourney, target}) => { const banner = root.createComponent(Banner); let quantity = target.current.quantity; target?.subscribe((newTarget) => { quantity = newTarget.quantity; }); buyerJourney.intercept( ({canBlockProgress}) => { return canBlockProgress && quantity > 1 ? { behavior: 'block', reason: 'limited stock', perform: (result) => { if (result.behavior === 'block') { banner.appendChild( 'This item has a limit of one per customer.', ); root.appendChild(banner); } }, } : { behavior: 'allow', perform: () => { root.removeChild(banner); }, }; }, ); }, ); ```