DEV Community

Cover image for Verifying Your Shopify App Embed is Actually Enabled with Remix: A Step-by-Step Guide
TOMAS E GIL AMOEDO
TOMAS E GIL AMOEDO

Posted on

Verifying Your Shopify App Embed is Actually Enabled with Remix: A Step-by-Step Guide

Programmatically Checking a Shopify App Embed with Remix

How do we, as Shopify app developers, confirm programmatically that our theme app embed is truly switched on? Shopify provides a toggle in the theme editor, but there’s no official “Check if embed is active” endpoint. For all we know, the merchant could have disabled our block—or never enabled it—in their main theme.

In this tutorial, we’ll walk through a practical solution using Remix:

  • We’ll query the store’s main theme
  • Retrieve and parse settings_data.json (while stripping out comment blocks)
  • Verify that our embed block isn’t set to disabled: true By the end, we’ll be able to confirm—directly from our code—that the app embed is actually running for every merchant who installs it.

Context

If the Embed Is Off

Merchants end up with a “half-installed” app. That can lead to confusion or missing features

No Direct “Check Embed” Endpoint

Shopify doesn’t offer /is-embed-enabled, so we must verify—manually—that the block is disabled: false in the main theme.

The Remix + GraphQL Approach

We’ll fetch and parse settings_data.json, strip out comment blocks, and check if our block is enabled. This gives us a simple boolean: if true, it’s disabled; if false, it’s active.


Requirements & Setup

Note: Ensure your app has read_themes scope (and write_themes if you plan on modifying theme files).

Steps in a Nutshell

1.Identify the store’s main theme.
2.Fetch and parse settings_data.json.
3.Check if our app embed block is marked disabled: false.

With that covered, let’s jump right into the code!


Step-by-Step Solution

4.1 Identify the Main Theme

Query All Themes

We call Shopify’s Admin API (GraphQL) to retrieve a list of themes. Only one theme should have role: MAIN, which is the published or currently live theme.

Extract id

Once we find the main theme, we’ll grab its id (e.g., gid://shopify/OnlineStoreTheme/123456789). This will be crucial for the next step when we fetch settings_data.json.

const GET_THEMES = `
  query {
    themes(first: 20) {
      edges {
        node {
          id
          role
          name
        }
      }
    }
  }
`;

export async function getMainThemeId(admin: any) {
  const response = await admin.graphql(GET_THEMES);
  const responseJson = await response.json();

  const themes = responseJson.data.themes.edges;
  const mainTheme = themes.find((t: any) => t.node.role === "MAIN");

  return mainTheme ? mainTheme.node.id : undefined;
}

Enter fullscreen mode Exit fullscreen mode

4.2 Fetch settings_data.json

Use the Theme ID
With the ID from above, we craft another query to specifically retrieve settings_data.json from that theme’s files.

Strip Comment Blocks
settings_data.json often contains a multi-line comment (the big /* ... */ at the top). We remove it before parsing, because it breaks JSON.parse.

Parse the JSON
After removing the comment block, convert the remainder into a JavaScript object so we can inspect the blocks.

const GET_THEME_FILE = `
  query getThemeFile($id: ID!) {
    theme(id: $id) {
      files(filenames: ["config/settings_data.json"], first: 1) {
        nodes {
          filename
          body {
            ... on OnlineStoreThemeFileBodyText {
              content
            }
          }
        }
      }
    }
  }
`;

export async function getSettingsData(admin: any, themeId: string) {
  const response = await admin.graphql(GET_THEME_FILE, { variables: { id: themeId } });
  const result = await response.json();

  const rawContent = result.data.theme.files.nodes[0]?.body?.content ?? "";
  const cleaned = rawContent.replace(/\/\*[\s\S]*?\*\//, ""); // remove multi-line comment

  return JSON.parse(cleaned);
}

Enter fullscreen mode Exit fullscreen mode

4.3 Check for Your App Embed Block

Locate the "blocks"
Inside the parsed JSON, we typically look at parsedData.current.blocks.

Find the Block Matching Your App
The block type might look like shopify://apps/dev-storelock/blocks/country-blocking/.... Use something like block.type.includes("dev-storelock") (or your own app handle) to confirm it’s yours.

Verify disabled
If disabled is false, that means the embed is actually enabled. If the block is missing or set to disabled: true, the embed is off.

export function isAppEmbedDisabled(parsedData: any, appHandle: string): boolean {
  const blocks = parsedData?.current?.blocks;
  if (!blocks) return true; // If no blocks exist, treat as disabled.

  // Loop over block keys
  for (const blockId of Object.keys(blocks)) {
    const block = blocks[blockId];
    if (block?.type?.includes(appHandle)) {
      return block.disabled === true;
    }
  }

  // If we never found our block, assume disabled.
  return true;
}

Enter fullscreen mode Exit fullscreen mode

4.4 Putting It All Together (Remix Loader Example)

Below is a skeletal Remix loader showing how we might fetch both the main theme and then settings_data.json, and finally check if the app embed is active:

import { json } from "@remix-run/node";
import type { LoaderFunction } from "@remix-run/node";

// Utility functions from above
import { getMainThemeId, getSettingsData, isAppEmbedDisabled } from "~/lib/shopify.server";

export const loader: LoaderFunction = async ({ request }) => {
  // auth, create `admin` client, etc. omitted for brevity
  const themeId = await getMainThemeId(admin);

  let embedDisabled = true; // default to "embed off"

  if (themeId) {
    const settingsData = await getSettingsData(admin, themeId);
    embedDisabled = isAppEmbedDisabled(settingsData, "dev-storelock");
  }

  return json({ embedDisabled });
};

Enter fullscreen mode Exit fullscreen mode

In our Remix route, we end up with a simple boolean embedDisabled. Our React component can conditionally render a warning or skip certain features if the embed is off.

Recap

  • Find main theme → fetch settings_data.json → strip comment → check block type and disabled.

  • Once we have that result, we can react accordingly in our UI or logs. That’s how we confirm, programmatically, that our Shopify embed is truly enabled—no guesswork needed.

Want the Full Snippet?

For a consolidated version of all these steps, check out the Gist:

https://gist.github.com/Tommydemian/fe5896c66b5cba6b5b4a5139362758df
Happy coding and don't forget to leave a star if the code is useful, thanks!


Conclusion & Next Steps

This is a little guidance on how to integrate a working solution into a Remix environment. This tutorial covers the gap left by Shopify’s lack of a direct endpoint. With a short Remix loader (or custom hook—which I personally prefer, given my strong React background—and a bit of parsing), we get a clean, reliable way to verify the app embed’s status—no guesswork required.

Workflow Recap:
1.Locate the main theme
2.Fetch settings_data.json
3.Strip out comment blocks
4.Check the type and disabled fields

By following these steps, our block is truly active in the storefront—essential if the app handles security or other high-priority features.

Optional Enhancements:

  • Alerts: Consider logging a warning or showing a banner in your admin UI if the embed is off.

  • Caching: If you frequently call the Shopify Admin API, think about caching settings_data.json to avoid repeated fetches.

If you have questions or tips, feel free to share them in the comments.
Happy coding!

Top comments (0)