Storefront API not working in non-default language environment

As noted in the documentation, Shopify allows us to call the Storefront API using the global fetch method in checkout UI extensions when api_access is enabled:

Enabling the api_access capability allows you to use the Standard API query method and the global fetch to retrieve data from the Storefront API without manually managing token aquisition and refresh.

query lets you request a single GraphQL response from the Storefront API.

If you prefer to construct GraphQL requests yourself or you would like to use a full-featured GraphQL client such as Apollo or urql, our custom fetch global automatically appends the required access tokens.

The GraphQL client of your choice shouldn’t use any DOM APIs, as they aren’t available in a checkout UI extension’s Web Worker.

This works perfectly when the store is in its default language. However, when switching to a non-default language, calling shopify.shop.storefrontUrl returns a localized URL containing the language code:

image

When attempting to fetch using this localized URL, it fails and throws the following capability error:

permission to use fetch() must be specified under [capabilities] with flag “network_access = true”; this can be done within your extension’s configuration. View the docs for more information:

Hey, @Kenn thanks for the detailed write up here. Hopefully I’m understanding your use case, but are you using shopify.shop.storefrontUrl to build the Storefront API request so it follows the current non default language?

If so, could you try the same call using the built in query() helper or fetch('shopify:storefront/api/graphql.json', ...) instead, and pass the language and country in the query context rather than building the request off the localized storefront URL (more info on this here)?

From what you’re describing, it sounds possible that once the request is being built from the localized storefrontUrl, it may be getting treated more like a regular network request, which would explain why you’re seeing the network_access = true error. If that is what you’re aiming to do, I’d be curious whether the same behaviour still happens when using the built in Storefront API path instead.

If you can give that a try and share what you see, I’m happy to take a closer look. Let me know if I can clarify anything on my end here, happy to help!

Hi @Alan_G,

We need to access data that falls outside the access scope of the checkout extension, so we are making the Storefront API request using fetch (for using our own access token). We noticed that this works in our default language, but it fails when we switch to another language.

I tried updating the Storefront API URL to shopify:storefront/api/graphql.json, but it is still not working in non-default language environments.

ExtensionUsageError: invalid request URL for storefront API. View the docs for more information:

image

Hey @Kenn, thanks for sharing that snippet, that helps clarify things.

I think the issue here is that the request is mixing the built in checkout Storefront helper path with the standard token-authenticated Storefront API request pattern. I’m not seeing documentation that explicitly supports passing a custom X-Shopify-Storefront-Access-Token alongside fetch('shopify:storefront/api/graphql.json', ...). The checkout extension docs describe shopify:storefront as the built in Storefront helper path where Shopify infers the endpoint and appends the required auth automatically, while the Storefront API docs show manual token headers on the standard HTTPS Storefront endpoint. Based on that, this looks like an unsupported, or at least undocumented, request pattern rather than the intended use of shopify:storefront.

If you are using the built in checkout Storefront access, I’d try query() or fetch('shopify:storefront/api/graphql.json', ...) without manually setting the token header, and pass language and country through @inContext(...) rather than building from a localized storefront URL.

If you do need to use your own Storefront token, I’d treat that as a regular network request instead, which would mean using network_access = true, or preferably routing the request through your app backend or proxy.

I also would not recommend building the API endpoint from shopify.shop.storefrontUrl here, since that value can include localization in multilingual contexts.

If you can share whether the token you’re using is public or private, and a redacted version of the full request flow you’re aiming for, I’m happy to take a closer look and confirm the expected behaviour on our side.

@Alan_G
I don’t think this issue is caused by using our own access token, because when we use fetch, which auto-appends the access token by default, we still get this error:



This is the expected error, because the checkout extension does not include the unauthenticated_read_product_inventory access scope.

In a non-default language environment, we get this error:

It seems that shopify:storefront/api/graphql.json is translated to
https://xxx.myshopify.com/zh/2026-01/graphql.json in this JavaScript function:


and fails the path validation here:

image

We can see the problem is that when building the storefront URL using shopify.shop.storefrontUrl in a non-default language environment, the checkout extension treats it as a normal network request. If we use shopify:storefront/api/graphql.json instead, it fails the path validation.

Hey @Kenn Thanks for the extra detail and screenshots, that helps a lot. I agree the behaviour looks odd there and doesn’t seem aligned with the documented Storefront fetch flow, so I’m going to raise this internally. , could you confirm the exact Checkout UI Extensions API version you’re using and whether this reproduces in a minimal extension that only calls fetch(‘shopify:storefront/api/graphql.json’, …), and whether query() in that same localized checkout still reaches Storefront and returns a normal GraphQL response/error rather than the URL validation error? Just want to narrow potential issues down - we’ll get this looked into!

Hey @Kenn - just following up here, let me know if we can still help out

@Alan_G Hi, we attempted to switch the storefront request to query, it returns error messages normally in non-default language environments. This issue appears to occur only when using fetch to retrieve data from the Storefront API in non-default language.

our api version is 2026-01

Hey @Kenn, thanks for confirming that and for testing query() too. Since query() reaches Storefront correctly in the non-default language environment but fetch('shopify:storefront/api/graphql.json', ...) doesn’t, it does look potentially unexpected to me given they’re documented as equivalent for api_access usage, so I’ll flag that internally for a closer look.

In the meantime, I’d recommend sticking with query() for your Storefront calls, based on what you’ve shared it looks like the most reliable path here. You can pass language and country context directly in the query using @inContext(language: ..., country: ...) rather than relying on the URL to carry that, which keeps things clean regardless of the active storefront language.

I’ll loop back with you once I have more to share though, thanks for your patience on this, really appreciated!

One separate thing worth flagging while we’re here — unauthenticated_read_product_inventory isn’t currently in the list of access scopes available to checkout extensions via api_access, so that particular query won’t be able to return inventory data through the built-in Storefront helper even once you’re past the fetch issue. If inventory data is something you need at checkout, the recommended path for that would be network_access = true with the request routed through your app backend or a proxy. Happy to point you in the right direction on that if useful!

Let me know how you get on with query() and if there’s anything else I can help clarify.

Hey @Kenn - just following up here. We’ve identified this as a possible bug on our end and are investigating a fix. I’ll keep you in the loop on this :slight_smile:

Hey @Kenn - just looping back here, we’ve shipped a potential fix for this, please let me know if you still see any issues though and I’m happy to look into things with you.