How do I make a call to the storefront API from my emeded Apps public API end points

Topic summary

A developer is attempting to call Shopify’s Storefront API from public (unauthenticated) Node.js endpoints in their embedded app but encounters session-related errors.

Current situation:

  • Successfully created the desired checkoutCreate mutation using GraphQL Explorer
  • Can access the Storefront API from authenticated backend routes using res.locals.shopify.session
  • Public endpoints lack access to this session object, causing “Cannot read properties of undefined (reading ‘shop’)” errors

Key challenge:
How to obtain or create a valid session for initializing the Storefront API client on public endpoints where res.locals.shopify.session is unavailable.

Proposed solution:
One commenter identified a potential documentation error, suggesting the Storefront client initialization should use:

const storefrontClient = new shopify.api.clients.Storefront({session: session, storefrontAccessToken})

The discussion references the shopify-api-js GitHub repository for clarification on proper client setup. The issue remains unresolved regarding session management for public endpoints.

Summarized with AI on November 8. AI used: claude-sonnet-4-5-20250929.

I am trying to do something I thought would be simple but I can’t seem to figure out how to get the proper session on my public endpoints to make the call. I started off using the GraphQL explorer which got my the mutation I wanted:

mutation checkoutCreate($input: CheckoutCreateInput!) {
  checkoutCreate(input: $input) {
    checkout {
      webUrl
    }
    checkoutUserErrors {
      code
      field
      message
    }
    queueToken
  }
}

// variables 
{
"input": {
"allowPartialAddresses": true,
"buyerIdentity": {
"countryCode": "US"
},
"customAttributes": [
{
"key": "",
"value": ""
}
],
"lineItems": [
{
"customAttributes": [
{
"key": "",
"value": ""
}
],
"quantity": 1,
"variantId": "gid://shopify/ProductVariant/45806359249211"
}
],
"note": "",
"shippingAddress": {
"address1": "",
"address2": "",
"city": "Test",
"company": "",
"country": "US",
"firstName": "",
"lastName": "",
"phone": "",
"province": "CA",
"zip": ""
}
},
"queueToken": ""
}

// response 
{
"data": {
"checkoutCreate": {
"checkout": {
"webUrl": "https://quickstart-0f3b6685.myshopify.com/79491432763/checkouts/848734768d5e803df1346cc29fd708c3?key=28fafff6a1b88ce729969b9935d42cb6"
},
"checkoutUserErrors": [],
"queueToken": null
}
}
}

Cool this is exactly what I want. Now from what I have read that I would be able to query the Storefront API from my public end points. But when I try to do so I am getting errors when creating the session. In my authenticated backed API, where i fetch data for my embedded App I can get the session from the response variable like so:

app.get("/api/shop-data", async (req, res) => {

    const client = new shopify.api.clients.Graphql({
      session: res.locals.shopify.session, // doesnt work on the public end points
    });

    /* Fetch shop data, including all available discounts to list in the QR code form */
    const shopData = await client.query({
      data: {
        query: SHOP_DATA_QUERY,
        variables: {
          first: 25,
        },
      },
    });

    res.send(shopData.body.data);
  });

I am guessing this is because the call is coming from the storefront and not the backend. I went through the documentation and tried using the shopify api library:

app.get("/bundle/checkout", async (req, res) => {

		try {

			 const shopifyAPI = shopifyApi({
				// The next 4 values are typically read from environment variables for added security
				apiKey: 'xxxx',
				apiSecretKey: 'xxxxxxx',
				scopes: ['unauthenticated_read_checkouts,unauthenticated_write_checkouts'],
				hostName: 'localhost',
			 });

			 const adminApiClient = new shopifyAPI.clients.Rest({...shopifyAPI.session});

I am getting the following error:

TypeError: Cannot read properties of undefined (reading 'shop')
2023-07-23 17:01:50 │ web-backend  │     at new RestClient (/Users/mpmadmin/shopify/build-a-bundle/node_modules/@shopify/shopify-api/lib/clients/rest/rest_client.js:12:40)
2023-07-23 17:01:50 │ web-backend  │     at new RestClient (/Users/mpmadmin/shopify/build-a-bundle/node_modules/@shopify/shopify-api/lib/clients/rest/rest_client.js:104:5)
2023-07-23 17:01:50 │ web-backend  │     at file:///Users/mpmadmin/shopify/build-a-bundle/web/middleware/qr-code-public.js:81:28
2023-07-23 17:01:50 │ web-backend  │     at Layer.handle [as handle_request] (/Users/mpmadmin/shopify/build-a-bundle/node_modules/express/lib/router/layer.js:95:5)
2023-07-23 17:01:50 │ web-backend  │     at next (/Users/mpmadmin/shopify/build-a-bundle/node_modules/express/lib/router/route.js:144:13)
2023-07-23 17:01:50 │ web-backend  │     at Route.dispatch (/Users/mpmadmin/shopify/build-a-bundle/node_modules/express/lib/router/route.js:114:3)
2023-07-23 17:01:50 │ web-backend  │     at Layer.handle [as handle_request] (/Users/mpmadmin/shopify/build-a-bundle/node_modules/express/lib/router/layer.js:95:5)
2023-07-23 17:01:50 │ web-backend  │     at /Users/mpmadmin/shopify/build-a-bundle/node_modules/express/lib/router/index.js:284:15
2023-07-23 17:01:50 │ web-backend  │     at Function.process_params (/Users/mpmadmin/shopify/build-a-bundle/node_modules/express/lib/router/index.js:346:12)
2023-07-23 17:01:50 │ web-backend  │     at next (/Users/mpmadmin/shopify/build-a-bundle/node_modules/express/lib/router/index.js:280:10)

Can someone please help me out? How can I get the session to make a request from my public node end points to the store front API to create the checkout link and then redirect the user to it?

So you’re trying to make a fetch call from the frontend? I wrote a blog post on how to do this, http://www.toomanytabs.xyz/blog_posts/the-easy-way-to-do-the-shopify-storefront-api-graphql-with-fetch The top part is a little outdate, but the JS is the same once you get the storefront API key.

Also when you’re using the Graphical app to form your query, make sure you’re on the storefront api and not the admin api, because the queries might be slightly different

Hey thanks for the response. I actually want to do it from the public NodeJS end points I created. I am on the storefront API and I have successfully returned the URL I need here. The issue is getting the session to setup the client. On the admin protected routes I am able to create the client with out issue:

const adminApiClient = new shopify.api.clients.Rest({session: res.locals.shopify.session});

    const storefrontTokenResponse = await adminApiClient.post({
      path: 'storefront_access_tokens',
      type: DataType.JSON,
      data: {
        storefront_access_token: {
          title: 'This is my test access token',
        },
      },
    });

    const shop = adminApiClient.session.shop;
    const storefrontAccessToken = storefrontTokenResponse.body['storefront_access_token']['access_token'];

    const storefrontClient = new shopify.api.clients.Storefront({
      domain: shop,
      storefrontAccessToken,
    });

On my public routes I am not able to access the res.locals.shopify.session variable but I need a session to create my client and retrieve the access token. How do I get the session for the public end points?

1 Like

Looking at the source for clients.Storefront it seems like the doc is wrong and that the setup should be like this.
https://github.com/Shopify/shopify-api-js/blob/9dd9284376deaca14598e8dc96c90b868e03086b/packages/shopify-api/lib/clients/storefront/client.ts#L76

const storefrontClient = new shopify.api.clients.Storefront({ session: session, storefrontAccessToken, });