App script blocked due to sandboxing issues

I have a app named Only-bundles which i submitted to shopify after deploying it to render but I when app loads in store it shows Blocked script execution because allow scripts are not set but I have set all CRP headers and correct app bridge initialization because shopify is loading my app in sandbox and something related to iframe, the shopify partner dashboard config and my code config are exact match but still what to do

see my code

entry.server.jsx

import { RemixBrowser } from "@remix-run/react"
import { startTransition, StrictMode } from "react"
import { hydrateRoot } from "react-dom/client"

// Simple logging helper
const log = (message, data) => {
  console.log(`[Shopify App] ${message}`, data || "")
}

// Error logging helper
const logError = (message, error) => {
  console.error(`[Shopify App Error] ${message}`, error)
}

// Improve the App Bridge initialization logic
function initializeAppBridge() {
  try {
    if (typeof window === "undefined" || !window.shopify?.AppBridge) {
      logError("App Bridge not available")
      return null
    }

    // Get query parameters from URL
    const searchParams = new URLSearchParams(window.location.search)
    const shop = searchParams.get("shop")
    const host = searchParams.get("host")

    // Get API key from meta tag
    const apiKeyMeta = document.querySelector('meta[name="shopify-api-key"]')
    const apiKey = apiKeyMeta ? apiKeyMeta.getAttribute("content") : null

    // Fallback to global variable
    const globalApiKey = window.shopify?.apiKey

    // Use the actual API key from your environment
    const finalApiKey = apiKey || globalApiKey || "8d4e0e05f2b0106c384f977e8f218792"

    log("App Bridge configuration parameters:", {
      apiKey: finalApiKey ? "Set" : "Not set",
      shop,
      host,
    })

    if (!finalApiKey) {
      logError("Missing API key for App Bridge initialization")
      return null
    }

    if (!shop || !host) {
      logError("Missing shop or host for App Bridge initialization")
      return null
    }

    const AppBridge = window.shopify.AppBridge

    // Configure App Bridge
    const appBridgeConfig = {
      apiKey: finalApiKey,
      host: host,
      forceRedirect: false,
    }

    // Create App Bridge instance
    const app = AppBridge.createApp(appBridgeConfig)

    // Store the instance globally for easy access
    window.app = app

    log("App Bridge initialized successfully")

    return app
  } catch (error) {
    logError("Error during App Bridge initialization:", error)
    return null
  }
}

// Hydrate the app
function hydrateApp() {
  log("Starting hydration")

  try {
    startTransition(() => {
      hydrateRoot(
        document,
        <StrictMode>
          <RemixBrowser />
        </StrictMode>,
      )
      log("App hydrated successfully")
    })
  } catch (error) {
    logError("Error during hydration:", error)
  }
}

// Main initialization function
function initialize() {
  log("Initializing app")

  // First hydrate the app
  hydrateApp()

  // Then initialize App Bridge if it's loaded
  if (window.shopify?.AppBridge) {
    initializeAppBridge()
  } else {
    log("App Bridge not available")
  }
}

// Wait for DOM to be ready
if (typeof document !== "undefined") {
  if (document.readyState === "loading") {
    log("Document still loading, waiting for DOMContentLoaded")
    document.addEventListener("DOMContentLoaded", initialize)
  } else {
    log("Document already loaded, initializing immediately")
    initialize()
  }
}

entry.client.jsx

import { RemixBrowser } from "@remix-run/react"
import { startTransition, StrictMode } from "react"
import { hydrateRoot } from "react-dom/client"

// Simple logging helper
const log = (message, data) => {
  console.log(`[Shopify App] ${message}`, data || "")
}

// Error logging helper
const logError = (message, error) => {
  console.error(`[Shopify App Error] ${message}`, error)
}

// Improve the App Bridge initialization logic
function initializeAppBridge() {
  try {
    if (typeof window === "undefined" || !window.shopify?.AppBridge) {
      logError("App Bridge not available")
      return null
    }

    // Get query parameters from URL
    const searchParams = new URLSearchParams(window.location.search)
    const shop = searchParams.get("shop")
    const host = searchParams.get("host")

    // Get API key from meta tag
    const apiKeyMeta = document.querySelector('meta[name="shopify-api-key"]')
    const apiKey = apiKeyMeta ? apiKeyMeta.getAttribute("content") : null

    // Fallback to global variable
    const globalApiKey = window.shopify?.apiKey

    // Use the actual API key from your environment
    const finalApiKey = apiKey || globalApiKey || "api_key"

    log("App Bridge configuration parameters:", {
      apiKey: finalApiKey ? "Set" : "Not set",
      shop,
      host,
    })

    if (!finalApiKey) {
      logError("Missing API key for App Bridge initialization")
      return null
    }

    if (!shop || !host) {
      logError("Missing shop or host for App Bridge initialization")
      return null
    }

    const AppBridge = window.shopify.AppBridge

    // Configure App Bridge
    const appBridgeConfig = {
      apiKey: finalApiKey,
      host: host,
      forceRedirect: false,
    }

    // Create App Bridge instance
    const app = AppBridge.createApp(appBridgeConfig)

    // Store the instance globally for easy access
    window.app = app

    log("App Bridge initialized successfully")

    return app
  } catch (error) {
    logError("Error during App Bridge initialization:", error)
    return null
  }
}

// Hydrate the app
function hydrateApp() {
  log("Starting hydration")

  try {
    startTransition(() => {
      hydrateRoot(
        document,
        <StrictMode>
          <RemixBrowser />
        </StrictMode>,
      )
      log("App hydrated successfully")
    })
  } catch (error) {
    logError("Error during hydration:", error)
  }
}

// Main initialization function
function initialize() {
  log("Initializing app")

  // First hydrate the app
  hydrateApp()

  // Then initialize App Bridge if it's loaded
  if (window.shopify?.AppBridge) {
    initializeAppBridge()
  } else {
    log("App Bridge not available")
  }
}

// Wait for DOM to be ready
if (typeof document !== "undefined") {
  if (document.readyState === "loading") {
    log("Document still loading, waiting for DOMContentLoaded")
    document.addEventListener("DOMContentLoaded", initialize)
  } else {
    log("Document already loaded, initializing immediately")
    initialize()
  }
}



root.jsx

import { Links, Meta, Outlet, Scripts, ScrollRestoration, useLoaderData, useRouteError } from "@remix-run/react"
import { json } from "@remix-run/node"
import { AppProvider } from "@shopify/shopify-app-remix/react"
import { authenticate } from "./shopify.server"
import translations from "@shopify/polaris/locales/en.json"
import "@shopify/polaris/build/esm/styles.css"
import "./styles.css"
import { generateCSPHeaders } from "./utils/csp-headers"

export const loader = async ({ request }) => {
  try {
    // Get the shop from the URL if available
    const url = new URL(request.url)
    const shop = url.searchParams.get("shop")
    const embedded = url.searchParams.get("embedded") === "1"
    const host = url.searchParams.get("host")

    // Try to authenticate the request
    let sessionShop = null
    try {
      const { session } = await authenticate.admin(request)
      sessionShop = session?.shop
    } catch (authError) {
      console.log("Authentication error (expected during OAuth flow):", authError.message)
    }

    // Use the shop from the session or URL
    const shopDomain = sessionShop || shop

    // Get API key from environment variable
    const apiKey = process.env.SHOPIFY_API_KEY

    // Log important values for debugging
    console.log("Root loader values:", {
      apiKey: apiKey ? "Set" : "Not set",
      shopDomain,
      embedded,
      host,
      url: request.url,
    })

    // Get CSP headers
    const headers = generateCSPHeaders()

    return json(
      {
        apiKey,
        shop: shopDomain,
        host,
        embedded,
      },
      { headers },
    )
  } catch (error) {
    console.error("Loader error:", error)

    // Return a basic response with CSP headers
    return json(
      {
        apiKey: process.env.SHOPIFY_API_KEY,
        shop: null,
        host: null,
        embedded: false,
      },
      {
        headers: generateCSPHeaders(),
      },
    )
  }
}

export default function App() {
  const { apiKey, shop, host, embedded } = useLoaderData()

  // Log important values for debugging
  console.log("App component values:", {
    apiKey: apiKey ? "Set" : "Not set",
    shop,
    host,
    embedded,
  })

  if (!apiKey) {
    return (
      <div className="p-4">
        <div className="bg-critical/10 p-4 rounded-md">
          <h1 className="text-lg font-medium text-critical">Configuration Error</h1>
          <p className="mt-2 text-sm text-critical">Missing API Key. Please check your environment variables.</p>
        </div>
      </div>
    )
  }

  return (
    <html lang="en">
      <head>
        <meta charSet="utf-8" />
        <meta name="viewport" content="width=device-width,initial-scale=1" />
        <meta name="shopify-api-key" content={apiKey} />
        {/* Remove defer attribute to ensure App Bridge loads before other scripts */}
        <script src="https://cdn.shopify.com/shopifycloud/app-bridge.js"></script>
        <Meta />
        <Links />
      </head>
      <body>
        <AppProvider
          isEmbeddedApp
          apiKey={apiKey}
          host={host || ""}
          shop={shop || ""}
          forceRedirect={!embedded && !!shop}
          i18n={translations}
        >
          <Outlet context={{ shop, host }} />
        </AppProvider>
        <ScrollRestoration />
        <script
          dangerouslySetInnerHTML={{
            __html: `window.shopify = {
              apiKey: "${apiKey}",
              shop: "${shop || ""}",
              host: "${host || ""}",
            }`,
          }}
        />
        <Scripts />
      </body>
    </html>
  )
}

export function ErrorBoundary() {
  const error = useRouteError()
  console.error("Root error:", error)

  let errorMessage = "An unexpected error occurred"
  let errorTitle = "Application Error"
  let errorDetails = null

  if (error instanceof Error) {
    errorMessage = error.message
    errorDetails = error.stack
  }

  if (error?.status === 401) {
    errorTitle = "Authentication Error"
    errorMessage = "Please refresh the page or try logging in again."
  }

  return (
    <html lang="en">
      <head>
        <title>{errorTitle}</title>
        <Meta />
        <Links />
      </head>
      <body>
        <div className="p-4">
          <div className="bg-destructive/10 p-4 rounded-md">
            <h1 className="text-lg font-medium text-destructive">{errorTitle}</h1>
            <p className="mt-2 text-sm text-destructive">{errorMessage}</p>
            {process.env.NODE_ENV === "development" && errorDetails && (
              <pre className="mt-4 text-xs text-destructive/75 whitespace-pre-wrap">{errorDetails}</pre>
            )}
          </div>
        </div>
        <Scripts />
      </body>
    </html>
  )
}

Hey @Yash_Chaudhari :waving_hand: - the error you’re seeing is likely related to a known issue on our end and there’s more info here: Blocked script execution in <URL> because the document's frame is sandboxed and the 'allow-scripts' permission is not set.

There is some more information in that thread from some of my colleagues, but my understanding is that this is more of a warning message rather than an error and shouldn’t affect your app’s functionality by itself.

Let me know if I can clarify anything more on my end here - hope this helps!

These warnings are there in local development also , but as soon as i replace the redirect urls ,the whole UI vanishes.

Thanks for confirming @Yash_Chaudhari, I think we can take a closer look into this, but I might need more info. Would you be able to share the full CSP header your app is sending (usually you can grab this in Chrome DevTools in the network tab in the main request to your app’s URL)? If you’re also able to share the code you’re using for the generateCSPHeaders function, that would be super helpful as well - just want to see if there’s anything that is triggering the issue there.

I don’t think the UI itself disappearing is related to the error message that’s showing up, but I’m happy to do some more digging into this - hope to hear from you soon!



Hi @Alan_G I really appreciate your response to this issue. I have put all the CRP headers, App-bridge loading and initialization logic. Perhaps there is an issue between configuration in my code and the configuration in shopify partner dashboard.

I have attached my code. Please take a look into it and let me know if we can connect on the google meet to resolve the issue.

Thanks and Regards,
Yash Chaudhari

Thanks for sharing this @Yash_Chaudhari - I’ll do some more digging into this for you and loop back when I have more info to share/next steps :slight_smile: