I’m getting CORS error while calling Shopify GraphQL Admin API.
async function getMetafield(product_id) {
const res = await fetch("https://mystore.myshopify.com/admin/api/2025-07/graphql.json", {
method: "POST",
headers: {
"Content-Type": "application/json",
"X-Shopify-Access-Token": ""
},
body: JSON.stringify({
query: `
{
product(id: "gid://shopify/Product/${product_id}") {
metafields(first: 10) {
edges {
node {
namespace
key
value
}
}
}
}
}
`
})
});
The Admin API is blocked from browser calls on purpose. Shopify deliberately
doesn’t set CORS headers on /admin/api/... endpoints — it’s not a bug to
work around, it’s how the platform protects your Admin access token. Even if
you found a header trick, your token would be visible to anyone viewing the
page source.
What to use depends on what you’re trying to do:
-
Product/price data on a customer-facing page → use the Storefront API:
https://<shop>.myshopify.com/api/2025-07/graphql.json with a public
storefront access token in X-Shopify-Storefront-Access-Token. It’s
designed for browser calls, has CORS support, and the storefront token is
intentionally low-trust and safe to ship in client code. Note: product
metafields are only visible via the Storefront API if you’ve explicitly
exposed them — Admin → Settings → Custom data → Storefronts.
-
Admin data (orders, customers, internal metafields, etc.) → call from
your own backend. A small Node or serverless endpoint makes the Admin call
with the Admin token, and your page fetches just the result. The Admin
token never touches the browser.
-
Embedded Shopify app → use App Bridge to get a session token, send it
to your app’s backend, and have the backend call Admin GraphQL on the
merchant’s behalf. The Shopify CLI app templates (Remix, Node) wire this
up out of the box.