Three Kinds of Shopify App: Public, Custom, and the Retired Admin-Created App
"It's an app we built for ourselves" says nothing about what the app actually is. What determines its permissions, authentication path, ability to charge merchants, and whether any of that can be changed later is its distribution method — not how the developer describes its purpose. Only two distribution methods are available for new apps today. A third, legacy form keeps working in the stores that already have it but can no longer be created.
The three forms side by side
| Public | Custom | Admin-created (retired) | |
|---|---|---|---|
| Still creatable | Yes | Yes | No |
| Created by | A developer; App Store listing requires review | A developer or a merchant | The merchant, in their own admin |
| Install scope | Many stores | One store, several stores in the same Plus organization, or transfer-disabled development stores | Only the store that created it |
| Authentication | Token exchange when embedded, authorization code grant when not | Same as public | A pre-generated Admin API access token, no OAuth |
| Can be embedded | Yes | Yes | No |
| Shopify app billing | Available | Not available | Not available |
Source: App distribution. A custom-distribution app can't charge merchants through Shopify's app billing system, so any commercial app that needs Shopify to collect payment has to use public distribution.
The admin-created app is history
An admin-created app is one the merchant builds under Apps and sales channels → Develop apps in the Shopify admin: it hands out a long-lived Admin API access token directly, skips OAuth entirely, and cannot be embedded. Shopify now treats it as legacy. Generate access tokens for admin-created custom apps states that new apps of this kind can no longer be created and that existing ones keep working. The Help Center puts the cutoff at January 1, 2026: legacy custom apps created before that date can still be managed from the admin — see About apps.
So "a merchant-built app is the kind where you copy a token out of the admin" is now an outdated assumption. A merchant building an app today does it in the Dev Dashboard and ends up with an ordinary custom-distribution app: its configuration file carries embedded, [access_scopes] and [auth], and authentication is still token exchange or the authorization code grant. To classify an app, read its configuration and authentication path, not who clicked Create.
Created by the merchant, owned by the merchant's organization
A custom-distribution app belongs to the organization that created it. When a merchant creates the app inside their own Dev Dashboard organization, the developer has to work with an account that belongs to that organization; CLI commands run from an account outside it are rejected because that account is not a member (observed in practice, not a documented rule). When you take over a project like this, confirm three things first: which organization owns the app, whether your account is a member of it, and which store the app is bound to.
The distribution method is permanent
App distribution states that the distribution method cannot be changed once selected. "Ship it as a custom app now, list it on the App Store later" is therefore not a migration path — changing form means creating a second app and going through installation and authorization again. Answer two questions before choosing: will this app ever need to be installed on a store outside the original merchant (or their Plus organization), and will it ever charge merchants through Shopify? A yes to either rules out custom distribution.
A configuration consequence you have to handle
When the merchant has created only one app, development and production share a single app identity — and application_url can only hold one value at a time. In that setup automatically_update_urls_on_dev has to be false, or every shopify app dev run rewrites the app URL the merchant actually sees to the developer's local tunnel address. Shopify's own description of the field is that when it is false your URLs won't be updated on dev, and it lists that value as the recommendation for production apps — see App configuration.
If development and production genuinely need to stay out of each other's way, the answer is two app identities and two configuration files, not automatic URL rewriting.