CORS Errors with Shopify GraphQL Admin API? Here's Why (and What to Do!)

Hey everyone! I’ve been seeing a lot of chatter in the Shopify community about a common head-scratcher: CORS errors when trying to hit the GraphQL Admin API directly from a browser. It’s a frustrating moment, right? You’re just trying to get some data, and suddenly your console is yelling about cross-origin issues. We recently had a great discussion on this very topic, sparked by saurabhv's question about calling the Admin API from a client-side function.

Let's dive into why this happens and, more importantly, what the Shopify experts in the community recommend as the correct approach. Because spoiler alert: it’s not a bug you need to work around; it’s a deliberate security feature!

Why You Can't Call the Admin API Directly from a Browser

The core of the issue, as software-clever clearly laid out in the thread, is security. Shopify intentionally blocks direct browser calls to its /admin/api/... endpoints. They don’t set the necessary CORS (Cross-Origin Resource Sharing) headers for a very good reason: to protect your Admin access token.

Think about it: your Admin API token grants powerful access to your store's backend data – orders, customer information, internal metafields, and more. If you were to embed this token directly into your client-side JavaScript, it would be visible to anyone viewing your page source. That’s like leaving the keys to your store's vault under the doormat. Any malicious actor could grab that token and potentially wreak havoc on your store.

So, when you see that CORS error, it's actually Shopify doing its job, protecting your sensitive data. It's not a hurdle to bypass but a signal to adjust your strategy based on what you're trying to achieve.

Choosing the Right Tool for the Job: Your Shopify API Options

The solution really boils down to your specific use case. Are you displaying public product data? Accessing sensitive customer information? Building an embedded app? Each scenario has its own secure and intended method. Let's break down the best practices shared by the community.

1. For Product/Price Data on Customer-Facing Pages: Use the Storefront API

If your goal is to display product details, prices, inventory levels, or even certain metafields on a page that your customers will see, the Storefront API is your go-to. It's specifically designed for browser calls and comes with full CORS support. Crucially, the Storefront API uses a public storefront access token, which is considered low-trust and safe to include in your client-side code.

How to Use the Storefront API:

  1. Endpoint: Use the Storefront API endpoint, which looks like this:

    https://.myshopify.com/api/2025-07/graphql.json

    Notice the difference from the Admin API endpoint /admin/api/....

  2. Access Token: Include your public storefront access token in the X-Shopify-Storefront-Access-Token header. You can generate this token in your Shopify Admin under Settings > Apps and sales channels > Develop apps > Create an app > Configure Storefront API integration.

  3. Exposing Metafields: This is a common point of confusion! If you're trying to fetch product metafields, remember they are only visible via the Storefront API if you've explicitly exposed them. To do this, go to your Shopify Admin > Settings > Custom data > Storefronts, and make sure the relevant metafield definitions are checked for Storefront access.

2. For Admin-Level Data (Orders, Customers, Internal Metafields): Go Backend!

What if you genuinely need access to sensitive data like customer details, order information, or internal metafields that shouldn't be public? In this case, the community consensus is clear: call the Admin API from your own backend. This is the secure way to handle high-trust data.

How to Implement a Backend Proxy:

  1. Your Client-Side Page: Your website or application makes a request to your own backend endpoint, not directly to Shopify.

  2. Your Backend Endpoint: This could be a small Node.js server, a serverless function (like AWS Lambda, Google Cloud Functions, or a Vercel/Netlify function), or any other server-side environment. This backend service then securely makes the call to the Shopify Admin GraphQL API using your Admin access token.

    Here's what a simplified backend call might look like, similar to what saurabhv's original code was aiming for, but executed on a server:

    async function getMetafieldServerSide(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": "YOUR_SECRET_ADMIN_ACCESS_TOKEN" // This token is SAFE on the server!
    
        },
    
        body: JSON.stringify({
    
          query: `
    
            {
    
              product(id: "gid://shopify/Product/${product_id}") {
    
                metafields(first: 10) {
    
                  edges {
    
                    node {
    
                      namespace
    
                      key
    
                      value
    
                    }
    
                  }
    
                }
    
              }
    
            }
    
          `
    
        })
    
      });
      // Process the response and send only the necessary data back to the client
      const data = await res.json();
      return data;
    }
    
  3. Data Flow: Your backend processes the data received from Shopify and then sends only the necessary, sanitized information back to your client-side page. The crucial part is that your Admin access token never touches the browser.

3. For Embedded Shopify Apps: Leverage App Bridge

If you're developing an embedded Shopify app that lives within the Shopify Admin interface, then App Bridge is the recommended and most secure path. App Bridge handles the authentication dance for you.

How App Bridge Works for Admin API Calls:

  1. Session Token: Your embedded app uses App Bridge to get a session token.

  2. Backend Relay: This session token is then sent to your app's backend.

  3. Admin API Call: Your app's backend uses the session token to authenticate and make calls to the Shopify Admin GraphQL API on the merchant's behalf.

  4. Shopify CLI: If you're building a new embedded app, the Shopify CLI app templates (for Remix, Node, etc.) come pre-wired with App Bridge integration, making this setup much simpler right out of the box. It's a great starting point!

So, there you have it! The next time you encounter a CORS error with the Shopify Admin API, remember it's a security gate, not a roadblock. By understanding whether you need public storefront data, secure admin data, or are building an embedded app, you can choose the right API and architecture to keep your store's data safe and your development workflow smooth. Happy coding!

Share:

Start with the tools

Explore migration tools

See options, compare methods, and pick the path that fits your store.

Explore migration tools