Accessing browser window object in Node.js environment

I’m working on a Shopify app and ran into some confusion about browser APIs in server-side code. I found this piece of code that checks if the current window is a parent or child frame:

// Check if current frame is the main window
if (global.top === global.self) {
  global.location.href = authUrl;
} else {
  const shopifyApp = initializeApp({
    key: appKey,
    origin: storeOrigin
  });
  
  RedirectModule.build(shopifyApp).execute(RedirectModule.Type.EXTERNAL, authUrl);
}

The issue is that this code tries to use window object but I’m running this in Node.js. I tried using jsdom library to simulate the browser environment but it’s not working as expected. Can someone explain why browser-specific code would be used in a Node.js context and what’s the proper way to handle this situation?

you’re mixing up client and server contexts. that global.top check works for iframe detection but breaks in node. skip jsdom and just check the environment first - if typeof window === 'undefined' then handle server redirects one way, otherwise use app bridge for embedded stuff.

This code’s designed to work in both browser and server environments - pretty standard for Shopify apps using Next.js or other SSR frameworks. The global.top and global.self bits aren’t trying to mess with browser objects, they’re just checking where the code’s running.

You’d want to wrap this in environment checks first though. Check typeof window !== 'undefined' before touching browser APIs. Shopify App Bridge handles server-side differently - probably uses fallback redirects when it’s running in Node.js.

I’ve seen this pattern before where auth logic needs to work both client-side (embedded apps) and server-side (initial auth). Check if you’re missing a polyfill or if this should only run in the browser. jsdom works fine for testing but you don’t want it handling this logic in production SSR.

Hit this exact issue building a headless commerce app last year. Your code’s trying to access frame properties that only exist in browsers, but it’s running server-side during SSR or initial load. This looks like isomorphic code that’s supposed to handle both scenarios but doesn’t check the environment first. Those global.top and global.self references will blow up in Node.js since there’s no window hierarchy on the server. Don’t use jsdom - it’s overkill and creates more problems. Just detect the environment first and handle auth differently. Server-side should do a direct HTTP redirect instead of trying to mess with window objects. Save the Shopify App Bridge redirect for client-side after the component mounts. Wrap this in a useEffect hook or move it to a client-only component. Every Shopify app I’ve worked on separates server-side auth from client-side embedded app logic completely.