Is there any documentation with recommended paths forward to replace the now-deprecated custom app functionality? I feel like I’m missing something since there seem to be gaping holes between the old custom app and new dev dashboard functionality.
I regularly use custom apps to get single store, API-only access to both the Storefront and Admin APIs. This is super easy, very clear what scopes are granted, etc.
Storefront API → Sounds like the intention is that you instead install the Headless app to manage all Storefront API access? Otherwise you need to make manual requests to generate the token, etc.
Admin API → Really unclear how this is supposed to work. Sounds like I need to manually get an access token using a client credentials grant? But that says it only lasts for 24 hours which isn’t practical for use in, for example, Shopify Flow.
I’m not 100% sure if for the Storefront API you are required to use the Headless app, but for the Admin API when using the client credentials grant flow you would need to refresh the access token and replace before the 24 window closes. Is your concern that during the switch calls could fail?
My concern is that I need an access token that doesn’t expire. I need one that I can generate and continue to use indefinitely.
As practical example, I frequently need this to access data in Shopify Flow, which has no mechanism to save a new token, even if I could implement a client credentials grant, which isn’t really practical in that context.
Hi Andrew! The Flow team is aware that the MCA token deprecation will affect folks using the “Send HTTP request” action to call the Shopify GraphQL Admin API and we’re actively working to add support for client credentials grant to address that.
We’re also working to add support for most of the more commonly used fields that require arguments, which are a common use case for using the “Send HTTP request” action to call the Admin API.
Can I ask which use cases you have for calling the Admin API via HTTP request in Flow instead of using natively available options?
Get data that isn’t available via an action. Recently I used this to get gift card data although I see that’s now available as an action (possibly I missed it) - so this may be less of an issue going forward. Certainly using native actions is a lot nicer than having to make and parse API requests.
Making complication mutations. For example I currently have a flow that runs a variable number of aliased metaobjectUpdate mutations plus a customerUpdate and orderUpdate in a single request. This keeps things a lot tidier in Flow (1 HTTP action vs 3+ and a loop), and make it possible to chain actions reliably. Determine changes required > Make changes via API > Then do something else. If there was a generic “custom Admin API” action where I could set the body and variables directly, instead of picking from the predefined list, then that would eliminate this issue.
As a temporary workaround, you can use the Execute GraphQL request action from the Flow Companion app, if you don’t mind using third-party applications.
When the issue is resolved, you’ll be able to switch back to the Send HTTP request action or to the new Admin API actions that @RPiii is talking about.
@Liam-Shopify There are lots of use-cases for single store custom apps outside of Flow where it’s not practical to have to get an access token that expires in 24h. For example, any 3rd party integration that doesn’t have a dedicated Shopify app. In our specific use case, connecting Catchr to Looker Studio: Looker Studio Shopify Integration | No-code
It seems this type of workflow is no longer possible, with no clear direction on how to replace it?
@TerenceShopify@Liam-Shopify The limitation that “Client credentials is only available for apps developed by your own organization and installed in stores that you own” adds significant friction for working with merchants as an agency partner. Many merchants seek assistance from agencies for technical concerns, and requiring them to understand how to properly set up an app in the dev dashboard with the appropriate permissions isn’t practical. Some type of permissions system to allow a partner / collaborator to execute client credentials grants would be a more sensible approach.
You can use workaround that avoids client credentials entirely and only asks the merchant to install your app once (one OAuth click). After that, we reuse the same token everywhere, it’s hacky btw, I’m not sure if it works well.
How:
Your Partner app is installed on the merchant’s store once via the normal OAuth flow (e.g. “Test your app” in Partner Dashboard → choose their store — they click Install). No dev dashboard, no custom app, no client credentials on their side.
Persist the session in your own DB. We use a Remix app with Prisma and PrismaSessionStorage. On install, Shopify’s library stores the session (shop + accessToken) in a Session table. In that Session row set expires and refreshTokenExpires to null (e.g. via npx prisma studio) so the token isn’t treated as expired and stays valid until uninstall.
Read the token from the DB with a small script (e.g. by shop domain) and print it:
Use that token as a static secret in your backend. The token is long‑lived (no 24h rotation like client_credentials) and it’s valid until the app is uninstalled or scopes are changed. When that happens, re-run the install and the script, then update your secret.
So the merchant only does one Install. You handle the rest. No client credentials, no dev dashboard setup for them, and you get a stable token for all your serverless/API use cases.
Sounds like a clever workaround, easy for merchants with just one install. Worth testing, but be careful with long-lived tokens if scopes change or the app is uninstalled.
I’m diving into this again and this whole situation seems broken. It’s completely insane that Shopify has made this change with such blind disregard for actual use cases.
I’m doing some work on a new store, so no wonderfully simple, easy, nice UX, custom apps to use. I went to update a script to use client credentials grant which seems straightforward enough and has some nice clean example code provided.
Surprise, it doesn’t work! The limitation of “Client credentials is only available for apps developed by your own organization and installed in stores that you own” is rather more than what Nic so politely described as “friction”. It makes it totally useless for anyone who access a store via a partner/collaborator account. Which is doubly crazy since that’s the “correct” way to provide access to 3rd parties, rather than handing out staff accounts. Not to mention that having collaborator access and a staff account on the same store also causes all kinds of issues.
I’m trying to run a very simple script that programmatically links product option values to category metafields (something that as far as I can tell is not possible any other way, without manually clicking in the admin, for every single product.)
To do this I somehow need:
to scaffold up a full remix app
install some tunneling software so I can host it locally
install the app on the store
modify the database directly so the access tokens don’t expire
then manually extract the access token from the database
revert my changes to support client credentials grant
save the access token to my .env file like I always did before
I got this to work but I’m still baffled how a team that consistently delivers such excellence could think this was in any way a reasonable solution.
They replaced a simple, clear, easy to use feature with a process so opaque that it actively encourages poor security practices.
My key takeaways are:
Make sure to enable all possible access scopes, because it’s such a pain in the ass
Make sure to share access tokens as much as possible, because it’s such a pain in the ass
As I mentioned previously, the client credentials grant doesn’t actually work for normal agency flows where you access a store via a collaborator account.
The only alternative is to get a non-expiring offline access token. Despite the total lack of clarity from Shopify this does still exist and as far as I can tell works exactly like the access token you would get from an old custom app.
To get this:
Spin up a new app with the CLI using the default react router template
In shopify.server.js update expiringOfflineAccessTokens to false
Set your required access scopes in the app .toml file. Appreciate how nice it is to manually type them all out instead of checking boxes in the nice UI you had previously.
Expose a URL for your local machine using a service like ngrok
Update the app URLs to that URL
Run the production version of the app locally by following the deploy guide
Install the app on the target store
After app is authenticated, run the script lynthius provided to grab the access token from the database
Close down the app/server and ngrok tunnel
Use the access token exactly like you would have with the old custom app