New Dev Dashboard flow (post-Jan 2026) — Fill in your values and they populate every command.
As of January 1, 2026, Shopify deprecated legacy custom apps. You can no longer create apps that show a static shpat_ token to copy-paste. The new Dev Dashboard gives you a Client ID and Client Secret which you exchange programmatically for a short-lived access token (24hr expiry).
Go to your store admin. Fill in your store name below — it populates every URL and command:
Click Develop apps
Click the Build apps in Dev Dashboard button (yellow banner at top)
This opens the Shopify Dev Dashboard at dev.shopify.com
Click Create an app
Give it a name (e.g. my-migration-tool)
You'll land on a Create version page
App URL: Leave as https://example.com — doesn't matter for API-only use.
Scopes: Click Select scopes or paste directly into the Scopes text box:
read_products,write_products,read_metaobjects,write_metaobjects,read_metaobject_definitions,write_metaobject_definitions,read_files,write_files,read_inventory,write_inventory,read_themes,write_themes,read_online_store_pages,write_online_store_pages,read_content,write_content
Click the Release button (bottom-right).
After release, look for an Install option
Confirm the permissions dialog and click Install
The app opens an embedded view showing example.com — ignore it, close the tab
Go back to the Dev Dashboard: dev.shopify.com
Open your app → Settings
Copy the Client ID (long hex string) and enter it below:
Reveal and copy the Client Secret (starts with shpss_) and enter it below:
shpss_ value is your Client Secret, not a Storefront token. It's only used to request a token.Exchange your credentials for a short-lived access token. This replaces the old copy-paste shpat_ flow.
{
"access_token": "f85632530bf277ec9ac6...",
"scope": "read_products,write_products,...",
"expires_in": 86399
}The access_token is your Admin API token. Use it in the X-Shopify-Access-Token header. Expires in 24 hours.
For scripts that run repeatedly, use a shared auth module that fetches and caches the token automatically.
import 'dotenv/config';
import { URLSearchParams } from 'node:url';
const SHOP = process.env.SHOPIFY_SHOP;
const CLIENT_ID = process.env.SHOPIFY_CLIENT_ID;
const CLIENT_SECRET = process.env.SHOPIFY_CLIENT_SECRET;
let token = null;
let tokenExpiresAt = 0;
export async function getToken() {
if (token && Date.now() < tokenExpiresAt - 60_000) return token;
const response = await fetch(
`https://${SHOP}.myshopify.com/admin/oauth/access_token`,
{
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: new URLSearchParams({
grant_type: 'client_credentials',
client_id: CLIENT_ID,
client_secret: CLIENT_SECRET,
}),
}
);
const { access_token, expires_in } = await response.json();
token = access_token;
tokenExpiresAt = Date.now() + expires_in * 1000;
return token;
}import { getToken } from './auth.js';
const token = await getToken();
// Use in X-Shopify-Access-Token header{
"name": "shopify-tooling",
"type": "module",
"private": true,
"dependencies": {
"dotenv": "^16.4.0"
}
}Run npm install in your project folder, then node test-auth.js to verify.
Your .myshopify.com subdomain doesn't match the store the app is installed on. Check Settings → Domains in your store admin for the correct subdomain.
The app and store are in different Shopify organizations. Client credentials only works within the same org.
The shpss_ is your Client Secret, not an access token. You must exchange it programmatically (see Part 3).
Tokens last 24 hours. Use the auto-refreshing auth module (Part 4) or re-run the token request.
shpat_Old static Admin API token (legacy custom apps only)shpss_Client Secret used to request tokens (Dev Dashboard apps)Client IDPublic app identifier (hex string)Access TokenShort-lived token from client credentials exchange (24hr)X-Shopify-Access-TokenHTTP header for all Admin API requestsgrant_type=client_credentialsOAuth grant type — literal string, don't replace it