The Buyer Journey Intercept API is now deprecated

Hey everyone,

We’ve recently announced that the checkout UI extension buyer journey intercept API is deprecated starting on 2026-07. While it’s still available to use on this most recent checkout UI extension version, we plan to remove it in a future version. If you’ve been using the buyer journey intercept for client-side validation, this post is for you.

What’s changing

As of API version 2026-07, client-side validation via the buyer journey intercept is now deprecated. This means:

  • It’s still available in 2026-07, so nothing breaks today and your existing extensions will keep working.

  • It will be removed in a future API version. We encourage you to start migrating now before it’s removed.

  • Going forward, our recommendation for validation is cart and checkout validation functions.

Why we are making this change

The buyer journey intercept was released before Shopify Functions existed. It runs in the buyer’s browser, which means it isn’t guaranteed to run at all. That can happen on slow connections, or with some wallets that bypass checkout entirely. That makes it a less reliable foundation for validation than we’d like.

Cart and checkout validation functions solve this because they run server-side. That gives you better performance and security, and it means your validation logic actually runs when it needs to. We’ve also been investing in making them more capable, like targeting billing addresses and PO numbers and querying metaobjects. We will continue to invest further into cart and checkout validation functions to enable more use cases as needed.

But the biggest reason is coverage. Because they run server-side, validation functions work across every checkout surface, including agentic checkouts. The buyer journey intercept simply can’t do that, and as more buying happens across these surfaces, that gap is only going to matter more.

:backhand_index_pointing_right: Learn more about cart and checkout validation functions.

What this means for you

  • If you use useBuyerJourneyIntercept to enforce merchant business rules, migrate to a cart and checkout validation Function. These Functions run server-side and apply your rules consistently across all checkout surfaces, including express wallets and agentic checkout.

  • If you use useBuyerJourneyIntercept to reject discount codes, migrate that logic to the discount Function API, which now supports rejecting discount codes with a custom message.

Questions?

I’d love to hear about any use cases you’re blocked on, what we’re missing, or if you run into any edge cases. Drop your thoughts below. Happy to dig into specifics and setup time to chat.

Gil Greenberg
Product Manager, Checkout

Hi Gil, I have few blockers:

there are some issues with checkouts using multi-step checkouts or review step. I wrote about it here: [Bug] Cart validation functions - two issues blocking migration from useBuyerJourneyIntercept()

Also when using Apple Pay / Google Pay buttons on product page, validation functions prevent from going to checkout and displays unhelpful message: [Bug] Cart validation functions - Apple Pay / Google Pay shows unhelpful validation error on product/cart page

Let me know if you need more info

This API is pretty critical for the Plus merchants that use our checkout extension.

In order to successfully migrate them, we’ll need to be able to identify which still need the additional validation function we’ve published.

We only prompt for the bare minimum API scopes required, and read_validations or write_validations is required in order for us to tell if our cart validation function is activated on their checkout profile.

Can we either:

  1. have active Cart Validation inspection available in the App Bridge API, so that way we can prompt the merchant to accept this new scope and give feedback if the checkout validation function is active?

  2. Retroactively apply at least read_validations to all issued tokens that use this API before the deprecation so we can identify which merchants still need to perform these steps before we upgrade?

Since we cannot deploy specific checkout extension versions to specific merchants, in order to successfully migrate then 100% of merchants with extensions using this API need to perform this additional step. It’s very risky to them.

Hey Gil,

The intercept is a pretty critical feature that many of our Plus merchants rely on to prevent invalid orders from checking out. We’ve dug into migrating and see three problems with validation functions as they stand:

  • Error surfacing: Validation errors can only target $.cart or built-in fields, so “please pick a date” shows as a banner at the top of the page, nowhere near our calendar. The intercept lets us block and put the error right where the buyer needs to act. Losing that is going to damage conversion for merchants. A way to anchor a validation error to a UI extension block would close this.

  • Blocked checkouts: Our migration path is the extension validating client-side and unblocking the function via a cart metafield. But the function has to pick a default for when that metafield is missing. Block by default and, as your post acknowledges, extensions sometimes don’t load, so those checkouts are 100% bricked, along with every express wallet flow. Allow by default and a fast buyer checks out before the extension loads and writes, which is a problem merchants already come to us about constantly. The intercept handles this elegantly today because it only exists when our extension is actually present: it blocks while we’re still loading, and naturally stands down when the extension never ran. A function has no way to know whether an extension loaded in the session, so we lose that. Server-side validation is meant to fix exactly this race, but without extension-presence awareness we’d have to fail open and keep it.

  • Migration mechanics: +1 to @Dylan . We can’t see who’s activated the validation without prompting every store for read_validations, and merchants can deactivate it in admin without us knowing.

Happy to share specifics from our setup or jump on a call to run through.

Great points from @Dylan and @Alex_Hooper.

On visibility: if this is a breaking change, we need tooling to identify which merchants actually depend on the buyer journey intercept. Right now there’s no way for us to tell from the app side whether a given shop relies on it, and we have many merchants who deliberately chose it over a validation function for various reasons. Without that signal, migrating is guesswork and the risk lands on the merchant.

On the functions themselves: they still need a better story around default values and cleanup. Concrete example from our app: if the checkout extension fails to load, that’s acceptable to us. The problem is when a previously captured metafield value goes stale and the extension isn’t there to refresh it. Nothing cleans it up, so we let the order through rather than block the buyer, but it comes in with invalid data. What we’d want is a way to say “pass, but clear this metafield” - a cleanup action rather than a pass/fail outcome.

I agree that functions are better, but until these gaps are closed, the migration transfers risk from the platform onto merchants and partners. Ship the bug fixes, tooling and the cleanup mechanism before removal, not after.

Here are the challenges we’re facing in migrating to Validation Functions.

  • Dynamic control over blocking
    We want to show buyers an error, but we need a way to control whether it actually blocks checkout.

    Our use case: we provide an address validation app. The Japanese address system is complex, and we often see addresses that don’t match the official definitions but are still valid (e.g., notation variations). In those cases we want to let buyers proceed at their own discretion despite the error, to minimize the impact on conversion.

  • Use of fetch
    Our validation is based on postal code data, which is external reference data. Given its size, embedding it within the function’s 256 KB limit is not realistic.

    An alternative approach might be an app-level metaobject space that apps can manage and Functions can read.

  • Banner placement
    As Alex mentioned, banners currently only appear at the top of the page, so buyers may not intuitively see what to fix. It would be great if we could control where banners are displayed, like UI Extensions can.

One additional migration gap I haven’t seen mentioned explicitly is lifecycle coupling between the Checkout UI extension and its Validation Function.

Could apps declare that a Checkout UI extension depends on a specific Function, so that when a merchant adds or enables the extension in the checkout editor, Shopify automatically activates the corresponding validation?

For example, an app could use a shared naming convention and declare the dependency directly in its extension configuration:

extensions/
├── address-validation-ui/
│   └── shopify.extension.toml
└── address-validation-function/
    └── shopify.extension.toml
# address-validation-ui/shopify.extension.toml

[[extensions]]
type = "ui_extension"
handle = "address-validation-ui"

[extensions.dependencies]
validation_function = "address-validation-function"

When the merchant enables address-validation-ui in the checkout editor, Shopify would automatically activate address-validation-function.

From the merchant’s perspective, they are enabling one feature, not two independent extensions. Shopify could then surface the dependency if either part is disabled.

The exact configuration syntax could be different, but the idea is to let both extensions represent a single merchant-facing feature. This would remove the manual activation step, reduce the need for apps to inspect validation state using additional scopes, and make migrations from useBuyerJourneyIntercept much safer.

Just want to express that we experience all of the above issues with the checkout extensions we maintain too.

I understand the sentiment and the fact that running it in the browser is not ideal, but there are so many gaps.

Functions, in its current form, can’t cover them. The biggest issue I see is the lack of fetching data and the lack of linkage between a checkout ui extension and its function counterpart that will now be required.

That being said, all of the other issues already mentioned are also the ones we experience. And the timeline of deprecation is very steep with these vital elements missing.

This is a really good suggestion.

I’d also love to see a proper way for a Checkout UI extension and its Function to share state.

At the moment, the usual workaround is writing cart attributes or metafields, waiting for the round trip through Shopify, and then having the Function pick them up.

It works but it’s hacky, slow, and can introduce stale state or race conditions.

Coupling the extension and Function would solve for this - giving them a proper shared state layer would solve a lot of the runtime pain + other elements folks are sharing above ^^

Hey folks. Thanks for all the great feedback. Again, to be clear, no timeline for removal has been shared. We don’t plan to remove the API until we’ve provided adequate coverage for the most common gaps but we do want to make it clear, client-side validation is not recommended and at some point, will be removed. There are many apps (custom or public) which can and should leverage Shopify Functions today.

Also acknowledging the buyer journey intercept is a critical API which is why we want to get this right and we believe server-side validation is the correct approach.

The biggest issue I see is the lack of fetching data

@stefan What data are you fetching and is this from your app’s backend or a 3p party API? What’s preventing your app from leveraging metafields or metaobjects for this data on the function side?

We need tooling to identify which merchants actually depend on the buyer journey intercept.

@Dylan @Patrick_Jakubik @Alex_Hooper You’re both referring to an Admin API equivalent to what App Bridge provides in terms of active extensions on a published checkout configuration?

Error surfacing: Validation errors can only target $.cart or built-in fields, so “please pick a date” shows as a banner at the top of the page, nowhere near our calendar.

@Alex_Hooper definitely a gap we will look to address.

  1. Retroactively apply at least read_validations to all issued tokens that use this API before the deprecation so we can identify which merchants still need to perform these steps before we upgrade?

@Dylan Is this to enable auto creation of cart and checkout validation functions for those with the checkout ui extension activated?

Ideally this should be accessible via Admin GraphQL API, not through App Bridge, as with App Bridge we cannot perform check in bulk on all stores.

Thanks @Gil-Shopify I know you’re well versed on internals, merchant and developer sides of Checkout Extensions more than anyone. Really helps to have you in our corner on this migration!

We need tooling to identify which merchants actually depend on the buyer journey intercept.

>> You’re both referring to an Admin API equivalent to what App Bridge provides in terms of active extensions on a published checkout configuration?

Yes, specifically the active extensions configuration. Right now the AppBridge can tell us if the checkout extension is enabled (during an app session only), but it cannot tell us if the merchant has enabled the “Allow blocking checkout” option for the buyer journey intercept.

To successfully migrate, we need to identify with merchants are using our Checkout Extension and if the checkout extension is configured to allow blocking checkout.

Ideally we can inspect this with the Admin GraphQL, since the AppBridge relies on the current session and it’s limited to the frontend. For apps that are “configure and forget” there’s a narrow window to display this information and telemetry back to our own backends.

Retroactively apply at least read_validations to all issued tokens that use this API before the deprecation so we can identify which merchants still need to perform these steps before we upgrade?

@Dylan Is this to enable auto creation of cart and checkout validation functions for those with the checkout ui extension activated?

No, the purpose of read_validations would be to identify which merchants have both the Checkout Extension activated and enabled “Allow blocking checkout” but don’t currently have the Cart Validation installed and activated.

Those are the merchants that would be impacted if forced to switch over the newest checkout extension API.

Without knowing those 3 pieces of information, we cannot display informational banners nor can we send targeted emails to these merchants that an action is required.

Shopify does this well, take a look at the Customer Account migration. The date of when it’s happening is communicated in the dashboard and over email.

After you migrate, the dashboard displays you’re migrated and the emails stop.

If we cannot inspect the current state of the Checkout Extension, it’s configuration, and if the corresponding Validation Function is enabled.

We just want to follow this same pattern. Give a reasonable deadline, communicate clearly and often and show correct feedback when they have completed the action.

Right now, those apps using this buyer journey intercept don’t have visibility into if it’s enabled or if their cart validation function is enabled.

Hopefully that makes sense, let me know if I can clarify bits. It’s a complex problem.